aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mgcmark.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/mgcmark.go')
-rw-r--r--src/runtime/mgcmark.go33
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