diff options
-rw-r--r-- | src/runtime/mgcmark.go | 33 | ||||
-rw-r--r-- | src/runtime/proc1.go | 25 |
2 files changed, 46 insertions, 12 deletions
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 64cc1af64f..ac93e16606 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -365,6 +365,8 @@ func scanstack(gp *g) { throw("g already has stack barriers") } + gcLockStackBarriers(gp) + case _GCmarktermination: if int(gp.stkbarPos) == len(gp.stkbar) { // gp hit all of the stack barriers (or there @@ -419,6 +421,9 @@ func scanstack(gp *g) { if gcphase == _GCmarktermination { gcw.dispose() } + if gcphase == _GCscan { + gcUnlockStackBarriers(gp) + } gp.gcscanvalid = true } @@ -572,6 +577,8 @@ func gcRemoveStackBarriers(gp *g) { print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n") } + gcLockStackBarriers(gp) + // Remove stack barriers that we didn't hit. for _, stkbar := range gp.stkbar[gp.stkbarPos:] { gcRemoveStackBarrier(gp, stkbar) @@ -581,6 +588,8 @@ func gcRemoveStackBarriers(gp *g) { // adjust them. gp.stkbarPos = 0 gp.stkbar = gp.stkbar[:0] + + gcUnlockStackBarriers(gp) } // gcRemoveStackBarrier removes a single stack barrier. It is the @@ -627,6 +636,7 @@ func gcPrintStkbars(stkbar []stkbar) { // //go:nosplit func gcUnwindBarriers(gp *g, sp uintptr) { + gcLockStackBarriers(gp) // On LR machines, if there is a stack barrier on the return // from the frame containing sp, this will mark it as hit even // though it isn't, but it's okay to be conservative. @@ -635,6 +645,7 @@ func gcUnwindBarriers(gp *g, sp uintptr) { gcRemoveStackBarrier(gp, gp.stkbar[gp.stkbarPos]) gp.stkbarPos++ } + gcUnlockStackBarriers(gp) if debugStackBarrier && gp.stkbarPos != before { print("skip barriers below ", hex(sp), " in goid=", gp.goid, ": ") gcPrintStkbars(gp.stkbar[before:gp.stkbarPos]) @@ -658,6 +669,28 @@ func setNextBarrierPC(pc uintptr) { gp.stkbar[gp.stkbarPos].savedLRVal = pc } +// gcLockStackBarriers synchronizes with tracebacks of gp's stack +// during sigprof for installation or removal of stack barriers. It +// blocks until any current sigprof is done tracebacking gp's stack +// and then disallows profiling tracebacks of gp's stack. +// +// This is necessary because a sigprof during barrier installation or +// removal could observe inconsistencies between the stkbar array and +// the stack itself and crash. +func gcLockStackBarriers(gp *g) { + for !cas(&gp.stackLock, 0, 1) { + osyield() + } +} + +func gcTryLockStackBarriers(gp *g) bool { + return cas(&gp.stackLock, 0, 1) +} + +func gcUnlockStackBarriers(gp *g) { + atomicstore(&gp.stackLock, 0) +} + // TODO(austin): Can we consolidate the gcDrain* functions? // gcDrain scans objects in work buffers, blackening grey diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index 55f1a24ec2..54cb3eb77f 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -414,13 +414,7 @@ func scang(gp *g) { // the goroutine until we're done. if castogscanstatus(gp, s, s|_Gscan) { if !gp.gcscandone { - // Coordinate with traceback - // in sigprof. - for !cas(&gp.stackLock, 0, 1) { - osyield() - } scanstack(gp) - atomicstore(&gp.stackLock, 0) gp.gcscandone = true } restartg(gp) @@ -2500,11 +2494,6 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { // Profiling runs concurrently with GC, so it must not allocate. mp.mallocing++ - // Coordinate with stack barrier insertion in scanstack. - for !cas(&gp.stackLock, 0, 1) { - osyield() - } - // Define that a "user g" is a user-created goroutine, and a "system g" // is one that is m->g0 or m->gsignal. // @@ -2571,8 +2560,18 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { // transition. We simply require that g and SP match and that the PC is not // in gogo. traceback := true + haveStackLock := false if gp == nil || sp < gp.stack.lo || gp.stack.hi < sp || setsSP(pc) { traceback = false + } else if gp.m.curg != nil { + if gcTryLockStackBarriers(gp.m.curg) { + haveStackLock = true + } else { + // Stack barriers are being inserted or + // removed, so we can't get a consistent + // traceback right now. + traceback = false + } } var stk [maxCPUProfStack]uintptr n := 0 @@ -2615,7 +2614,9 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { } } } - atomicstore(&gp.stackLock, 0) + if haveStackLock { + gcUnlockStackBarriers(gp.m.curg) + } if prof.hz != 0 { // Simple cas-lock to coordinate with setcpuprofilerate. |