diff options
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/mgc.go | 19 | ||||
| -rw-r--r-- | src/runtime/proc.go | 29 | ||||
| -rw-r--r-- | src/runtime/stack.go | 21 |
3 files changed, 27 insertions, 42 deletions
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index f2df1a00e0..26cec37f74 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1521,18 +1521,15 @@ func gcBgMarkWorker(ready chan struct{}) { } systemstack(func() { - // Mark our goroutine preemptible so its stack - // can be scanned or observed by the execution - // tracer. This, for example, lets two mark workers - // scan each other (otherwise, they would - // deadlock). We must not modify anything on - // the G stack. However, stack shrinking is - // disabled for mark workers, so it is safe to - // read from the G stack. + // Mark our goroutine preemptible so its stack can be scanned or observed + // by the execution tracer. This, for example, lets two mark workers scan + // each other (otherwise, they would deadlock). // - // N.B. The execution tracer is not aware of this status - // transition and handles it specially based on the - // wait reason. + // casGToWaitingForSuspendG marks the goroutine as ineligible for a + // stack shrink, effectively pinning the stack in memory for the duration. + // + // N.B. The execution tracer is not aware of this status transition and + // handles it specially based on the wait reason. casGToWaitingForSuspendG(gp, _Grunning, waitReasonGCWorkerActive) switch pp.gcMarkWorkerMode { default: diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 25d39d9ba3..8d5f2fc793 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1372,6 +1372,9 @@ func casGToWaiting(gp *g, old uint32, reason waitReason) { // casGToWaitingForSuspendG transitions gp from old to _Gwaiting, and sets the wait reason. // The wait reason must be a valid isWaitingForSuspendG wait reason. // +// While a goroutine is in this state, it's stack is effectively pinned. +// The garbage collector must not shrink or otherwise mutate the goroutine's stack. +// // Use this over casgstatus when possible to ensure that a waitreason is set. func casGToWaitingForSuspendG(gp *g, old uint32, reason waitReason) { if !reason.isWaitingForSuspendG() { @@ -1608,18 +1611,11 @@ func stopTheWorldWithSema(reason stwReason) worldStop { // stack while we try to stop the world since otherwise we could get // in a mutual preemption deadlock. // - // We must not modify anything on the G stack because a stack shrink - // may occur, now that we switched to _Gwaiting, specifically if we're - // doing this during the mark phase (mark termination excepted, since - // we know that stack scanning is done by that point). A stack shrink - // is otherwise OK though because in order to return from this function - // (and to leave the system stack) we must have preempted all - // goroutines, including any attempting to scan our stack, in which - // case, any stack shrinking will have already completed by the time we - // exit. + // casGToWaitingForSuspendG marks the goroutine as ineligible for a + // stack shrink, effectively pinning the stack in memory for the duration. // // N.B. The execution tracer is not aware of this status transition and - // andles it specially based on the wait reason. + // handles it specially based on the wait reason. casGToWaitingForSuspendG(getg().m.curg, _Grunning, waitReasonStoppingTheWorld) trace := traceAcquire() @@ -2106,16 +2102,11 @@ func forEachP(reason waitReason, fn func(*p)) { // deadlock as we attempt to preempt a goroutine that's trying // to preempt us (e.g. for a stack scan). // - // We must not modify anything on the G stack because a stack shrink - // may occur. A stack shrink is otherwise OK though because in order - // to return from this function (and to leave the system stack) we - // must have preempted all goroutines, including any attempting - // to scan our stack, in which case, any stack shrinking will - // have already completed by the time we exit. + // casGToWaitingForSuspendG marks the goroutine as ineligible for a + // stack shrink, effectively pinning the stack in memory for the duration. // - // N.B. The execution tracer is not aware of this status - // transition and handles it specially based on the - // wait reason. + // N.B. The execution tracer is not aware of this status transition and + // handles it specially based on the wait reason. casGToWaitingForSuspendG(gp, _Grunning, reason) forEachPInternal(fn) casgstatus(gp, _Gwaiting, _Grunning) diff --git a/src/runtime/stack.go b/src/runtime/stack.go index a338708d76..d809820b07 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1214,15 +1214,18 @@ func isShrinkStackSafe(gp *g) bool { if gp.parkingOnChan.Load() { return false } - // We also can't copy the stack while tracing is enabled, and - // gp is in _Gwaiting solely to make itself available to suspendG. + // We also can't copy the stack while a gp is in _Gwaiting solely + // to make itself available to suspendG. + // // In these cases, the G is actually executing on the system - // stack, and the execution tracer may want to take a stack trace - // of the G's stack. Note: it's safe to access gp.waitreason here. - // We're only checking if this is true if we took ownership of the + // stack, and the execution tracer, mutex profiler, etc. may want + // to take a stack trace of the G's stack. + // + // Note: it's safe to access gp.waitreason here. + // We're only calling isShrinkStackSafe if we took ownership of the // G with the _Gscan bit. This prevents the goroutine from transitioning, // which prevents gp.waitreason from changing. - if traceEnabled() && readgstatus(gp)&^_Gscan == _Gwaiting && gp.waitreason.isWaitingForSuspendG() { + if readgstatus(gp)&^_Gscan == _Gwaiting && gp.waitreason.isWaitingForSuspendG() { return false } return true @@ -1258,12 +1261,6 @@ func shrinkstack(gp *g) { if debug.gcshrinkstackoff > 0 { return } - f := findfunc(gp.startpc) - if f.valid() && f.funcID == abi.FuncID_gcBgMarkWorker { - // We're not allowed to shrink the gcBgMarkWorker - // stack (see gcBgMarkWorker for explanation). - return - } oldsize := gp.stack.hi - gp.stack.lo newsize := oldsize / 2 |
