}
// findRunnable returns the background mark worker for _p_ if it
-// should be run. This must only be called when gcphase == _GCmark.
+// should be run. This must only be called when gcBlackenEnabled != 0.
func (c *gcControllerState) findRunnable(_p_ *p) *g {
- if gcphase != _GCmark {
- throw("gcControllerState.findRunnable: not in mark phase")
+ if gcBlackenEnabled == 0 {
+ throw("gcControllerState.findRunnable: blackening not enabled")
}
if _p_.gcBgMarkWorker == nil {
throw("gcControllerState.findRunnable: no background mark worker")
gcscan_m()
gctimer.cycle.installmarkwb = nanotime()
- // Enter mark phase, enabling write barriers
- // and mutator assists.
- //
- // TODO: Elimate this STW. This requires
- // enabling write barriers in all mutators
- // before enabling any mutator assists or
- // background marking.
+ // Enter mark phase. This enables write
+ // barriers.
if debug.gctrace > 0 {
tInstallWB = nanotime()
}
- stoptheworld()
- gcBgMarkPrepare()
- gcphase = _GCmark
-
- // Concurrent mark.
- starttheworld()
+ atomicstore(&gcphase, _GCmark)
+ // Ensure all Ps have observed the phase
+ // change and have write barriers enabled
+ // before any blackening occurs.
+ forEachP(func(*p) {})
})
+ // Concurrent mark.
+ gcBgMarkPrepare() // Must happen before assist enable.
+ // At this point all Ps have enabled the mark phase
+ // write barrier, thus maintaining the no white to
+ // black invariant. Mutator assists and mark workers
+ // can now be enabled to safely blacken grey objects.
+ atomicstore(&gcBlackenEnabled, 1)
gctimer.cycle.mark = nanotime()
if debug.gctrace > 0 {
tMark = nanotime()
// World is stopped.
// Start marktermination which includes enabling the write barrier.
+ atomicstore(&gcBlackenEnabled, 0)
gcphase = _GCmarktermination
if debug.gctrace > 0 {
// Update work.totaltime
sweepTermCpu := int64(stwprocs) * (tScan - tSweepTerm)
scanCpu := tInstallWB - tScan
- installWBCpu := int64(stwprocs) * (tMark - tInstallWB)
+ installWBCpu := int64(0)
// We report idle marking time below, but omit it from
// the overall utilization here since it's "free".
markCpu := gcController.assistTime + gcController.dedicatedMarkTime + gcController.fractionalMarkTime
// dispose the gcw, and then preempt.
mp = acquirem()
+ if gcBlackenEnabled == 0 {
+ throw("gcBgMarkWorker: blackening not enabled")
+ }
+
startTime := nanotime()
xadd(&work.nwait, -1)
done := false
switch p.gcMarkWorkerMode {
+ default:
+ throw("gcBgMarkWorker: unexpected gcMarkWorkerMode")
case gcMarkWorkerDedicatedMode:
gcDrain(&p.gcw, gcBgCreditSlack)
// gcDrain did the xadd(&work.nwait +1) to
}
stop:
- // We have nothing to do. If we're in the GC mark phase, run
- // idle-time marking rather than give up the P.
- if _p_ := _g_.m.p.ptr(); gcphase == _GCmark && _p_.gcBgMarkWorker != nil {
+ // We have nothing to do. If we're in the GC mark phaseand can
+ // safely scan and blacken objects, run idle-time marking
+ // rather than give up the P.
+ if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil {
_p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
gp := _p_.gcBgMarkWorker
casgstatus(gp, _Gwaiting, _Grunnable)
resetspinning()
}
}
- if gp == nil && gcphase == _GCmark {
+ if gp == nil && gcBlackenEnabled != 0 {
gp = gcController.findRunnable(_g_.m.p.ptr())
if gp != nil {
resetspinning()