// credit to gcController.bgScanCredit every gcCreditSlack units of
// scan work.
//
+// gcDrain will always return if there is a pending STW.
+//
//go:nowritebarrier
func gcDrain(gcw *gcWork, flags gcDrainFlags) {
if !writeBarrier.needed {
// Drain root marking jobs.
if work.markrootNext < work.markrootJobs {
- for !(preemptible && gp.preempt) {
+ // Stop if we're preemptible or if someone wants to STW.
+ for !(gp.preempt && (preemptible || atomic.Load(&sched.gcwaiting) != 0)) {
job := atomic.Xadd(&work.markrootNext, +1) - 1
if job >= work.markrootJobs {
break
}
// Drain heap marking jobs.
- for !(preemptible && gp.preempt) {
+ // Stop if we're preemptible or if someone wants to STW.
+ for !(gp.preempt && (preemptible || atomic.Load(&sched.gcwaiting) != 0)) {
// Try to keep work available on the global queue. We used to
// check if there were waiting workers, but it's better to
// just keep work available than to make workers wait. In the