aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/stack.go
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2020-04-15 12:35:24 -0700
committerDan Scales <danscales@google.com>2020-05-07 20:45:42 +0000
commitf9640b88c7e5f4df3350643f3ec6c30c30e8678d (patch)
tree3135a1d5eaa231190acd85f20b2eec0b9b48131c /src/runtime/stack.go
parent33213039e5d806f93a11561609c804cef7c065b3 (diff)
downloadgo-f9640b88c7e5f4df3350643f3ec6c30c30e8678d.tar.xz
runtime: incorporate Gscan acquire/release into lock ranking order
I added routines that can acquire/release a particular rank without acquiring/releasing an associated lock. I added lockRankGscan as a rank for acquiring/releasing the Gscan bit. castogscanstatus() and casGtoPreemptScan() are acquires of the Gscan bit. casfrom_Gscanstatus() is a release of the Gscan bit. casgstatus() is like an acquire and release of the Gscan bit, since it will wait if Gscan bit is currently set. We have a cycle between hchan and Gscan. The acquisition of Gscan and then hchan only happens in syncadjustsudogs() when the G is suspended, so the main normal ordering (get hchan, then get Gscan) can't be happening. So, I added a new rank lockRankHchanLeaf that is used when acquiring hchan locks in syncadjustsudogs. This ranking is set so no other locks can be acquired except other hchan locks. Fixes #38922 Change-Id: I58ce526a74ba856cb42078f7b9901f2832e1d45c Reviewed-on: https://go-review.googlesource.com/c/go/+/228417 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/stack.go')
-rw-r--r--src/runtime/stack.go11
1 files changed, 10 insertions, 1 deletions
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 6e1f07bf73..52e54171cb 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -794,7 +794,16 @@ func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
var lastc *hchan
for sg := gp.waiting; sg != nil; sg = sg.waitlink {
if sg.c != lastc {
- lock(&sg.c.lock)
+ // There is a ranking cycle here between gscan bit and
+ // hchan locks. Normally, we only allow acquiring hchan
+ // locks and then getting a gscan bit. In this case, we
+ // already have the gscan bit. We allow acquiring hchan
+ // locks here as a special case, since a deadlock can't
+ // happen because the G involved must already be
+ // suspended. So, we get a special hchan lock rank here
+ // that is lower than gscan, but doesn't allow acquiring
+ // any other locks other than hchan.
+ lockWithRank(&sg.c.lock, lockRankHchanLeaf)
}
lastc = sg.c
}