gp.schedlink = 0
// Park the calling goroutine.
- gp.waitreason = waitReasonDebugCall
if trace.enabled {
traceGoPark(traceEvGoBlock, 1)
}
- casgstatus(gp, _Grunning, _Gwaiting)
+ casGToWaiting(gp, _Grunning, waitReasonDebugCall)
dropg()
// Directly execute the new goroutine. The debug
assertWorldStopped()
gp := getg()
- casgstatus(gp.m.curg, _Grunning, _Gwaiting)
- gp.waitreason = waitReasonDumpingHeap
+ casGToWaiting(gp.m.curg, _Grunning, waitReasonDumpingHeap)
// Set dump file.
dumpfd = fd
// Otherwise, our attempt to force all P's to a safepoint could
// result in a deadlock as we attempt to preempt a worker that's
// trying to preempt us (e.g. for a stack scan).
- casgstatus(gp, _Grunning, _Gwaiting)
+ casGToWaiting(gp, _Grunning, waitReasonGCMarkTermination)
forEachP(func(pp *p) {
// Flush the write barrier buffer, since this may add
// work to the gcWork.
mp.preemptoff = "gcing"
mp.traceback = 2
curgp := mp.curg
- casgstatus(curgp, _Grunning, _Gwaiting)
- curgp.waitreason = waitReasonGarbageCollection
+ casGToWaiting(curgp, _Grunning, waitReasonGarbageCollection)
// Run gc on the g0 stack. We do this so that the g stack
// we're currently running on will no longer change. Cuts
// the G stack. However, stack shrinking is
// disabled for mark workers, so it is safe to
// read from the G stack.
- casgstatus(gp, _Grunning, _Gwaiting)
+ casGToWaiting(gp, _Grunning, waitReasonGCWorkerActive)
switch pp.gcMarkWorkerMode {
default:
throw("gcBgMarkWorker: unexpected gcMarkWorkerMode")
userG := getg().m.curg
selfScan := gp == userG && readgstatus(userG) == _Grunning
if selfScan {
- casgstatus(userG, _Grunning, _Gwaiting)
- userG.waitreason = waitReasonGarbageCollectionScan
+ casGToWaiting(userG, _Grunning, waitReasonGarbageCollectionScan)
}
// TODO: suspendG blocks (and spins) until gp
}
// gcDrainN requires the caller to be preemptible.
- casgstatus(gp, _Grunning, _Gwaiting)
- gp.waitreason = waitReasonGCAssistMarking
+ casGToWaiting(gp, _Grunning, waitReasonGCAssistMarking)
// drain own cached work first in the hopes that it
// will be more cache friendly.
}
}
+// casGToWaiting transitions gp from old to _Gwaiting, and sets the wait reason.
+//
+// Use this over casgstatus when possible to ensure that a waitreason is set.
+func casGToWaiting(gp *g, old uint32, reason waitReason) {
+ gp.waitreason = reason
+ casgstatus(gp, old, _Gwaiting)
+}
+
// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
// Returns old status. Cannot call casgstatus directly, because we are racing with an
// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
if old != _Gpreempted || new != _Gwaiting {
throw("bad g transition")
}
+ gp.waitreason = waitReasonPreempted
return gp.atomicstatus.CompareAndSwap(_Gpreempted, _Gwaiting)
}
// 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.
- casgstatus(gp, _Grunning, _Gwaiting)
+ // Don't provide a wait reason because we're still executing.
+ casGToWaiting(gp, _Grunning, waitReasonStoppingTheWorld)
stopTheWorldWithSema()
casgstatus(gp, _Gwaiting, _Grunning)
})
traceGoPark(mp.waittraceev, mp.waittraceskip)
}
+ // N.B. Not using casGToWaiting here because the waitreason is
+ // set by park_m's caller.
casgstatus(gp, _Grunning, _Gwaiting)
dropg()
dumpgstatus(gp)
throw("bad g status")
}
- gp.waitreason = waitReasonPreempted
if gp.asyncSafePoint {
// Double-check that async preemption does not
gp._defer = nil // should be true already but just in case.
gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
gp.writebuf = nil
- gp.waitreason = 0
+ gp.waitreason = waitReasonZero
gp.param = nil
gp.labels = nil
gp.timer = nil
waitReasonTraceReaderBlocked // "trace reader (blocked)"
waitReasonWaitForGCCycle // "wait for GC cycle"
waitReasonGCWorkerIdle // "GC worker (idle)"
+ waitReasonGCWorkerActive // "GC worker (active)"
waitReasonPreempted // "preempted"
waitReasonDebugCall // "debug call"
+ waitReasonGCMarkTermination // "GC mark termination"
+ waitReasonStoppingTheWorld // "stopping the world"
)
var waitReasonStrings = [...]string{
waitReasonTraceReaderBlocked: "trace reader (blocked)",
waitReasonWaitForGCCycle: "wait for GC cycle",
waitReasonGCWorkerIdle: "GC worker (idle)",
+ waitReasonGCWorkerActive: "GC worker (active)",
waitReasonPreempted: "preempted",
waitReasonDebugCall: "debug call",
+ waitReasonGCMarkTermination: "GC mark termination",
+ waitReasonStoppingTheWorld: "stopping the world",
}
func (w waitReason) String() string {