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>
lockRankTraceStackTab
lockRankPanic
lockRankDeadlock
+ lockRankRaceFini
)
// lockRankLeafRank is the rank of lock that does not have a declared rank,
lockRankTraceStackTab: "traceStackTab",
lockRankPanic: "panic",
lockRankDeadlock: "deadlock",
+ lockRankRaceFini: "raceFini",
}
func (rank lockRank) String() string {
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},
}
package runtime
+const staticLockRanking = false
+
// // lockRankStruct is embedded in mutex, but is empty when staticklockranking is
// disabled (the default)
type lockRankStruct struct {
"unsafe"
)
+const staticLockRanking = true
+
// worldIsStopped is accessed atomically to track world-stops. 1 == world
// stopped.
var worldIsStopped atomic.Uint32
// 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.
// 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
}
// 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
# 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
g0 g
mcache0 *mcache
raceprocctx0 uintptr
+ raceFiniLock mutex
)
// This slice records the initializing tasks that need to be
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")
//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")
return
}
-var raceFiniLock mutex
-
//go:nosplit
func racefini() {
// racefini() can only be called once to avoid races.