]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: set new m signal mask to program startup mask
authorIan Lance Taylor <iant@golang.org>
Sat, 19 Dec 2015 18:17:10 +0000 (10:17 -0800)
committerIan Lance Taylor <iant@golang.org>
Wed, 6 Jan 2016 23:14:46 +0000 (23:14 +0000)
We were setting the signal mask of a new m to the signal mask of the m
that created it.  That failed when that m happened to be the one created
by ensureSigM, which sets its signal mask to only include the signals
being caught by os/signal.Notify.

Fixes #13164.
Update #9896.

Change-Id: I705c196fe9d11754e10bab9e9b2e7530ecdfa367
Reviewed-on: https://go-review.googlesource.com/18064
Reviewed-by: Russ Cox <rsc@golang.org>
src/runtime/crash_cgo_test.go
src/runtime/proc.go
src/runtime/testdata/testprogcgo/exec.go [new file with mode: 0644]

index 346a80f0aea704de126ea605a3440a209c36f0f9..9422a086205b8b2aacda656b7b2472684d06ce0f 100644 (file)
@@ -121,3 +121,16 @@ func TestCgoDLLImports(t *testing.T) {
                t.Fatalf("expected %q, but got %v", want, got)
        }
 }
+
+func TestCgoExecSignalMask(t *testing.T) {
+       // Test issue 13164.
+       switch runtime.GOOS {
+       case "windows", "plan9":
+               t.Skipf("skipping signal mask test on %s", runtime.GOOS)
+       }
+       got := runTestProg(t, "testprogcgo", "CgoExecSignalMask")
+       want := "OK\n"
+       if got != want {
+               t.Errorf("expected %q, got %v", want, got)
+       }
+}
index 12fba1404c2f6dee02c040ec190b13b23b99814a..fd8e161c1754b9506dfdfdf26ce6b7bfa26fa7ba 100644 (file)
@@ -98,6 +98,9 @@ func main_main()
 // runtimeInitTime is the nanotime() at which the runtime started.
 var runtimeInitTime int64
 
+// Value to use for signal mask for newly created M's.
+var initSigmask sigset
+
 // The main goroutine.
 func main() {
        g := getg()
@@ -430,6 +433,9 @@ func schedinit() {
        mallocinit()
        mcommoninit(_g_.m)
 
+       msigsave(_g_.m)
+       initSigmask = _g_.m.sigmask
+
        goargs()
        goenvs()
        parsedebugvars()
@@ -1480,7 +1486,7 @@ func unlockextra(mp *m) {
 func newm(fn func(), _p_ *p) {
        mp := allocm(_p_, fn)
        mp.nextp.set(_p_)
-       msigsave(mp)
+       mp.sigmask = initSigmask
        if iscgo {
                var ts cgothreadstart
                if _cgo_thread_start == nil {
diff --git a/src/runtime/testdata/testprogcgo/exec.go b/src/runtime/testdata/testprogcgo/exec.go
new file mode 100644 (file)
index 0000000..8dc1d51
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2015 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 !plan9,!windows
+
+package main
+
+/*
+#include <stddef.h>
+#include <signal.h>
+#include <pthread.h>
+
+// Save the signal mask at startup so that we see what it is before
+// the Go runtime starts setting up signals.
+
+static sigset_t mask;
+
+static void init(void) __attribute__ ((constructor));
+
+static void init() {
+       sigemptyset(&mask);
+       pthread_sigmask(SIG_SETMASK, NULL, &mask);
+}
+
+int SIGINTBlocked() {
+       return sigismember(&mask, SIGINT);
+}
+*/
+import "C"
+
+import (
+       "fmt"
+       "os"
+       "os/exec"
+       "os/signal"
+       "sync"
+       "syscall"
+)
+
+func init() {
+       register("CgoExecSignalMask", CgoExecSignalMask)
+}
+
+func CgoExecSignalMask() {
+       if len(os.Args) > 2 && os.Args[2] == "testsigint" {
+               if C.SIGINTBlocked() != 0 {
+                       os.Exit(1)
+               }
+               os.Exit(0)
+       }
+
+       c := make(chan os.Signal, 1)
+       signal.Notify(c, syscall.SIGTERM)
+       go func() {
+               for range c {
+               }
+       }()
+
+       const goCount = 10
+       const execCount = 10
+       var wg sync.WaitGroup
+       wg.Add(goCount*execCount + goCount)
+       for i := 0; i < goCount; i++ {
+               go func() {
+                       defer wg.Done()
+                       for j := 0; j < execCount; j++ {
+                               c2 := make(chan os.Signal, 1)
+                               signal.Notify(c2, syscall.SIGUSR1)
+                               syscall.Kill(os.Getpid(), syscall.SIGTERM)
+                               go func(j int) {
+                                       defer wg.Done()
+                                       cmd := exec.Command(os.Args[0], "CgoExecSignalMask", "testsigint")
+                                       cmd.Stdin = os.Stdin
+                                       cmd.Stdout = os.Stdout
+                                       cmd.Stderr = os.Stderr
+                                       if err := cmd.Run(); err != nil {
+                                               fmt.Printf("iteration %d: %v\n", j, err)
+                                               os.Exit(1)
+                                       }
+                               }(j)
+                               signal.Stop(c2)
+                       }
+               }()
+       }
+       wg.Wait()
+
+       fmt.Println("OK")
+}