Skip to content

Commit 70c9a81

Browse files
runtime: set new m signal mask to program startup mask
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 <[email protected]>
1 parent a7cad52 commit 70c9a81

File tree

3 files changed

+109
-1
lines changed

3 files changed

+109
-1
lines changed

src/runtime/crash_cgo_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,16 @@ func TestCgoDLLImports(t *testing.T) {
121121
t.Fatalf("expected %q, but got %v", want, got)
122122
}
123123
}
124+
125+
func TestCgoExecSignalMask(t *testing.T) {
126+
// Test issue 13164.
127+
switch runtime.GOOS {
128+
case "windows", "plan9":
129+
t.Skipf("skipping signal mask test on %s", runtime.GOOS)
130+
}
131+
got := runTestProg(t, "testprogcgo", "CgoExecSignalMask")
132+
want := "OK\n"
133+
if got != want {
134+
t.Errorf("expected %q, got %v", want, got)
135+
}
136+
}

src/runtime/proc.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ func main_main()
9898
// runtimeInitTime is the nanotime() at which the runtime started.
9999
var runtimeInitTime int64
100100

101+
// Value to use for signal mask for newly created M's.
102+
var initSigmask sigset
103+
101104
// The main goroutine.
102105
func main() {
103106
g := getg()
@@ -430,6 +433,9 @@ func schedinit() {
430433
mallocinit()
431434
mcommoninit(_g_.m)
432435

436+
msigsave(_g_.m)
437+
initSigmask = _g_.m.sigmask
438+
433439
goargs()
434440
goenvs()
435441
parsedebugvars()
@@ -1480,7 +1486,7 @@ func unlockextra(mp *m) {
14801486
func newm(fn func(), _p_ *p) {
14811487
mp := allocm(_p_, fn)
14821488
mp.nextp.set(_p_)
1483-
msigsave(mp)
1489+
mp.sigmask = initSigmask
14841490
if iscgo {
14851491
var ts cgothreadstart
14861492
if _cgo_thread_start == nil {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2015 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build !plan9,!windows
6+
7+
package main
8+
9+
/*
10+
#include <stddef.h>
11+
#include <signal.h>
12+
#include <pthread.h>
13+
14+
// Save the signal mask at startup so that we see what it is before
15+
// the Go runtime starts setting up signals.
16+
17+
static sigset_t mask;
18+
19+
static void init(void) __attribute__ ((constructor));
20+
21+
static void init() {
22+
sigemptyset(&mask);
23+
pthread_sigmask(SIG_SETMASK, NULL, &mask);
24+
}
25+
26+
int SIGINTBlocked() {
27+
return sigismember(&mask, SIGINT);
28+
}
29+
*/
30+
import "C"
31+
32+
import (
33+
"fmt"
34+
"os"
35+
"os/exec"
36+
"os/signal"
37+
"sync"
38+
"syscall"
39+
)
40+
41+
func init() {
42+
register("CgoExecSignalMask", CgoExecSignalMask)
43+
}
44+
45+
func CgoExecSignalMask() {
46+
if len(os.Args) > 2 && os.Args[2] == "testsigint" {
47+
if C.SIGINTBlocked() != 0 {
48+
os.Exit(1)
49+
}
50+
os.Exit(0)
51+
}
52+
53+
c := make(chan os.Signal, 1)
54+
signal.Notify(c, syscall.SIGTERM)
55+
go func() {
56+
for range c {
57+
}
58+
}()
59+
60+
const goCount = 10
61+
const execCount = 10
62+
var wg sync.WaitGroup
63+
wg.Add(goCount*execCount + goCount)
64+
for i := 0; i < goCount; i++ {
65+
go func() {
66+
defer wg.Done()
67+
for j := 0; j < execCount; j++ {
68+
c2 := make(chan os.Signal, 1)
69+
signal.Notify(c2, syscall.SIGUSR1)
70+
syscall.Kill(os.Getpid(), syscall.SIGTERM)
71+
go func(j int) {
72+
defer wg.Done()
73+
cmd := exec.Command(os.Args[0], "CgoExecSignalMask", "testsigint")
74+
cmd.Stdin = os.Stdin
75+
cmd.Stdout = os.Stdout
76+
cmd.Stderr = os.Stderr
77+
if err := cmd.Run(); err != nil {
78+
fmt.Printf("iteration %d: %v\n", j, err)
79+
os.Exit(1)
80+
}
81+
}(j)
82+
signal.Stop(c2)
83+
}
84+
}()
85+
}
86+
wg.Wait()
87+
88+
fmt.Println("OK")
89+
}

0 commit comments

Comments
 (0)