sched.needspinning.Store(0)
}
+// Take a snapshot of allp, for use after dropping the P.
+//
+// Must be called with a P, but the returned slice may be used after dropping
+// the P. The M holds a reference on the snapshot to keep the backing array
+// alive.
+//
+//go:yeswritebarrierrec
+func (mp *m) snapshotAllp() []*p {
+ mp.allpSnapshot = allp
+ return mp.allpSnapshot
+}
+
+// Clear the saved allp snapshot. Should be called as soon as the snapshot is
+// no longer required.
+//
+// Must be called after reacquiring a P, as it requires a write barrier.
+//
+//go:yeswritebarrierrec
+func (mp *m) clearAllpSnapshot() {
+ mp.allpSnapshot = nil
+}
+
func (mp *m) hasCgoOnStack() bool {
return mp.ncgo > 0 || mp.isextra
}
// an M.
top:
+ // We may have collected an allp snapshot below. The snapshot is only
+ // required in each loop iteration. Clear it to all GC to collect the
+ // slice.
+ mp.clearAllpSnapshot()
+
pp := mp.p.ptr()
if sched.gcwaiting.Load() {
gcstopm()
// which can change underfoot once we no longer block
// safe-points. We don't need to snapshot the contents because
// everything up to cap(allp) is immutable.
- allpSnapshot := allp
+ //
+ // We clear the snapshot from the M after return via
+ // mp.clearAllpSnapshop (in schedule) and on each iteration of the top
+ // loop.
+ allpSnapshot := mp.snapshotAllp()
// Also snapshot masks. Value changes are OK, but we can't allow
// len to change out from under us.
idlepMaskSnapshot := idlepMask
pollUntil = checkTimersNoP(allpSnapshot, timerpMaskSnapshot, pollUntil)
}
+ // We don't need allp anymore at this pointer, but can't clear the
+ // snapshot without a P for the write barrier..
+
// Poll network until next timer.
if netpollinited() && (netpollAnyWaiters() || pollUntil != 0) && sched.lastpoll.Swap(0) != 0 {
sched.pollUntil.Store(pollUntil)
gp, inheritTime, tryWakeP := findRunnable() // blocks until work is available
+ // findRunnable may have collected an allp snapshot. The snapshot is
+ // only required within findRunnable. Clear it to all GC to collect the
+ // slice.
+ mp.clearAllpSnapshot()
+
if debug.dontfreezetheworld > 0 && freezing.Load() {
// See comment in freezetheworld. We don't want to perturb
// scheduler state, so we didn't gcstopm in findRunnable, but