aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/select.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/select.go')
-rw-r--r--src/runtime/select.go19
1 files changed, 7 insertions, 12 deletions
diff --git a/src/runtime/select.go b/src/runtime/select.go
index a069e3e050..081db7bad4 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -221,12 +221,12 @@ func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) {
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])
@@ -331,6 +331,7 @@ loop:
// 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 {
@@ -352,6 +353,7 @@ loop:
// 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 {
@@ -367,16 +369,7 @@ loop:
}
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
@@ -386,7 +379,9 @@ loop:
}
if cas.kind == caseRecv {
- recvOK = true
+ recvOK = caseSuccess
+ } else if cas.kind == caseSend && !caseSuccess {
+ goto sclose
}
if raceenabled {