diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index bc157cddbb..425ed3a160 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1266,6 +1266,13 @@ func gcMarkTermination() { // Free stack spans. This must be done between GC cycles. systemstack(freeStackSpans) + // Best-effort remove stack barriers so they don't get in the + // way of things like GDB and perf. + lock(&allglock) + myallgs := allgs + unlock(&allglock) + gcTryRemoveAllStackBarriers(myallgs) + // Print gctrace before dropping worldsema. As soon as we drop // worldsema another cycle could start and smash the stats // we're trying to print. diff --git a/src/runtime/mstkbar.go b/src/runtime/mstkbar.go index f320c351d0..1bf9d573b7 100644 --- a/src/runtime/mstkbar.go +++ b/src/runtime/mstkbar.go @@ -257,6 +257,31 @@ func gcRemoveStackBarrier(gp *g, stkbar stkbar) { *lrPtr = sys.Uintreg(stkbar.savedLRVal) } +// gcTryRemoveAllStackBarriers tries to remove stack barriers from all +// Gs in gps. It is best-effort and efficient. If it can't remove +// barriers from a G immediately, it will simply skip it. +func gcTryRemoveAllStackBarriers(gps []*g) { + for _, gp := range gps { + retry: + for { + switch s := readgstatus(gp); s { + default: + break retry + + case _Grunnable, _Gsyscall, _Gwaiting: + if !castogscanstatus(gp, s, s|_Gscan) { + continue + } + gcLockStackBarriers(gp) + gcRemoveStackBarriers(gp) + gcUnlockStackBarriers(gp) + restartg(gp) + break retry + } + } + } +} + // gcPrintStkbars prints the stack barriers of gp for debugging. It // places a "@@@" marker at gp.stkbarPos. If marker >= 0, it will also // place a "==>" marker before the marker'th entry.