aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/lockrank_on.go
diff options
context:
space:
mode:
authorRhys Hiltner <rhys.hiltner@gmail.com>2024-04-19 22:12:18 +0000
committerGopher Robot <gobot@golang.org>2024-04-22 14:29:04 +0000
commit4bb67bc21eea06afadceec239bae6e5e40a9e759 (patch)
treec6a2329b64053275ae75435ec4ffee2248b28a18 /src/runtime/lockrank_on.go
parent2dddc7ef881669276c96356ec44c4e46ec20b1e9 (diff)
downloadgo-4bb67bc21eea06afadceec239bae6e5e40a9e759.tar.gz
go-4bb67bc21eea06afadceec239bae6e5e40a9e759.zip
runtime: always acquire M when acquiring locks by rank
Profiling of runtime-internal locks checks gp.m.locks to see if it's safe to add a new record to the profile, but direct use of acquireLockRank can change the list of the M's active lock ranks without updating gp.m.locks to match. The runtime's internal rwmutex implementation makes a point of calling acquirem/releasem when manipulating the lock rank list, but the other user of acquireLockRank (the GC's Gscan bit) relied on the GC's invariants to avoid deadlocks. Codify the rwmutex approach by renaming acquireLockRank to acquireLockRankAndM and having it include a call to aquirem. Do the same for release. Fixes #64706 Fixes #66004 Change-Id: Ib76eaa0cc1c45b64861d03345e17e1e843c19713 GitHub-Last-Rev: 160577bdb2bb2a4e869c6fd7e53e3be8fb819182 GitHub-Pull-Request: golang/go#66276 Reviewed-on: https://go-review.googlesource.com/c/go/+/571056 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Auto-Submit: Rhys Hiltner <rhys.hiltner@gmail.com> Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/lockrank_on.go')
-rw-r--r--src/runtime/lockrank_on.go16
1 files changed, 12 insertions, 4 deletions
diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go
index e95190f0b2..120ebc21fa 100644
--- a/src/runtime/lockrank_on.go
+++ b/src/runtime/lockrank_on.go
@@ -104,12 +104,16 @@ func printHeldLocks(gp *g) {
}
}
-// acquireLockRank acquires a rank which is not associated with a mutex lock
+// acquireLockRankAndM acquires a rank which is not associated with a mutex
+// lock. To maintain the invariant that an M with m.locks==0 does not hold any
+// lock-like resources, it also acquires the M.
//
// This function may be called in nosplit context and thus must be nosplit.
//
//go:nosplit
-func acquireLockRank(rank lockRank) {
+func acquireLockRankAndM(rank lockRank) {
+ acquirem()
+
gp := getg()
// Log the new class. See comment on lockWithRank.
systemstack(func() {
@@ -189,12 +193,14 @@ func unlockWithRank(l *mutex) {
})
}
-// releaseLockRank releases a rank which is not associated with a mutex lock
+// releaseLockRankAndM releases a rank which is not associated with a mutex
+// lock. To maintain the invariant that an M with m.locks==0 does not hold any
+// lock-like resources, it also releases the M.
//
// This function may be called in nosplit context and thus must be nosplit.
//
//go:nosplit
-func releaseLockRank(rank lockRank) {
+func releaseLockRankAndM(rank lockRank) {
gp := getg()
systemstack(func() {
found := false
@@ -211,6 +217,8 @@ func releaseLockRank(rank lockRank) {
throw("lockRank release without matching lockRank acquire")
}
})
+
+ releasem(getg().m)
}
// nosplit because it may be called from nosplit contexts.