aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/runtime/mgcmark.go33
-rw-r--r--src/runtime/proc1.go25
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.