OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package runtime | 5 package runtime |
6 | 6 |
7 // This file contains the implementation of Go select statements. | 7 // This file contains the implementation of Go select statements. |
8 | 8 |
9 import "unsafe" | 9 import "unsafe" |
10 | 10 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 } | 361 } |
362 } | 362 } |
363 | 363 |
364 // wait for someone to wake us up | 364 // wait for someone to wake us up |
365 gp.param = nil | 365 gp.param = nil |
366 gopark(unsafe.Pointer(funcPC(selparkcommit)), unsafe.Pointer(sel), "sele
ct") | 366 gopark(unsafe.Pointer(funcPC(selparkcommit)), unsafe.Pointer(sel), "sele
ct") |
367 | 367 |
368 // someone woke us up | 368 // someone woke us up |
369 sellock(sel) | 369 sellock(sel) |
370 sg = (*sudog)(gp.param) | 370 sg = (*sudog)(gp.param) |
| 371 gp.param = nil |
371 | 372 |
372 // pass 3 - dequeue from unsuccessful chans | 373 // pass 3 - dequeue from unsuccessful chans |
373 // otherwise they stack up on quiet channels | 374 // otherwise they stack up on quiet channels |
374 // record the successful case, if any. | 375 // record the successful case, if any. |
375 // We singly-linked up the SudoGs in case order, so when | 376 // We singly-linked up the SudoGs in case order, so when |
376 // iterating through the linked list they are in reverse order. | 377 // iterating through the linked list they are in reverse order. |
377 cas = nil | 378 cas = nil |
378 sglist = gp.waiting | 379 sglist = gp.waiting |
| 380 // Clear all selectdone and elem before unlinking from gp.waiting. |
| 381 // They must be cleared before being put back into the sudog cache. |
| 382 // Clear before unlinking, because if a stack copy happens after the unl
ink, |
| 383 // they will not be updated, they will be left pointing to the old stack
, |
| 384 // which creates dangling pointers, which may be detected by the |
| 385 // garbage collector. |
| 386 for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { |
| 387 sg1.selectdone = nil |
| 388 sg1.elem = nil |
| 389 } |
379 gp.waiting = nil | 390 gp.waiting = nil |
380 for i := int(sel.ncase) - 1; i >= 0; i-- { | 391 for i := int(sel.ncase) - 1; i >= 0; i-- { |
381 k = &scases[pollorder[i]] | 392 k = &scases[pollorder[i]] |
382 if sglist.releasetime > 0 { | 393 if sglist.releasetime > 0 { |
383 k.releasetime = sglist.releasetime | 394 k.releasetime = sglist.releasetime |
384 } | 395 } |
385 if sg == sglist { | 396 if sg == sglist { |
386 cas = k | 397 cas = k |
387 } else { | 398 } else { |
388 c = k._chan | 399 c = k._chan |
389 if k.kind == _CaseSend { | 400 if k.kind == _CaseSend { |
390 » » » » c.sendq.dequeueg(gp) | 401 » » » » c.sendq.dequeueSudoG(sglist) |
391 } else { | 402 } else { |
392 » » » » c.recvq.dequeueg(gp) | 403 » » » » c.recvq.dequeueSudoG(sglist) |
393 } | 404 } |
394 } | 405 } |
395 sgnext = sglist.waitlink | 406 sgnext = sglist.waitlink |
396 releaseSudog(sglist) | 407 releaseSudog(sglist) |
397 sglist = sgnext | 408 sglist = sgnext |
398 } | 409 } |
399 | 410 |
400 if cas == nil { | 411 if cas == nil { |
401 goto loop | 412 goto loop |
402 } | 413 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 selunlock(sel) | 510 selunlock(sel) |
500 if debugSelect { | 511 if debugSelect { |
501 print("syncrecv: sel=", sel, " c=", c, "\n") | 512 print("syncrecv: sel=", sel, " c=", c, "\n") |
502 } | 513 } |
503 if cas.receivedp != nil { | 514 if cas.receivedp != nil { |
504 *cas.receivedp = true | 515 *cas.receivedp = true |
505 } | 516 } |
506 if cas.elem != nil { | 517 if cas.elem != nil { |
507 memmove(cas.elem, sg.elem, uintptr(c.elemsize)) | 518 memmove(cas.elem, sg.elem, uintptr(c.elemsize)) |
508 } | 519 } |
| 520 sg.elem = nil |
509 gp = sg.g | 521 gp = sg.g |
510 gp.param = unsafe.Pointer(sg) | 522 gp.param = unsafe.Pointer(sg) |
511 if sg.releasetime != 0 { | 523 if sg.releasetime != 0 { |
512 sg.releasetime = cputicks() | 524 sg.releasetime = cputicks() |
513 } | 525 } |
514 goready(gp) | 526 goready(gp) |
515 goto retc | 527 goto retc |
516 | 528 |
517 rclose: | 529 rclose: |
518 // read at end of closed channel | 530 // read at end of closed channel |
(...skipping 15 matching lines...) Expand all Loading... |
534 raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) | 546 raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) |
535 racesync(c, sg) | 547 racesync(c, sg) |
536 } | 548 } |
537 selunlock(sel) | 549 selunlock(sel) |
538 if debugSelect { | 550 if debugSelect { |
539 print("syncsend: sel=", sel, " c=", c, "\n") | 551 print("syncsend: sel=", sel, " c=", c, "\n") |
540 } | 552 } |
541 if sg.elem != nil { | 553 if sg.elem != nil { |
542 memmove(sg.elem, cas.elem, uintptr(c.elemsize)) | 554 memmove(sg.elem, cas.elem, uintptr(c.elemsize)) |
543 } | 555 } |
| 556 sg.elem = nil |
544 gp = sg.g | 557 gp = sg.g |
545 gp.param = unsafe.Pointer(sg) | 558 gp.param = unsafe.Pointer(sg) |
546 if sg.releasetime != 0 { | 559 if sg.releasetime != 0 { |
547 sg.releasetime = cputicks() | 560 sg.releasetime = cputicks() |
548 } | 561 } |
549 goready(gp) | 562 goready(gp) |
550 | 563 |
551 retc: | 564 retc: |
552 if cas.releasetime > 0 { | 565 if cas.releasetime > 0 { |
553 blockevent(cas.releasetime-t0, 2) | 566 blockevent(cas.releasetime-t0, 2) |
(...skipping 27 matching lines...) Expand all Loading... |
581 const ( | 594 const ( |
582 _ selectDir = iota | 595 _ selectDir = iota |
583 selectSend // case Chan <- Send | 596 selectSend // case Chan <- Send |
584 selectRecv // case <-Chan: | 597 selectRecv // case <-Chan: |
585 selectDefault // default | 598 selectDefault // default |
586 ) | 599 ) |
587 | 600 |
588 func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { | 601 func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { |
589 // flagNoScan is safe here, because all objects are also referenced from
cases. | 602 // flagNoScan is safe here, because all objects are also referenced from
cases. |
590 size := selectsize(uintptr(len(cases))) | 603 size := selectsize(uintptr(len(cases))) |
591 » sel := (*_select)(gomallocgc(size, nil, flagNoScan)) | 604 » sel := (*_select)(mallocgc(size, nil, flagNoScan)) |
592 newselect(sel, int64(size), int32(len(cases))) | 605 newselect(sel, int64(size), int32(len(cases))) |
593 r := new(bool) | 606 r := new(bool) |
594 for i := range cases { | 607 for i := range cases { |
595 rc := &cases[i] | 608 rc := &cases[i] |
596 switch rc.dir { | 609 switch rc.dir { |
597 case selectDefault: | 610 case selectDefault: |
598 selectdefaultImpl(sel, uintptr(i), 0) | 611 selectdefaultImpl(sel, uintptr(i), 0) |
599 case selectSend: | 612 case selectSend: |
600 if rc.ch == nil { | 613 if rc.ch == nil { |
601 break | 614 break |
602 } | 615 } |
603 selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0) | 616 selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0) |
604 case selectRecv: | 617 case selectRecv: |
605 if rc.ch == nil { | 618 if rc.ch == nil { |
606 break | 619 break |
607 } | 620 } |
608 selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0) | 621 selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0) |
609 } | 622 } |
610 } | 623 } |
611 | 624 |
612 pc, _ := selectgoImpl(sel) | 625 pc, _ := selectgoImpl(sel) |
613 chosen = int(pc) | 626 chosen = int(pc) |
614 recvOK = *r | 627 recvOK = *r |
615 return | 628 return |
616 } | 629 } |
617 | 630 |
618 func (q *waitq) dequeueg(gp *g) { | 631 func (q *waitq) dequeueSudoG(s *sudog) { |
619 var prevsgp *sudog | 632 var prevsgp *sudog |
620 l := &q.first | 633 l := &q.first |
621 for { | 634 for { |
622 sgp := *l | 635 sgp := *l |
623 if sgp == nil { | 636 if sgp == nil { |
624 return | 637 return |
625 } | 638 } |
626 » » if sgp.g == gp { | 639 » » if sgp == s { |
627 *l = sgp.next | 640 *l = sgp.next |
628 if q.last == sgp { | 641 if q.last == sgp { |
629 q.last = prevsgp | 642 q.last = prevsgp |
630 } | 643 } |
631 return | 644 return |
632 } | 645 } |
633 l = &sgp.next | 646 l = &sgp.next |
634 prevsgp = sgp | 647 prevsgp = sgp |
635 } | 648 } |
636 } | 649 } |
OLD | NEW |