aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/runtime/select.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/select.go')
-rw-r--r--libgo/go/runtime/select.go76
1 files changed, 9 insertions, 67 deletions
diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go
index 9f8ac49..096af52 100644
--- a/libgo/go/runtime/select.go
+++ b/libgo/go/runtime/select.go
@@ -88,7 +88,7 @@ func newselect(sel *hselect, selsize int64, size int32) {
}
func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) {
- pc := getcallerpc(unsafe.Pointer(&sel))
+ pc := getcallerpc()
i := sel.ncase
if i >= sel.tcase {
throw("selectsend: too many cases")
@@ -109,7 +109,7 @@ func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) {
}
func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) {
- pc := getcallerpc(unsafe.Pointer(&sel))
+ pc := getcallerpc()
i := sel.ncase
if i >= sel.tcase {
throw("selectrecv: too many cases")
@@ -131,7 +131,7 @@ func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) {
}
func selectdefault(sel *hselect) {
- pc := getcallerpc(unsafe.Pointer(&sel))
+ pc := getcallerpc()
i := sel.ncase
if i >= sel.tcase {
throw("selectdefault: too many cases")
@@ -301,7 +301,6 @@ func selectgo(sel *hselect) int {
var (
gp *g
- done uint32
sg *sudog
c *hchan
k *scase
@@ -368,7 +367,6 @@ loop:
// pass 2 - enqueue on all chans
gp = getg()
- done = 0
if gp.waiting != nil {
throw("gp.waiting != nil")
}
@@ -382,8 +380,7 @@ loop:
c = cas.c
sg := acquireSudog()
sg.g = gp
- // Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
- sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
+ sg.isSelect = true
// No stack splits between assigning elem and enqueuing
// sg on gp.waiting where copystack can find it.
sg.elem = cas.elem
@@ -409,62 +406,9 @@ loop:
gp.param = nil
gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 1)
- // While we were asleep, some goroutine came along and completed
- // one of the cases in the select and woke us up (called ready).
- // As part of that process, the goroutine did a cas on done above
- // (aka *sg.selectdone for all queued sg) to win the right to
- // complete the select. Now done = 1.
- //
- // If we copy (grow) our own stack, we will update the
- // selectdone pointers inside the gp.waiting sudog list to point
- // at the new stack. Another goroutine attempting to
- // complete one of our (still linked in) select cases might
- // see the new selectdone pointer (pointing at the new stack)
- // before the new stack has real data; if the new stack has done = 0
- // (before the old values are copied over), the goroutine might
- // do a cas via sg.selectdone and incorrectly believe that it has
- // won the right to complete the select, executing a second
- // communication and attempting to wake us (call ready) again.
- //
- // Then things break.
- //
- // The best break is that the goroutine doing ready sees the
- // _Gcopystack status and throws, as in #17007.
- // A worse break would be for us to continue on, start running real code,
- // block in a semaphore acquisition (sema.go), and have the other
- // goroutine wake us up without having really acquired the semaphore.
- // That would result in the goroutine spuriously running and then
- // queue up another spurious wakeup when the semaphore really is ready.
- // In general the situation can cascade until something notices the
- // problem and causes a crash.
- //
- // A stack shrink does not have this problem, because it locks
- // all the channels that are involved first, blocking out the
- // possibility of a cas on selectdone.
- //
- // A stack growth before gopark above does not have this
- // problem, because we hold those channel locks (released by
- // selparkcommit).
- //
- // A stack growth after sellock below does not have this
- // problem, because again we hold those channel locks.
- //
- // The only problem is a stack growth during sellock.
- // To keep that from happening, run sellock on the system stack.
- //
- // It might be that we could avoid this if copystack copied the
- // stack before calling adjustsudogs. In that case,
- // syncadjustsudogs would need to recopy the tiny part that
- // it copies today, resulting in a little bit of extra copying.
- //
- // An even better fix, not for the week before a release candidate,
- // would be to put space in every sudog and make selectdone
- // point at (say) the space in the first sudog.
-
- systemstack(func() {
- sellock(scases, lockorder)
- })
+ sellock(scases, lockorder)
+ gp.selectDone = 0
sg = (*sudog)(gp.param)
gp.param = nil
@@ -477,7 +421,7 @@ loop:
sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting.
for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
- sg1.selectdone = nil
+ sg1.isSelect = false
sg1.elem = nil
sg1.c = nil
}
@@ -528,10 +472,8 @@ loop:
print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
}
- if cas.kind == caseRecv {
- if cas.receivedp != nil {
- *cas.receivedp = true
- }
+ if cas.kind == caseRecv && cas.receivedp != nil {
+ *cas.receivedp = true
}
if raceenabled {