]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: hold traceAcquire across casgstatus in injectglist
authorMichael Anthony Knyszek <mknyszek@google.com>
Mon, 23 Dec 2024 17:21:07 +0000 (17:21 +0000)
committerMichael Knyszek <mknyszek@google.com>
Wed, 8 Jan 2025 17:25:53 +0000 (09:25 -0800)
Currently injectglist emits all the trace events before actually calling
casgstatus on each goroutine. This is a problem, since tracing can
observe an inconsistent state (gstatus does not match tracer's 'emitted
an event' state).

This change fixes the problem by having injectglist do what every other
scheduler function does, and that's wrap each call to casgstatus in
traceAcquire/traceRelease.

Fixes #70883.

Change-Id: I857e96cec01688013597e8efc0c4c3d0b72d3a70
Reviewed-on: https://go-review.googlesource.com/c/go/+/638558
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/runtime/proc.go

index 636296020048324b6ba24b6a9f0e94ae078ee07d..e9873e54cd5709494f9d488982ebd311e574d283 100644 (file)
@@ -3894,23 +3894,23 @@ func injectglist(glist *gList) {
        if glist.empty() {
                return
        }
-       trace := traceAcquire()
-       if trace.ok() {
-               for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() {
-                       trace.GoUnpark(gp, 0)
-               }
-               traceRelease(trace)
-       }
 
        // Mark all the goroutines as runnable before we put them
        // on the run queues.
        head := glist.head.ptr()
        var tail *g
        qsize := 0
+       trace := traceAcquire()
        for gp := head; gp != nil; gp = gp.schedlink.ptr() {
                tail = gp
                qsize++
                casgstatus(gp, _Gwaiting, _Grunnable)
+               if trace.ok() {
+                       trace.GoUnpark(gp, 0)
+               }
+       }
+       if trace.ok() {
+               traceRelease(trace)
        }
 
        // Turn the gList into a gQueue.