diff options
Diffstat (limited to 'src/runtime/mgcmark.go')
-rw-r--r-- | src/runtime/mgcmark.go | 33 |
1 files changed, 33 insertions, 0 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 |