diff options
author | Austin Clements <austin@google.com> | 2019-11-02 18:39:17 -0400 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2019-11-06 14:34:46 +0000 |
commit | b82404837d3f2227115f70687d318689535b8a2d (patch) | |
tree | 2bbcfa81762eed6976dedb173352f2133e14337f /src/runtime/export_unix_test.go | |
parent | f891b7c3425621d0ec3771144182507c90a80cff (diff) | |
download | go-b82404837d3f2227115f70687d318689535b8a2d.tar.gz go-b82404837d3f2227115f70687d318689535b8a2d.zip |
runtime: remove write barrier in WaitForSigusr1
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>
Diffstat (limited to 'src/runtime/export_unix_test.go')
-rw-r--r-- | src/runtime/export_unix_test.go | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/src/runtime/export_unix_test.go b/src/runtime/export_unix_test.go index 7af1c1dd54..5e59e406c6 100644 --- a/src/runtime/export_unix_test.go +++ b/src/runtime/export_unix_test.go @@ -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. |