Commit 70c9a818 authored by Ian Lance Taylor's avatar Ian Lance Taylor

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/18064Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
parent a7cad52e
...@@ -121,3 +121,16 @@ func TestCgoDLLImports(t *testing.T) { ...@@ -121,3 +121,16 @@ func TestCgoDLLImports(t *testing.T) {
t.Fatalf("expected %q, but got %v", want, got) 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)
}
}
...@@ -98,6 +98,9 @@ func main_main() ...@@ -98,6 +98,9 @@ func main_main()
// runtimeInitTime is the nanotime() at which the runtime started. // runtimeInitTime is the nanotime() at which the runtime started.
var runtimeInitTime int64 var runtimeInitTime int64
// Value to use for signal mask for newly created M's.
var initSigmask sigset
// The main goroutine. // The main goroutine.
func main() { func main() {
g := getg() g := getg()
...@@ -430,6 +433,9 @@ func schedinit() { ...@@ -430,6 +433,9 @@ func schedinit() {
mallocinit() mallocinit()
mcommoninit(_g_.m) mcommoninit(_g_.m)
msigsave(_g_.m)
initSigmask = _g_.m.sigmask
goargs() goargs()
goenvs() goenvs()
parsedebugvars() parsedebugvars()
...@@ -1480,7 +1486,7 @@ func unlockextra(mp *m) { ...@@ -1480,7 +1486,7 @@ func unlockextra(mp *m) {
func newm(fn func(), _p_ *p) { func newm(fn func(), _p_ *p) {
mp := allocm(_p_, fn) mp := allocm(_p_, fn)
mp.nextp.set(_p_) mp.nextp.set(_p_)
msigsave(mp) mp.sigmask = initSigmask
if iscgo { if iscgo {
var ts cgothreadstart var ts cgothreadstart
if _cgo_thread_start == nil { if _cgo_thread_start == nil {
......
// 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")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment