Commit 84cfba17 authored by Elias Naur's avatar Elias Naur Committed by Ian Lance Taylor

runtime: don't always unblock all signals

Ian proposed an improved way of handling signals masks in Go, motivated
by a problem where the Android java runtime expects certain signals to
be blocked for all JVM threads. Discussion here

https://groups.google.com/forum/#!topic/golang-dev/_TSCkQHJt6g

Ian's text is used in the following:

A Go program always needs to have the synchronous signals enabled.
These are the signals for which _SigPanic is set in sigtable, namely
SIGSEGV, SIGBUS, SIGFPE.

A Go program that uses the os/signal package, and calls signal.Notify,
needs to have at least one thread which is not blocking that signal,
but it doesn't matter much which one.

Unix programs do not change signal mask across execve.  They inherit
signal masks across fork.  The shell uses this fact to some extent;
for example, the job control signals (SIGTTIN, SIGTTOU, SIGTSTP) are
blocked for commands run due to backquote quoting or $().

Our current position on signal masks was not thought out.  We wandered
into step by step, e.g., http://golang.org/cl/7323067 .

This CL does the following:

Introduce a new platform hook, msigsave, that saves the signal mask of
the current thread to m.sigsave.

Call msigsave from needm and newm.

In minit grab set up the signal mask from m.sigsave and unblock the
essential synchronous signals, and SIGILL, SIGTRAP, SIGPROF, SIGSTKFLT
(for systems that have it).

In unminit, restore the signal mask from m.sigsave.

The first time that os/signal.Notify is called, start a new thread whose
only purpose is to update its signal mask to make sure signals for
signal.Notify are unblocked on at least one thread.

The effect on Go programs will be that if they are invoked with some
non-synchronous signals blocked, those signals will normally be
ignored.  Previously, those signals would mostly be ignored.  A change
in behaviour will occur for programs started with any of these signals
blocked, if they receive the signal: SIGHUP, SIGINT, SIGQUIT, SIGABRT,
SIGTERM.  Previously those signals would always cause a crash (unless
using the os/signal package); with this change, they will be ignored
if the program is started with the signal blocked (and does not use
the os/signal package).

./all.bash completes successfully on linux/amd64.

OpenBSD is missing the implementation.

