diff --git a/src/runtime/lockrank_off.go b/src/runtime/lockrank_off.go index c86726f3dd7d9f..edeb265f43e874 100644 --- a/src/runtime/lockrank_off.go +++ b/src/runtime/lockrank_off.go @@ -27,7 +27,8 @@ func lockWithRank(l *mutex, rank lockRank) { // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func acquireLockRank(rank lockRank) { +func acquireLockRankAndM(rank lockRank) { + acquirem() } func unlockWithRank(l *mutex) { @@ -37,7 +38,8 @@ func unlockWithRank(l *mutex) { // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func releaseLockRank(rank lockRank) { +func releaseLockRankAndM(rank lockRank) { + releasem(getg().m) } func lockWithRankMayAcquire(l *mutex, rank lockRank) { diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go index e95190f0b22628..120ebc21fae59a 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. diff --git a/src/runtime/proc.go b/src/runtime/proc.go index a029a23f7de610..d00f9dd5ba8788 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1067,7 +1067,7 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) { dumpgstatus(gp) throw("casfrom_Gscanstatus: gp->status is not in scan state") } - releaseLockRank(lockRankGscan) + releaseLockRankAndM(lockRankGscan) } // This will return false if the gp is not in the expected status and the cas fails. @@ -1081,7 +1081,7 @@ func castogscanstatus(gp *g, oldval, newval uint32) bool { if newval == oldval|_Gscan { r := gp.atomicstatus.CompareAndSwap(oldval, newval) if r { - acquireLockRank(lockRankGscan) + acquireLockRankAndM(lockRankGscan) } return r @@ -1110,8 +1110,7 @@ func casgstatus(gp *g, oldval, newval uint32) { }) } - acquireLockRank(lockRankGscan) - releaseLockRank(lockRankGscan) + lockWithRankMayAcquire(nil, lockRankGscan) // See https://golang.org/cl/21503 for justification of the yield delay. const yieldDelay = 5 * 1000 @@ -1245,7 +1244,7 @@ func casGToPreemptScan(gp *g, old, new uint32) { if old != _Grunning || new != _Gscan|_Gpreempted { throw("bad g transition") } - acquireLockRank(lockRankGscan) + acquireLockRankAndM(lockRankGscan) for !gp.atomicstatus.CompareAndSwap(_Grunning, _Gscan|_Gpreempted) { } } diff --git a/src/runtime/rwmutex.go b/src/runtime/rwmutex.go index 5833d5957661b4..4f9585f98d6b64 100644 --- a/src/runtime/rwmutex.go +++ b/src/runtime/rwmutex.go @@ -72,9 +72,7 @@ func (rw *rwmutex) rlock() { // things blocking on the lock may consume all of the Ps and // deadlock (issue #20903). Alternatively, we could drop the P // while sleeping. - acquirem() - - acquireLockRank(rw.readRank) + acquireLockRankAndM(rw.readRank) lockWithRankMayAcquire(&rw.rLock, getLockRank(&rw.rLock)) if rw.readerCount.Add(1) < 0 { @@ -116,8 +114,7 @@ func (rw *rwmutex) runlock() { unlock(&rw.rLock) } } - releaseLockRank(rw.readRank) - releasem(getg().m) + releaseLockRankAndM(rw.readRank) } // lock locks rw for writing.