aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/select.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2019-04-03 14:00:12 -0400
committerAustin Clements <austin@google.com>2019-10-25 23:25:33 +0000
commit36a432f27bbcc65fb03845ebe5e4a3db6f4cc189 (patch)
tree0374d3b67d27268c8d522ed721f161dcaab25b6e /src/runtime/select.go
parent8c5861576a983684faac98c612c9c7e569974ffa (diff)
downloadgo-36a432f27bbcc65fb03845ebe5e4a3db6f4cc189.tar.xz
runtime: make copystack/sudog synchronization more explicit
When we copy a stack of a goroutine blocked in a channel operation, we have to be very careful because other goroutines may be writing to that goroutine's stack. To handle this, stack copying acquires the locks for the channels a goroutine is waiting on. One complication is that stack growth may happen while a goroutine holds these locks, in which case stack copying must *not* acquire these locks because that would self-deadlock. Currently, stack growth never acquires these locks because stack growth only happens when a goroutine is running, which means it's either not blocking on a channel or it's holding the channel locks already. Stack shrinking always acquires these locks because shrinking happens asynchronously, so the goroutine is never running, so there are either no locks or they've been released by the goroutine. However, we're about to change when stack shrinking can happen, which is going to break the current rules. Rather than find a new way to derive whether to acquire these locks or not, this CL simply adds a flag to the g struct that indicates that stack copying should acquire channel locks. This flag is set while the goroutine is blocked on a channel op. For #10958, #24543. Change-Id: Ia2ac8831b1bfda98d39bb30285e144c4f7eaf9ab Reviewed-on: https://go-review.googlesource.com/c/go/+/172982 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/select.go')
-rw-r--r--src/runtime/select.go4
1 files changed, 4 insertions, 0 deletions
diff --git a/src/runtime/select.go b/src/runtime/select.go
index d2c5a03a1a..8033b6512f 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -75,6 +75,9 @@ func selunlock(scases []scase, lockorder []uint16) {
}
func selparkcommit(gp *g, _ unsafe.Pointer) bool {
+ // There are unlocked sudogs that point into gp's stack. Stack
+ // copying must lock the channels of those sudogs.
+ gp.activeStackChans = true
// This must not access gp's stack (see gopark). In
// particular, it must not access the *hselect. That's okay,
// because by the time this is called, gp.waiting has all
@@ -311,6 +314,7 @@ loop:
// wait for someone to wake us up
gp.param = nil
gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1)
+ gp.activeStackChans = false
sellock(scases, lockorder)