Change-Id: I188098ba7eb85eae4c14861269cc466f2aa40e8c
Reviewed-on: https://go-review.googlesource.com/10173Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 994b2d46
...@@ -10,3 +10,4 @@ func TestSetgid(t *testing.T) { testSetgid(t) } ...@@ -10,3 +10,4 @@ func TestSetgid(t *testing.T) { testSetgid(t) }
func Test6997(t *testing.T) { test6997(t) } func Test6997(t *testing.T) { test6997(t) }
func TestBuildID(t *testing.T) { testBuildID(t) } func TestBuildID(t *testing.T) { testBuildID(t) }
func Test9400(t *testing.T) { test9400(t) } func Test9400(t *testing.T) { test9400(t) }
func TestSigProcMask(t *testing.T) { testSigProcMask(t) }
// 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.
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
extern void IntoGoAndBack();
int CheckBlocked() {
sigset_t mask;
sigprocmask(SIG_BLOCK, NULL, &mask);
return sigismember(&mask, SIGIO);
}
static void* sigthreadfunc(void* unused) {
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGIO);
sigprocmask(SIG_BLOCK, &mask, NULL);
IntoGoAndBack();
}
int RunSigThread() {
pthread_t thread;
int r;
r = pthread_create(&thread, NULL, &sigthreadfunc, NULL);
if (r != 0)
return r;
return pthread_join(thread, NULL);
}
// 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.
package cgotest
/*
#cgo CFLAGS: -pthread
#cgo LDFLAGS: -pthread
extern int RunSigThread();
extern int CheckBlocked();
*/
import "C"
import (
"os"
"os/signal"
"syscall"
"testing"
)
var blocked bool
//export IntoGoAndBack
func IntoGoAndBack() {
// Verify that SIGIO stays blocked on the C thread
// even when unblocked for signal.Notify().
signal.Notify(make(chan os.Signal), syscall.SIGIO)
blocked = C.CheckBlocked() != 0
}
func testSigProcMask(t *testing.T) {
if r := C.RunSigThread(); r != 0 {
t.Error("pthread_create/pthread_join failed")
}
if !blocked {
t.Error("Go runtime unblocked SIGIO")
}
}
...@@ -8,7 +8,6 @@ import "unsafe" ...@@ -8,7 +8,6 @@ import "unsafe"
//extern SigTabTT runtime·sigtab[]; //extern SigTabTT runtime·sigtab[];
var sigset_none = uint32(0)
var sigset_all = ^uint32(0) var sigset_all = ^uint32(0)
func unimplemented(name string) { func unimplemented(name string) {
...@@ -126,17 +125,36 @@ func mpreinit(mp *m) { ...@@ -126,17 +125,36 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp mp.gsignal.m = mp
} }
func msigsave(mp *m) {
smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
sigprocmask(_SIG_SETMASK, nil, smask)
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
// Initialize signal handling. // Initialize signal handling.
_g_ := getg() _g_ := getg()
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
sigprocmask(_SIG_SETMASK, &sigset_none, nil)
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask &^= 1 << (uint32(i) - 1)
}
}
sigprocmask(_SIG_SETMASK, &nmask, nil)
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
func unminit() { func unminit() {
_g_ := getg()
smask := (*uint32)(unsafe.Pointer(&_g_.m.sigmask))
sigprocmask(_SIG_SETMASK, smask, nil)
signalstack(nil, 0) signalstack(nil, 0)
} }
...@@ -447,6 +465,6 @@ func signalstack(p *byte, n int32) { ...@@ -447,6 +465,6 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, &sigset_none, nil) sigprocmask(_SIG_SETMASK, &m[0], nil)
} }
...@@ -12,7 +12,6 @@ const ( ...@@ -12,7 +12,6 @@ const (
_HW_NCPU = 3 _HW_NCPU = 3
) )
var sigset_none = sigset{}
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
func getncpu() int32 { func getncpu() int32 {
...@@ -120,6 +119,14 @@ func mpreinit(mp *m) { ...@@ -120,6 +119,14 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp mp.gsignal.m = mp
} }
func msigsave(mp *m) {
smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
sigprocmask(nil, smask)
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
...@@ -130,11 +137,22 @@ func minit() { ...@@ -130,11 +137,22 @@ func minit() {
// Initialize signal handling // Initialize signal handling
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
sigprocmask(&sigset_none, nil)
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
sigprocmask(&nmask, nil)
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
func unminit() { func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
sigprocmask(smask, nil)
signalstack(nil, 0) signalstack(nil, 0)
} }
...@@ -215,6 +233,8 @@ func signalstack(p *byte, n int32) { ...@@ -215,6 +233,8 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m sigmask) {
sigprocmask(&sigset_none, nil) var mask sigset
copy(mask.__bits[:], m[:])
sigprocmask(&mask, nil)
} }
...@@ -12,7 +12,6 @@ const ( ...@@ -12,7 +12,6 @@ const (
_HW_NCPU = 3 _HW_NCPU = 3
) )
var sigset_none = sigset{}
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
func getncpu() int32 { func getncpu() int32 {
...@@ -119,6 +118,14 @@ func mpreinit(mp *m) { ...@@ -119,6 +118,14 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp mp.gsignal.m = mp
} }
func msigsave(mp *m) {
smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
sigprocmask(nil, smask)
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
...@@ -132,11 +139,22 @@ func minit() { ...@@ -132,11 +139,22 @@ func minit() {
// Initialize signal handling. // Initialize signal handling.
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
sigprocmask(&sigset_none, nil)
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
sigprocmask(&nmask, nil)
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
func unminit() { func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
sigprocmask(smask, nil)
signalstack(nil, 0) signalstack(nil, 0)
} }
...@@ -217,6 +235,8 @@ func signalstack(p *byte, n int32) { ...@@ -217,6 +235,8 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
sigprocmask(&sigset_none, nil) var mask sigset
copy(mask.__bits[:], m[:])
sigprocmask(&mask, nil)
} }
...@@ -6,7 +6,6 @@ package runtime ...@@ -6,7 +6,6 @@ package runtime
import "unsafe" import "unsafe"
var sigset_none sigset
var sigset_all sigset = sigset{^uint32(0), ^uint32(0)} var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}
// Linux futex. // Linux futex.
...@@ -190,17 +189,36 @@ func mpreinit(mp *m) { ...@@ -190,17 +189,36 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp mp.gsignal.m = mp
} }
func msigsave(mp *m) {
smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
// Initialize signal handling. // Initialize signal handling.
_g_ := getg() _g_ := getg()
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
func unminit() { func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
signalstack(nil, 0) signalstack(nil, 0)
} }
...@@ -304,6 +322,8 @@ func signalstack(p *byte, n int32) { ...@@ -304,6 +322,8 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m sigmask) {
rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none))) var mask sigset
copy(mask[:], m[:])
rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
} }
...@@ -15,6 +15,9 @@ func mpreinit(mp *m) { ...@@ -15,6 +15,9 @@ func mpreinit(mp *m) {
func sigtramp() func sigtramp()
func msigsave(mp *m) {
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
......
...@@ -17,7 +17,6 @@ const ( ...@@ -17,7 +17,6 @@ const (
_CLOCK_MONOTONIC = 3 _CLOCK_MONOTONIC = 3
) )
var sigset_none = sigset{}
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
// From NetBSD's <sys/sysctl.h> // From NetBSD's <sys/sysctl.h>
...@@ -139,6 +138,14 @@ func mpreinit(mp *m) { ...@@ -139,6 +138,14 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp mp.gsignal.m = mp
} }
func msigsave(mp *m) {
smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
sigprocmask(_SIG_SETMASK, nil, smask)
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
...@@ -147,11 +154,23 @@ func minit() { ...@@ -147,11 +154,23 @@ func minit() {
// Initialize signal handling // Initialize signal handling
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
sigprocmask(_SIG_SETMASK, &sigset_none, nil)
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
sigprocmask(_SIG_SETMASK, &nmask, nil)
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
func unminit() { func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
sigprocmask(_SIG_SETMASK, smask, nil)
signalstack(nil, 0) signalstack(nil, 0)
} }
...@@ -206,6 +225,8 @@ func signalstack(p *byte, n int32) { ...@@ -206,6 +225,8 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, &sigset_none, nil) var mask sigset
copy(mask.__bits[:], m[:])
sigprocmask(_SIG_SETMASK, &mask, nil)
} }
...@@ -148,6 +148,9 @@ func mpreinit(mp *m) { ...@@ -148,6 +148,9 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp mp.gsignal.m = mp
} }
func msigsave(mp *m) {
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
...@@ -217,6 +220,6 @@ func signalstack(p *byte, n int32) { ...@@ -217,6 +220,6 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, sigset_none) sigprocmask(_SIG_SETMASK, m[0])
} }
...@@ -18,6 +18,9 @@ func mpreinit(mp *m) { ...@@ -18,6 +18,9 @@ func mpreinit(mp *m) {
mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan)) mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan))
} }
func msigsave(mp *m) {
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
......
...@@ -292,6 +292,9 @@ func newosproc(mp *m, stk unsafe.Pointer) { ...@@ -292,6 +292,9 @@ func newosproc(mp *m, stk unsafe.Pointer) {
func mpreinit(mp *m) { func mpreinit(mp *m) {
} }
func msigsave(mp *m) {
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
......
...@@ -114,7 +114,6 @@ var ( ...@@ -114,7 +114,6 @@ var (
libc_write libcFunc libc_write libcFunc
) )
var sigset_none = sigset{}
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
func getncpu() int32 { func getncpu() int32 {
...@@ -190,6 +189,14 @@ func mpreinit(mp *m) { ...@@ -190,6 +189,14 @@ func mpreinit(mp *m) {
func miniterrno() func miniterrno()
func msigsave(mp *m) {
smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
sigprocmask(_SIG_SETMASK, nil, smask)
}
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory. // Called on the new thread, can not allocate memory.
func minit() { func minit() {
...@@ -197,11 +204,23 @@ func minit() { ...@@ -197,11 +204,23 @@ func minit() {
asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno)) asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
// Initialize signal handling // Initialize signal handling
signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
sigprocmask(_SIG_SETMASK, &sigset_none, nil)
// restore signal mask from m.sigmask and unblock essential signals
nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
nmask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
sigprocmask(_SIG_SETMASK, &nmask, nil)
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
func unminit() { func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
sigprocmask(_SIG_SETMASK, smask, nil)
signalstack(nil, 0) signalstack(nil, 0)
} }
...@@ -278,8 +297,10 @@ func signalstack(p *byte, n int32) { ...@@ -278,8 +297,10 @@ func signalstack(p *byte, n int32) {
sigaltstack(&st, nil) sigaltstack(&st, nil)
} }
func unblocksignals() { func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, &sigset_none, nil) var mask sigset
copy(mask.__sigbits[:], m[:])
sigprocmask(_SIG_SETMASK, &mask, nil)
} }
//go:nosplit //go:nosplit
......
...@@ -944,6 +944,7 @@ func needm(x byte) { ...@@ -944,6 +944,7 @@ func needm(x byte) {
_g_.stack.lo = uintptr(noescape(unsafe.Pointer(&x))) - 32*1024 _g_.stack.lo = uintptr(noescape(unsafe.Pointer(&x))) - 32*1024
_g_.stackguard0 = _g_.stack.lo + _StackGuard _g_.stackguard0 = _g_.stack.lo + _StackGuard
msigsave(mp)
// Initialize this thread to use the m. // Initialize this thread to use the m.
asminit() asminit()
minit() minit()
...@@ -1071,6 +1072,7 @@ func unlockextra(mp *m) { ...@@ -1071,6 +1072,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)
if iscgo { if iscgo {
var ts cgothreadstart var ts cgothreadstart
if _cgo_thread_start == nil { if _cgo_thread_start == nil {
......
...@@ -266,6 +266,7 @@ type m struct { ...@@ -266,6 +266,7 @@ type m struct {
// Fields not known to debuggers. // Fields not known to debuggers.
procid uint64 // for debuggers, but offset not hard-coded procid uint64 // for debuggers, but offset not hard-coded
gsignal *g // signal-handling g gsignal *g // signal-handling g
sigmask [4]uintptr // storage for saved signal mask
tls [4]uintptr // thread-local storage (for x86 extern register) tls [4]uintptr // thread-local storage (for x86 extern register)
mstartfn func() mstartfn func()
curg *g // current running goroutine curg *g // current running goroutine
...@@ -469,15 +470,16 @@ type sigtabtt struct { ...@@ -469,15 +470,16 @@ type sigtabtt struct {
} }
const ( const (
_SigNotify = 1 << 0 // let signal.Notify have signal, even if from kernel _SigNotify = 1 << iota // let signal.Notify have signal, even if from kernel
_SigKill = 1 << 1 // if signal.Notify doesn't take it, exit quietly _SigKill // if signal.Notify doesn't take it, exit quietly
_SigThrow = 1 << 2 // if signal.Notify doesn't take it, exit loudly _SigThrow // if signal.Notify doesn't take it, exit loudly
_SigPanic = 1 << 3 // if the signal is from the kernel, panic _SigPanic // if the signal is from the kernel, panic
_SigDefault = 1 << 4 // if the signal isn't explicitly requested, don't monitor it _SigDefault // if the signal isn't explicitly requested, don't monitor it
_SigHandling = 1 << 5 // our signal handler is registered _SigHandling // our signal handler is registered
_SigIgnored = 1 << 6 // the signal was ignored before we registered for it _SigIgnored // the signal was ignored before we registered for it
_SigGoExit = 1 << 7 // cause all runtime procs to exit (only used on Plan 9). _SigGoExit // cause all runtime procs to exit (only used on Plan 9).
_SigSetStack = 1 << 8 // add SA_ONSTACK to libc handler _SigSetStack // add SA_ONSTACK to libc handler
_SigUnblock // unblocked in minit
) )
// Layout of in-memory per-function information prepared by linker // Layout of in-memory per-function information prepared by linker
......
...@@ -19,6 +19,19 @@ const ( ...@@ -19,6 +19,19 @@ const (
// Signal forwarding is currently available only on Linux. // Signal forwarding is currently available only on Linux.
var fwdSig [_NSIG]uintptr var fwdSig [_NSIG]uintptr
// sigmask represents a general signal mask compatible with the GOOS
// specific sigset types: the signal numbered x is represented by bit x-1
// to match the representation expected by sigprocmask.
type sigmask [(_NSIG + 31) / 32]uint32
// channels for synchronizing signal mask updates with the signal mask
// thread
var (
disableSigChan chan uint32
enableSigChan chan uint32
maskUpdatedChan chan struct{}
)
func initsig() { func initsig() {
// _NSIG is the number of signals on this operating system. // _NSIG is the number of signals on this operating system.
// sigtable should describe what to do for all the possible signals. // sigtable should describe what to do for all the possible signals.
...@@ -61,13 +74,18 @@ func sigenable(sig uint32) { ...@@ -61,13 +74,18 @@ func sigenable(sig uint32) {
} }
t := &sigtable[sig] t := &sigtable[sig]
if t.flags&_SigNotify != 0 && t.flags&_SigHandling == 0 { if t.flags&_SigNotify != 0 {
ensureSigM()
enableSigChan <- sig
<-maskUpdatedChan
if t.flags&_SigHandling == 0 {
t.flags |= _SigHandling t.flags |= _SigHandling
if getsig(int32(sig)) == _SIG_IGN { if getsig(int32(sig)) == _SIG_IGN {
t.flags |= _SigIgnored t.flags |= _SigIgnored
} }
setsig(int32(sig), funcPC(sighandler), true) setsig(int32(sig), funcPC(sighandler), true)
} }
}
} }
func sigdisable(sig uint32) { func sigdisable(sig uint32) {
...@@ -76,7 +94,11 @@ func sigdisable(sig uint32) { ...@@ -76,7 +94,11 @@ func sigdisable(sig uint32) {
} }
t := &sigtable[sig] t := &sigtable[sig]
if t.flags&_SigNotify != 0 && t.flags&_SigHandling != 0 { if t.flags&_SigNotify != 0 {
ensureSigM()
disableSigChan <- sig
<-maskUpdatedChan
if t.flags&_SigHandling != 0 {
t.flags &^= _SigHandling t.flags &^= _SigHandling
if t.flags&_SigIgnored != 0 { if t.flags&_SigIgnored != 0 {
setsig(int32(sig), _SIG_IGN, true) setsig(int32(sig), _SIG_IGN, true)
...@@ -84,6 +106,7 @@ func sigdisable(sig uint32) { ...@@ -84,6 +106,7 @@ func sigdisable(sig uint32) {
setsig(int32(sig), _SIG_DFL, true) setsig(int32(sig), _SIG_DFL, true)
} }
} }
}
} }
func sigignore(sig uint32) { func sigignore(sig uint32) {
...@@ -130,7 +153,52 @@ func crash() { ...@@ -130,7 +153,52 @@ func crash() {
} }
} }
unblocksignals() updatesigmask(sigmask{})
setsig(_SIGABRT, _SIG_DFL, false) setsig(_SIGABRT, _SIG_DFL, false)
raise(_SIGABRT) raise(_SIGABRT)
} }
// createSigM starts one global, sleeping thread to make sure at least one thread
// is available to catch signals enabled for os/signal.
func ensureSigM() {
if maskUpdatedChan != nil {
return
}
maskUpdatedChan = make(chan struct{})
disableSigChan = make(chan uint32)
enableSigChan = make(chan uint32)
go func() {
// Signal masks are per-thread, so make sure this goroutine stays on one
// thread.
LockOSThread()
defer UnlockOSThread()
// The sigBlocked mask contains the signals not active for os/signal,
// initially all signals except the essential. When signal.Notify()/Stop is called,
// sigenable/sigdisable in turn notify this thread to update its signal
// mask accordingly.
var sigBlocked sigmask
for i := range sigBlocked {
sigBlocked[i] = ^uint32(0)
}
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
updatesigmask(sigBlocked)
for {
select {
case sig := <-enableSigChan:
if b := sig - 1; b >= 0 {
sigBlocked[b/32] &^= (1 << (b & 31))
}
case sig := <-disableSigChan:
if b := sig - 1; b >= 0 {
sigBlocked[b/32] |= (1 << (b & 31))
}
}
updatesigmask(sigBlocked)
maskUpdatedChan <- struct{}{}
}
}()
}
...@@ -16,14 +16,14 @@ var sigtable = [...]sigTabT{ ...@@ -16,14 +16,14 @@ var sigtable = [...]sigTabT{
/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
/* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
/* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
/* 9 */ {0, "SIGKILL: kill"}, /* 9 */ {0, "SIGKILL: kill"},
/* 10 */ {_SigPanic, "SIGBUS: bus error"}, /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
/* 12 */ {_SigThrow, "SIGSYS: bad system call"}, /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
/* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
...@@ -32,14 +32,14 @@ var sigtable = [...]sigTabT{ ...@@ -32,14 +32,14 @@ var sigtable = [...]sigTabT{
/* 17 */ {0, "SIGSTOP: stop"}, /* 17 */ {0, "SIGSTOP: stop"},
/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
/* 19 */ {0, "SIGCONT: continue after stop"}, /* 19 */ {0, "SIGCONT: continue after stop"},
/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, /* 20 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
/* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, /* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
/* 28 */ {_SigNotify, "SIGWINCH: window size change"}, /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
......
...@@ -16,20 +16,20 @@ var sigtable = [...]sigTabT{ ...@@ -16,20 +16,20 @@ var sigtable = [...]sigTabT{
/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
/* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
/* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
/* 7 */ {_SigPanic, "SIGBUS: bus error"}, /* 7 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
/* 9 */ {0, "SIGKILL: kill"}, /* 9 */ {0, "SIGKILL: kill"},
/* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, /* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
/* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, /* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
/* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
/* 16 */ {_SigThrow, "SIGSTKFLT: stack fault"}, /* 16 */ {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"},
/* 17 */ {_SigNotify, "SIGCHLD: child status has changed"}, /* 17 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
/* 18 */ {0, "SIGCONT: continue"}, /* 18 */ {0, "SIGCONT: continue"},
/* 19 */ {0, "SIGSTOP: stop, unblockable"}, /* 19 */ {0, "SIGSTOP: stop, unblockable"},
/* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, /* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
...@@ -39,7 +39,7 @@ var sigtable = [...]sigTabT{ ...@@ -39,7 +39,7 @@ var sigtable = [...]sigTabT{
/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, /* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
/* 28 */ {_SigNotify, "SIGWINCH: window size change"}, /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
/* 29 */ {_SigNotify, "SIGIO: i/o now possible"}, /* 29 */ {_SigNotify, "SIGIO: i/o now possible"},
/* 30 */ {_SigNotify, "SIGPWR: power failure restart"}, /* 30 */ {_SigNotify, "SIGPWR: power failure restart"},
......
...@@ -14,14 +14,14 @@ var sigtable = [...]sigTabT{ ...@@ -14,14 +14,14 @@ var sigtable = [...]sigTabT{
/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
/* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
/* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
/* 9 */ {0, "SIGKILL: kill"}, /* 9 */ {0, "SIGKILL: kill"},
/* 10 */ {_SigPanic, "SIGBUS: bus error"}, /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
/* 12 */ {_SigThrow, "SIGSYS: bad system call"}, /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
/* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
...@@ -30,14 +30,14 @@ var sigtable = [...]sigTabT{ ...@@ -30,14 +30,14 @@ var sigtable = [...]sigTabT{
/* 17 */ {0, "SIGSTOP: stop"}, /* 17 */ {0, "SIGSTOP: stop"},
/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
/* 19 */ {0, "SIGCONT: continue after stop"}, /* 19 */ {0, "SIGCONT: continue after stop"},
/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, /* 20 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
/* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, /* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, /* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
/* 28 */ {_SigNotify, "SIGWINCH: window size change"}, /* 28 */ {_SigNotify, "SIGWINCH: window size change"},
/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
......
...@@ -14,21 +14,21 @@ var sigtable = [...]sigTabT{ ...@@ -14,21 +14,21 @@ var sigtable = [...]sigTabT{
/* 1 */ {_SigNotify + _SigKill, "SIGHUP: hangup"}, /* 1 */ {_SigNotify + _SigKill, "SIGHUP: hangup"},
/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt (rubout)"}, /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt (rubout)"},
/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit (ASCII FS)"}, /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit (ASCII FS)"},
/* 4 */ {_SigThrow, "SIGILL: illegal instruction (not reset when caught)"}, /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction (not reset when caught)"},
/* 5 */ {_SigThrow, "SIGTRAP: trace trap (not reset when caught)"}, /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap (not reset when caught)"},
/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: used by abort, replace SIGIOT in the future"}, /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: used by abort, replace SIGIOT in the future"},
/* 7 */ {_SigThrow, "SIGEMT: EMT instruction"}, /* 7 */ {_SigThrow, "SIGEMT: EMT instruction"},
/* 8 */ {_SigPanic, "SIGFPE: floating point exception"}, /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating point exception"},
/* 9 */ {0, "SIGKILL: kill (cannot be caught or ignored)"}, /* 9 */ {0, "SIGKILL: kill (cannot be caught or ignored)"},
/* 10 */ {_SigPanic, "SIGBUS: bus error"}, /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
/* 12 */ {_SigThrow, "SIGSYS: bad argument to system call"}, /* 12 */ {_SigThrow, "SIGSYS: bad argument to system call"},
/* 13 */ {_SigNotify, "SIGPIPE: write on a pipe with no one to read it"}, /* 13 */ {_SigNotify, "SIGPIPE: write on a pipe with no one to read it"},
/* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
/* 15 */ {_SigNotify + _SigKill, "SIGTERM: software termination signal from kill"}, /* 15 */ {_SigNotify + _SigKill, "SIGTERM: software termination signal from kill"},
/* 16 */ {_SigNotify, "SIGUSR1: user defined signal 1"}, /* 16 */ {_SigNotify, "SIGUSR1: user defined signal 1"},
/* 17 */ {_SigNotify, "SIGUSR2: user defined signal 2"}, /* 17 */ {_SigNotify, "SIGUSR2: user defined signal 2"},
/* 18 */ {_SigNotify, "SIGCHLD: child status change alias (POSIX)"}, /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status change alias (POSIX)"},
/* 19 */ {_SigNotify, "SIGPWR: power-fail restart"}, /* 19 */ {_SigNotify, "SIGPWR: power-fail restart"},
/* 20 */ {_SigNotify, "SIGWINCH: window size change"}, /* 20 */ {_SigNotify, "SIGWINCH: window size change"},
/* 21 */ {_SigNotify, "SIGURG: urgent socket condition"}, /* 21 */ {_SigNotify, "SIGURG: urgent socket condition"},
...@@ -39,7 +39,7 @@ var sigtable = [...]sigTabT{ ...@@ -39,7 +39,7 @@ var sigtable = [...]sigTabT{
/* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background tty read attempted"}, /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background tty read attempted"},
/* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background tty write attempted"}, /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background tty write attempted"},
/* 28 */ {_SigNotify, "SIGVTALRM: virtual timer expired"}, /* 28 */ {_SigNotify, "SIGVTALRM: virtual timer expired"},
/* 29 */ {_SigNotify, "SIGPROF: profiling timer expired"}, /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling timer expired"},
/* 30 */ {_SigNotify, "SIGXCPU: exceeded cpu limit"}, /* 30 */ {_SigNotify, "SIGXCPU: exceeded cpu limit"},
/* 31 */ {_SigNotify, "SIGXFSZ: exceeded file size limit"}, /* 31 */ {_SigNotify, "SIGXFSZ: exceeded file size limit"},
/* 32 */ {_SigNotify, "SIGWAITING: reserved signal no longer used by"}, /* 32 */ {_SigNotify, "SIGWAITING: reserved signal no longer used by"},
......
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