]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add test for signalM
authorAustin Clements <austin@google.com>
Tue, 15 Oct 2019 00:10:48 +0000 (20:10 -0400)
committerAustin Clements <austin@google.com>
Sat, 26 Oct 2019 02:52:32 +0000 (02:52 +0000)
For #10958, #24543.

Change-Id: Ib009a83fe02bc623894f4908fe8f6b266382ba95
Reviewed-on: https://go-review.googlesource.com/c/go/+/201404
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/runtime/export_unix_test.go
src/runtime/preemptm_test.go [new file with mode: 0644]
src/runtime/signal_unix.go

index eecdfb7eb2216e4dfd85860062587badfa71587e..3f8bff619dfcf36c90835bc536f839529857baf6 100644 (file)
@@ -17,3 +17,42 @@ func Sigisblocked(i int) bool {
        sigprocmask(_SIG_SETMASK, nil, &sigmask)
        return sigismember(&sigmask, i)
 }
+
+type M = m
+
+var waitForSigusr1 struct {
+       park note
+       mp   *m
+}
+
+// WaitForSigusr1 blocks until a SIGUSR1 is received. It calls ready
+// when it is set up to receive SIGUSR1. The ready function should
+// cause a SIGUSR1 to be sent.
+//
+// Once SIGUSR1 is received, it returns the ID of the current M and
+// the ID of the M the SIGUSR1 was received on. If no SIGUSR1 is
+// received for timeoutNS nanoseconds, it returns -1.
+func WaitForSigusr1(ready func(mp *M), timeoutNS int64) (int64, int64) {
+       mp := getg().m
+       testSigusr1 = func(gp *g) bool {
+               waitForSigusr1.mp = gp.m
+               notewakeup(&waitForSigusr1.park)
+               return true
+       }
+       ready(mp)
+       ok := notetsleepg(&waitForSigusr1.park, timeoutNS)
+       noteclear(&waitForSigusr1.park)
+       gotM := waitForSigusr1.mp
+       waitForSigusr1.mp = nil
+       testSigusr1 = nil
+
+       if !ok {
+               return -1, -1
+       }
+       return mp.id, gotM.id
+}
+
+// SendSigusr1 sends SIGUSR1 to mp.
+func SendSigusr1(mp *M) {
+       signalM(mp, _SIGUSR1)
+}
diff --git a/src/runtime/preemptm_test.go b/src/runtime/preemptm_test.go
new file mode 100644 (file)
index 0000000..70c6ad5
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime_test
+
+import (
+       "runtime"
+       "sync"
+       "testing"
+)
+
+func TestPreemptM(t *testing.T) {
+       var want, got int64
+       var wg sync.WaitGroup
+       ready := make(chan *runtime.M)
+       wg.Add(1)
+       go func() {
+               runtime.LockOSThread()
+               want, got = runtime.WaitForSigusr1(func(mp *runtime.M) {
+                       ready <- mp
+               }, 1e9)
+               runtime.UnlockOSThread()
+               wg.Done()
+       }()
+       runtime.SendSigusr1(<-ready)
+       wg.Wait()
+       if got == -1 {
+               t.Fatal("preemptM signal not received")
+       } else if want != got {
+               t.Fatalf("signal sent to M %d, but received on M %d", want, got)
+       }
+}
index cea65282e0a4e32dc4a17d21403a9f3faaf2b7e1..27552c9f335ee4b015bb0f71f9a9405a29d63691 100644 (file)
@@ -412,10 +412,11 @@ func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
 // GOTRACEBACK=crash when a signal is received.
 var crashing int32
 
-// testSigtrap is used by the runtime tests. If non-nil, it is called
-// on SIGTRAP. If it returns true, the normal behavior on SIGTRAP is
-// suppressed.
+// testSigtrap and testSigusr1 are used by the runtime tests. If
+// non-nil, it is called on SIGTRAP/SIGUSR1. If it returns true, the
+// normal behavior on this signal is suppressed.
 var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
+var testSigusr1 func(gp *g) bool
 
 // sighandler is invoked when a signal occurs. The global g will be
 // set to a gsignal goroutine and we will be running on the alternate
@@ -441,6 +442,10 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
                return
        }
 
+       if sig == _SIGUSR1 && testSigusr1 != nil && testSigusr1(gp) {
+               return
+       }
+
        flags := int32(_SigThrow)
        if sig < uint32(len(sigtable)) {
                flags = sigtable[sig].flags