aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/export_unix_test.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2019-11-02 18:39:17 -0400
committerIan Lance Taylor <iant@golang.org>2019-11-06 14:34:46 +0000
commitb82404837d3f2227115f70687d318689535b8a2d (patch)
tree2bbcfa81762eed6976dedb173352f2133e14337f /src/runtime/export_unix_test.go
parentf891b7c3425621d0ec3771144182507c90a80cff (diff)
downloadgo-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.go28
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.