]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: remove write barrier in WaitForSigusr1
authorAustin Clements <austin@google.com>
Sat, 2 Nov 2019 22:39:17 +0000 (18:39 -0400)
committerIan Lance Taylor <iant@golang.org>
Wed, 6 Nov 2019 14:34:46 +0000 (14:34 +0000)
WaitForSigusr1 registers a callback to be called on SIGUSR1 directly
from the runtime signal handler. Currently, this callback has a write
barrier in it, which can crash with a nil P if the GC is active and
the signal arrives on an M that doesn't have a P.

Fix this by recording the ID of the M that receives the signal instead
of the M itself, since that's all we needed anyway. To make sure there
are no other problems, this also lifts the callback into a package
function and marks it "go:nowritebarrierrec".

Fixes #35248.

Updates #35276, since in principle a write barrier at exactly the
wrong time while entering the scheduler could cause issues, though I
suspect that bug is unrelated.

Change-Id: I47b4bc73782efbb613785a93e381d8aaf6850826
Reviewed-on: https://go-review.googlesource.com/c/go/+/204620
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/export_unix_test.go

index 7af1c1dd549167d951fc6949e7a31c44402e32a8..5e59e406c687456d2b1720e144e395a4f973c236 100644 (file)
@@ -22,7 +22,7 @@ type M = m
 
 var waitForSigusr1 struct {
        park note
-       mp   *m
+       mID  int64
 }
 
 // WaitForSigusr1 blocks until a SIGUSR1 is received. It calls ready
@@ -38,16 +38,11 @@ func WaitForSigusr1(ready func(mp *M), timeoutNS int64) (int64, int64) {
        unblocksig(_SIGUSR1)
 
        mp := getg().m
-       testSigusr1 = func(gp *g) bool {
-               waitForSigusr1.mp = gp.m
-               notewakeup(&waitForSigusr1.park)
-               return true
-       }
+       testSigusr1 = waitForSigusr1Callback
        ready(mp)
        ok := notetsleepg(&waitForSigusr1.park, timeoutNS)
        noteclear(&waitForSigusr1.park)
-       gotM := waitForSigusr1.mp
-       waitForSigusr1.mp = nil
+       gotM := waitForSigusr1.mID
        testSigusr1 = nil
 
        unlockOSThread()
@@ -55,7 +50,22 @@ func WaitForSigusr1(ready func(mp *M), timeoutNS int64) (int64, int64) {
        if !ok {
                return -1, -1
        }
-       return mp.id, gotM.id
+       return mp.id, gotM
+}
+
+// waitForSigusr1Callback is called from the signal handler during
+// WaitForSigusr1. It must not have write barriers because there may
+// not be a P.
+//
+//go:nowritebarrierrec
+func waitForSigusr1Callback(gp *g) bool {
+       if gp == nil || gp.m == nil {
+               waitForSigusr1.mID = -1
+       } else {
+               waitForSigusr1.mID = gp.m.id
+       }
+       notewakeup(&waitForSigusr1.park)
+       return true
 }
 
 // SendSigusr1 sends SIGUSR1 to mp.