]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add raceFiniLock to lock ranking
authorIan Lance Taylor <iant@golang.org>
Sun, 23 Apr 2023 19:25:47 +0000 (12:25 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 24 Apr 2023 21:37:06 +0000 (21:37 +0000)
Also preserve the PC/SP in reentersyscall when doing lock ranking.
The test is TestDestructorCallbackRace with the staticlockranking
experiment enabled.

For #59711

Change-Id: I87ac1d121ec0d399de369666834891ab9e7d11b0
Reviewed-on: https://go-review.googlesource.com/c/go/+/487955
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>

src/runtime/lockrank.go
src/runtime/lockrank_off.go
src/runtime/lockrank_on.go
src/runtime/mklockrank.go
src/runtime/proc.go
src/runtime/race.go

index 284a61e3365c9ebb30994fbe06768aaab1877070..c2d85ef11bf015d6cb52102bff3eae392fc22211 100644 (file)
@@ -62,6 +62,7 @@ const (
        lockRankTraceStackTab
        lockRankPanic
        lockRankDeadlock
+       lockRankRaceFini
 )
 
 // lockRankLeafRank is the rank of lock that does not have a declared rank,
@@ -115,6 +116,7 @@ var lockNames = []string{
        lockRankTraceStackTab:  "traceStackTab",
        lockRankPanic:          "panic",
        lockRankDeadlock:       "deadlock",
+       lockRankRaceFini:       "raceFini",
 }
 
 func (rank lockRank) String() string {
@@ -181,4 +183,5 @@ var lockPartialOrder [][]lockRank = [][]lockRank{
        lockRankTraceStackTab:  {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankPollDesc, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRwmutexW, lockRankRwmutexR, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankGcBitsArenas, lockRankMspanSpecial, lockRankSpanSetSpine, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace},
        lockRankPanic:          {},
        lockRankDeadlock:       {lockRankPanic, lockRankDeadlock},
+       lockRankRaceFini:       {lockRankPanic},
 }
index bf046a104124e32e8ca3a8bc38a6ea5d7ea7bdae..c86726f3dd7d9fe47ad294078e4dc7676d3c9c7f 100644 (file)
@@ -6,6 +6,8 @@
 
 package runtime
 
+const staticLockRanking = false
+
 // // lockRankStruct is embedded in mutex, but is empty when staticklockranking is
 // disabled (the default)
 type lockRankStruct struct {
index 5dcc79b15eb85d3429e319a3a660714795c5e1a3..bf530eeb5bcf101c292263623f4fd5aa28464119 100644 (file)
@@ -11,6 +11,8 @@ import (
        "unsafe"
 )
 
+const staticLockRanking = true
+
 // worldIsStopped is accessed atomically to track world-stops. 1 == world
 // stopped.
 var worldIsStopped atomic.Uint32
@@ -49,7 +51,7 @@ func getLockRank(l *mutex) lockRank {
 // split on entry to lock2() would record stack split locks as taken after l,
 // even though l is not actually locked yet.
 func lockWithRank(l *mutex, rank lockRank) {
-       if l == &debuglock || l == &paniclk {
+       if l == &debuglock || l == &paniclk || l == &raceFiniLock {
                // debuglock is only used for println/printlock(). Don't do lock
                // rank recording for it, since print/println are used when
                // printing out a lock ordering problem below.
@@ -59,6 +61,10 @@ func lockWithRank(l *mutex, rank lockRank) {
                // lock ordering problem. Additionally, paniclk may be taken
                // after effectively any lock (anywhere we might panic), which
                // the partial order doesn't cover.
+               //
+               // raceFiniLock is held while exiting when running
+               // the race detector. Don't do lock rank recording for it,
+               // since we are exiting.
                lock2(l)
                return
        }
@@ -159,7 +165,7 @@ func checkRanks(gp *g, prevRank, rank lockRank) {
 
 // See comment on lockWithRank regarding stack splitting.
 func unlockWithRank(l *mutex) {
-       if l == &debuglock || l == &paniclk {
+       if l == &debuglock || l == &paniclk || l == &raceFiniLock {
                // See comment at beginning of lockWithRank.
                unlock2(l)
                return
index bc15e57dd4c9fae63a2fcc073261555121002cea..87328baf382817490f8c49e2bb1fad5862bef716 100644 (file)
@@ -179,6 +179,8 @@ NONE < panic;
 # deadlock is not acquired while holding panic, but it also needs to be
 # below all other locks.
 panic < deadlock;
+# raceFini is only held while exiting.
+panic < raceFini;
 `
 
 // cyclicRanks lists lock ranks that allow multiple locks of the same
index fdbf888c4f635a1debc490184c1f6261ecc7cf8d..26bab27cb1d85c5ee46b5fbbbf0785f1d2fe3ca5 100644 (file)
@@ -115,6 +115,7 @@ var (
        g0           g
        mcache0      *mcache
        raceprocctx0 uintptr
+       raceFiniLock mutex
 )
 
 // This slice records the initializing tasks that need to be
@@ -3773,6 +3774,11 @@ func reentersyscall(pc, sp uintptr) {
        gp.syscallsp = sp
        gp.syscallpc = pc
        casgstatus(gp, _Grunning, _Gsyscall)
+       if staticLockRanking {
+               // When doing static lock ranking casgstatus can call
+               // systemstack which clobbers g.sched.
+               save(pc, sp)
+       }
        if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
                systemstack(func() {
                        print("entersyscall inconsistent ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
index 7c7b78c145065dfd27023c856078c171372b7121..9120db28da6123023d36ae1dfa2aca755248df18 100644 (file)
@@ -355,6 +355,8 @@ func isvalidaddr(addr unsafe.Pointer) bool {
 
 //go:nosplit
 func raceinit() (gctx, pctx uintptr) {
+       lockInit(&raceFiniLock, lockRankRaceFini)
+
        // On most machines, cgo is required to initialize libc, which is used by race runtime.
        if !iscgo && GOOS != "darwin" {
                throw("raceinit: race build must use cgo")
@@ -397,8 +399,6 @@ func raceinit() (gctx, pctx uintptr) {
        return
 }
 
-var raceFiniLock mutex
-
 //go:nosplit
 func racefini() {
        // racefini() can only be called once to avoid races.