}
gp.waiting = nil
gp.activeStackChans = false
- if gp.param == nil {
- if c.closed == 0 {
- throw("chansend: spurious wakeup")
- }
- panic(plainError("send on closed channel"))
- }
+ closed := !mysg.success
gp.param = nil
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
mysg.c = nil
releaseSudog(mysg)
+ if closed {
+ if c.closed == 0 {
+ throw("chansend: spurious wakeup")
+ }
+ panic(plainError("send on closed channel"))
+ }
return true
}
gp := sg.g
unlockf()
gp.param = unsafe.Pointer(sg)
+ sg.success = true
if sg.releasetime != 0 {
sg.releasetime = cputicks()
}
sg.releasetime = cputicks()
}
gp := sg.g
- gp.param = nil
+ gp.param = unsafe.Pointer(sg)
+ sg.success = false
if raceenabled {
raceacquireg(gp, c.raceaddr())
}
sg.releasetime = cputicks()
}
gp := sg.g
- gp.param = nil
+ gp.param = unsafe.Pointer(sg)
+ sg.success = false
if raceenabled {
raceacquireg(gp, c.raceaddr())
}
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
- closed := gp.param == nil
+ success := mysg.success
gp.param = nil
mysg.c = nil
releaseSudog(mysg)
- return true, !closed
+ return true, success
}
// recv processes a receive operation on a full channel c.
gp := sg.g
unlockf()
gp.param = unsafe.Pointer(sg)
+ sg.success = true
if sg.releasetime != 0 {
sg.releasetime = cputicks()
}
// g.selectDone must be CAS'd to win the wake-up race.
isSelect bool
+ // success indicates whether communication over channel c
+ // succeeded. It is true if the goroutine was awoken because a
+ // value was delivered over channel c, and false if awoken
+ // because c was closed.
+ success bool
+
parent *sudog // semaRoot binary tree
waitlink *sudog // g.waiting list or semaRoot
waittail *sudog // semaRoot
nextp **sudog
)
-loop:
// pass 1 - look for something already waiting
var dfli int
var dfl *scase
var casi int
var cas *scase
+ var caseSuccess bool
var recvOK bool
for i := 0; i < ncases; i++ {
casi = int(pollorder[i])
// We singly-linked up the SudoGs in lock order.
casi = -1
cas = nil
+ caseSuccess = false
sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting.
for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
// sg has already been dequeued by the G that woke us up.
casi = int(casei)
cas = k
+ caseSuccess = sglist.success
} else {
c = k.c
if k.kind == caseSend {
}
if cas == nil {
- // We can wake up with gp.param == nil (so cas == nil)
- // when a channel involved in the select has been closed.
- // It is easiest to loop and re-run the operation;
- // we'll see that it's now closed.
- // Maybe some day we can signal the close explicitly,
- // but we'd have to distinguish close-on-reader from close-on-writer.
- // It's easiest not to duplicate the code and just recheck above.
- // We know that something closed, and things never un-close,
- // so we won't block again.
- goto loop
+ throw("selectgo: bad wakeup")
}
c = cas.c
}
if cas.kind == caseRecv {
- recvOK = true
+ recvOK = caseSuccess
+ } else if cas.kind == caseSend && !caseSuccess {
+ goto sclose
}
if raceenabled {