]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/runtime/proc.go
runtime: make it harder to introduce deadlocks with forEachP
[gostls13.git] / src / runtime / proc.go
index ae2562a5b76caa70e5a6ca3b71eb53d1909f3c4b..159c19caf35dcacd8b81c659121d648b542daf06 100644 (file)
@@ -1820,10 +1820,35 @@ found:
 // fn will run on every CPU executing Go code, but it acts as a global
 // memory barrier. GC uses this as a "ragged barrier."
 //
-// The caller must hold worldsema.
+// The caller must hold worldsema. fn must not refer to any
+// part of the current goroutine's stack, since the GC may move it.
+func forEachP(reason waitReason, fn func(*p)) {
+       systemstack(func() {
+               gp := getg().m.curg
+               // Mark the user stack as preemptible so that it may be scanned.
+               // 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).
+               //
+               // N.B. The execution tracer is not aware of this status
+               // transition and handles it specially based on the
+               // wait reason.
+               casGToWaiting(gp, _Grunning, reason)
+               forEachPInternal(fn)
+               casgstatus(gp, _Gwaiting, _Grunning)
+       })
+}
+
+// forEachPInternal calls fn(p) for every P p when p reaches a GC safe point.
+// It is the internal implementation of forEachP.
+//
+// The caller must hold worldsema and either must ensure that a GC is not
+// running (otherwise this may deadlock with the GC trying to preempt this P)
+// or it must leave its goroutine in a preemptible state before it switches
+// to the systemstack. Due to these restrictions, prefer forEachP when possible.
 //
 //go:systemstack
-func forEachP(fn func(*p)) {
+func forEachPInternal(fn func(*p)) {
        mp := acquirem()
        pp := getg().m.p.ptr()