aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/mgc.go19
-rw-r--r--src/runtime/proc.go29
-rw-r--r--src/runtime/stack.go21
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