mirror of
https://github.com/golang/go.git
synced 2025-11-11 14:11:04 +00:00
os/signal: add Stop, be careful about SIGHUP
Fixes #4268. Fixes #4491. R=golang-dev, nightlyone, fullung, r CC=golang-dev https://golang.org/cl/7546048
This commit is contained in:
parent
392d5feb8b
commit
cb4428e555
12 changed files with 289 additions and 47 deletions
|
|
@ -8,6 +8,9 @@
|
||||||
#define JMP B
|
#define JMP B
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEXT ·signal_disable(SB),7,$0
|
||||||
|
JMP runtime·signal_disable(SB)
|
||||||
|
|
||||||
TEXT ·signal_enable(SB),7,$0
|
TEXT ·signal_enable(SB),7,$0
|
||||||
JMP runtime·signal_enable(SB)
|
JMP runtime·signal_enable(SB)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,20 @@ import (
|
||||||
|
|
||||||
var handlers struct {
|
var handlers struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
list []handler
|
m map[chan<- os.Signal]*handler
|
||||||
|
ref [numSig]int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
c chan<- os.Signal
|
mask [(numSig + 31) / 32]uint32
|
||||||
sig os.Signal
|
}
|
||||||
all bool
|
|
||||||
|
func (h *handler) want(sig int) bool {
|
||||||
|
return (h.mask[sig/32]>>uint(sig&31))&1 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) set(sig int) {
|
||||||
|
h.mask[sig/32] |= 1 << uint(sig&31)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify causes package signal to relay incoming signals to c.
|
// Notify causes package signal to relay incoming signals to c.
|
||||||
|
|
@ -32,6 +39,13 @@ type handler struct {
|
||||||
// signal rate. For a channel used for notification of just one signal value,
|
// signal rate. For a channel used for notification of just one signal value,
|
||||||
// a buffer of size 1 is sufficient.
|
// a buffer of size 1 is sufficient.
|
||||||
//
|
//
|
||||||
|
// It is allowed to call Notify multiple times with the same channel:
|
||||||
|
// each call expands the set of signals sent to that channel.
|
||||||
|
// The only way to remove signals from the set is to call Stop.
|
||||||
|
//
|
||||||
|
// It is allowed to call Notify multiple times with different channels
|
||||||
|
// and the same signals: each channel receives copies of incoming
|
||||||
|
// signals independently.
|
||||||
func Notify(c chan<- os.Signal, sig ...os.Signal) {
|
func Notify(c chan<- os.Signal, sig ...os.Signal) {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
panic("os/signal: Notify using nil channel")
|
panic("os/signal: Notify using nil channel")
|
||||||
|
|
@ -39,32 +53,77 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) {
|
||||||
|
|
||||||
handlers.Lock()
|
handlers.Lock()
|
||||||
defer handlers.Unlock()
|
defer handlers.Unlock()
|
||||||
|
|
||||||
|
h := handlers.m[c]
|
||||||
|
if h == nil {
|
||||||
|
if handlers.m == nil {
|
||||||
|
handlers.m = make(map[chan<- os.Signal]*handler)
|
||||||
|
}
|
||||||
|
h = new(handler)
|
||||||
|
handlers.m[c] = h
|
||||||
|
}
|
||||||
|
|
||||||
|
add := func(n int) {
|
||||||
|
if n < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !h.want(n) {
|
||||||
|
h.set(n)
|
||||||
|
if handlers.ref[n] == 0 {
|
||||||
|
enableSignal(n)
|
||||||
|
}
|
||||||
|
handlers.ref[n]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(sig) == 0 {
|
if len(sig) == 0 {
|
||||||
enableSignal(nil)
|
for n := 0; n < numSig; n++ {
|
||||||
handlers.list = append(handlers.list, handler{c: c, all: true})
|
add(n)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, s := range sig {
|
for _, s := range sig {
|
||||||
// We use nil as a special wildcard value for enableSignal,
|
add(signum(s))
|
||||||
// so filter it out of the list of arguments. This is safe because
|
}
|
||||||
// we will never get an incoming nil signal, so discarding the
|
}
|
||||||
// registration cannot affect the observed behavior.
|
}
|
||||||
if s != nil {
|
|
||||||
enableSignal(s)
|
// Stop causes package signal to stop relaying incoming signals to c.
|
||||||
handlers.list = append(handlers.list, handler{c: c, sig: s})
|
// It undoes the effect of all prior calls to Notify using c.
|
||||||
|
// When Stop returns, it is guaranteed that c will receive no more signals.
|
||||||
|
func Stop(c chan<- os.Signal) {
|
||||||
|
handlers.Lock()
|
||||||
|
defer handlers.Unlock()
|
||||||
|
|
||||||
|
h := handlers.m[c]
|
||||||
|
if h == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(handlers.m, c)
|
||||||
|
|
||||||
|
for n := 0; n < numSig; n++ {
|
||||||
|
if h.want(n) {
|
||||||
|
handlers.ref[n]--
|
||||||
|
if handlers.ref[n] == 0 {
|
||||||
|
disableSignal(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func process(sig os.Signal) {
|
func process(sig os.Signal) {
|
||||||
|
n := signum(sig)
|
||||||
|
if n < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
handlers.Lock()
|
handlers.Lock()
|
||||||
defer handlers.Unlock()
|
defer handlers.Unlock()
|
||||||
|
|
||||||
for _, h := range handlers.list {
|
for c, h := range handlers.m {
|
||||||
if h.all || h.sig == sig {
|
if h.want(n) {
|
||||||
// send but do not block for it
|
// send but do not block for it
|
||||||
select {
|
select {
|
||||||
case h.c <- sig:
|
case c <- sig:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,10 @@ package signal
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
func enableSignal(sig os.Signal) {}
|
const numSig = 0
|
||||||
|
|
||||||
|
func signum(sig os.Signal) int { return -1 }
|
||||||
|
|
||||||
|
func disableSignal(int) {}
|
||||||
|
|
||||||
|
func enableSignal(int) {}
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,17 @@
|
||||||
package signal
|
package signal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const sighup = syscall.SIGHUP
|
|
||||||
|
|
||||||
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
|
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
|
||||||
select {
|
select {
|
||||||
case s := <-c:
|
case s := <-c:
|
||||||
|
|
@ -27,15 +29,17 @@ func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that basic signal handling works.
|
||||||
func TestSignal(t *testing.T) {
|
func TestSignal(t *testing.T) {
|
||||||
// Ask for SIGHUP
|
// Ask for SIGHUP
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
Notify(c, sighup)
|
Notify(c, syscall.SIGHUP)
|
||||||
|
defer Stop(c)
|
||||||
|
|
||||||
t.Logf("sighup...")
|
t.Logf("sighup...")
|
||||||
// Send this process a SIGHUP
|
// Send this process a SIGHUP
|
||||||
syscall.Kill(syscall.Getpid(), sighup)
|
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
|
||||||
waitSig(t, c, sighup)
|
waitSig(t, c, syscall.SIGHUP)
|
||||||
|
|
||||||
// Ask for everything we can get.
|
// Ask for everything we can get.
|
||||||
c1 := make(chan os.Signal, 1)
|
c1 := make(chan os.Signal, 1)
|
||||||
|
|
@ -71,6 +75,7 @@ func TestStress(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
sig := make(chan os.Signal, 1)
|
sig := make(chan os.Signal, 1)
|
||||||
Notify(sig, syscall.SIGUSR1)
|
Notify(sig, syscall.SIGUSR1)
|
||||||
|
defer Stop(sig)
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|
@ -103,3 +108,101 @@ func TestStress(t *testing.T) {
|
||||||
// Sleep for a while to reduce the possibility of the failure.
|
// Sleep for a while to reduce the possibility of the failure.
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
|
||||||
|
|
||||||
|
// Test that Stop cancels the channel's registrations.
|
||||||
|
func TestStop(t *testing.T) {
|
||||||
|
sigs := []syscall.Signal{
|
||||||
|
syscall.SIGWINCH,
|
||||||
|
syscall.SIGHUP,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sig := range sigs {
|
||||||
|
// Send the signal.
|
||||||
|
// If it's SIGWINCH, we should not see it.
|
||||||
|
// If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
|
||||||
|
if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 {
|
||||||
|
syscall.Kill(syscall.Getpid(), sig)
|
||||||
|
}
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
|
// Ask for signal
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
Notify(c, sig)
|
||||||
|
defer Stop(c)
|
||||||
|
|
||||||
|
// Send this process that signal
|
||||||
|
syscall.Kill(syscall.Getpid(), sig)
|
||||||
|
waitSig(t, c, sig)
|
||||||
|
|
||||||
|
Stop(c)
|
||||||
|
select {
|
||||||
|
case s := <-c:
|
||||||
|
t.Fatalf("unexpected signal %v", s)
|
||||||
|
case <-time.After(10 * time.Millisecond):
|
||||||
|
// nothing to read - good
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the signal.
|
||||||
|
// If it's SIGWINCH, we should not see it.
|
||||||
|
// If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
|
||||||
|
if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 {
|
||||||
|
syscall.Kill(syscall.Getpid(), sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case s := <-c:
|
||||||
|
t.Fatalf("unexpected signal %v", s)
|
||||||
|
case <-time.After(10 * time.Millisecond):
|
||||||
|
// nothing to read - good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that when run under nohup, an uncaught SIGHUP does not kill the program,
|
||||||
|
// but a
|
||||||
|
func TestNohup(t *testing.T) {
|
||||||
|
// Ugly: ask for SIGHUP so that child will not have no-hup set
|
||||||
|
// even if test is running under nohup environment.
|
||||||
|
// We have no intention of reading from c.
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
Notify(c, syscall.SIGHUP)
|
||||||
|
|
||||||
|
// When run without nohup, the test should crash on an uncaught SIGHUP.
|
||||||
|
// When run under nohup, the test should ignore uncaught SIGHUPs,
|
||||||
|
// because the runtime is not supposed to be listening for them.
|
||||||
|
// Either way, TestStop should still be able to catch them when it wants them
|
||||||
|
// and then when it stops wanting them, the original behavior should resume.
|
||||||
|
//
|
||||||
|
// send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs.
|
||||||
|
// send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs.
|
||||||
|
//
|
||||||
|
// Both should fail without nohup and succeed with nohup.
|
||||||
|
|
||||||
|
for i := 1; i <= 2; i++ {
|
||||||
|
out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stop(c)
|
||||||
|
|
||||||
|
// Again, this time with nohup, assuming we can find it.
|
||||||
|
_, err := os.Stat("/usr/bin/nohup")
|
||||||
|
if err != nil {
|
||||||
|
t.Skip("cannot find nohup; skipping second half of test")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i <= 2; i++ {
|
||||||
|
os.Remove("nohup.out")
|
||||||
|
out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
|
||||||
|
|
||||||
|
data, _ := ioutil.ReadFile("nohup.out")
|
||||||
|
os.Remove("nohup.out")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", i, err, out, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// In assembly.
|
// In assembly.
|
||||||
|
func signal_disable(uint32)
|
||||||
func signal_enable(uint32)
|
func signal_enable(uint32)
|
||||||
func signal_recv() uint32
|
func signal_recv() uint32
|
||||||
|
|
||||||
|
|
@ -26,13 +27,27 @@ func init() {
|
||||||
go loop()
|
go loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func enableSignal(sig os.Signal) {
|
const (
|
||||||
|
numSig = 65 // max across all systems
|
||||||
|
)
|
||||||
|
|
||||||
|
func signum(sig os.Signal) int {
|
||||||
switch sig := sig.(type) {
|
switch sig := sig.(type) {
|
||||||
case nil:
|
|
||||||
signal_enable(^uint32(0))
|
|
||||||
case syscall.Signal:
|
case syscall.Signal:
|
||||||
signal_enable(uint32(sig))
|
i := int(sig)
|
||||||
|
if i < 0 || i >= numSig {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return i
|
||||||
default:
|
default:
|
||||||
// Can ignore: this signal (whatever it is) will never come in.
|
return -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enableSignal(sig int) {
|
||||||
|
signal_enable(uint32(sig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func disableSignal(sig int) {
|
||||||
|
signal_disable(uint32(sig))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,12 @@ runtime·sigenable(uint32 sig)
|
||||||
USED(sig);
|
USED(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·sigdisable(uint32 sig)
|
||||||
|
{
|
||||||
|
USED(sig);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·resetcpuprofiler(int32 hz)
|
runtime·resetcpuprofiler(int32 hz)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,12 @@ runtime·sigenable(uint32 sig)
|
||||||
USED(sig);
|
USED(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·sigdisable(uint32 sig)
|
||||||
|
{
|
||||||
|
USED(sig);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·resetcpuprofiler(int32 hz)
|
runtime·resetcpuprofiler(int32 hz)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,12 @@ runtime·sigenable(uint32 sig)
|
||||||
USED(sig);
|
USED(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·sigdisable(uint32 sig)
|
||||||
|
{
|
||||||
|
USED(sig);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·dosigprof(Context *r, G *gp)
|
runtime·dosigprof(Context *r, G *gp)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,12 @@ runtime·sigenable(uint32 sig)
|
||||||
USED(sig);
|
USED(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·sigdisable(uint32 sig)
|
||||||
|
{
|
||||||
|
USED(sig);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·dosigprof(Context *r, G *gp)
|
runtime·dosigprof(Context *r, G *gp)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,8 @@ enum
|
||||||
SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
|
SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
|
||||||
SigPanic = 1<<3, // if the signal is from the kernel, panic
|
SigPanic = 1<<3, // if the signal is from the kernel, panic
|
||||||
SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
|
SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
|
||||||
|
SigHandling = 1<<5, // our signal handler is registered
|
||||||
|
SigIgnored = 1<<6, // the signal was ignored before we registered for it
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(rsc): keep in sync with extern.go:/type.Func.
|
// NOTE(rsc): keep in sync with extern.go:/type.Func.
|
||||||
|
|
@ -696,6 +698,7 @@ String runtime·gostringnocopy(byte*);
|
||||||
String runtime·gostringw(uint16*);
|
String runtime·gostringw(uint16*);
|
||||||
void runtime·initsig(void);
|
void runtime·initsig(void);
|
||||||
void runtime·sigenable(uint32 sig);
|
void runtime·sigenable(uint32 sig);
|
||||||
|
void runtime·sigdisable(uint32 sig);
|
||||||
int32 runtime·gotraceback(void);
|
int32 runtime·gotraceback(void);
|
||||||
void runtime·goroutineheader(G*);
|
void runtime·goroutineheader(G*);
|
||||||
void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
|
void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,20 @@ runtime·initsig(void)
|
||||||
t = &runtime·sigtab[i];
|
t = &runtime·sigtab[i];
|
||||||
if((t->flags == 0) || (t->flags & SigDefault))
|
if((t->flags == 0) || (t->flags & SigDefault))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// For some signals, we respect an inherited SIG_IGN handler
|
||||||
|
// rather than insist on installing our own default handler.
|
||||||
|
// Even these signals can be fetched using the os/signal package.
|
||||||
|
switch(i) {
|
||||||
|
case SIGHUP:
|
||||||
|
case SIGINT:
|
||||||
|
if(runtime·getsig(i) == SIG_IGN) {
|
||||||
|
t->flags = SigNotify | SigIgnored;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t->flags |= SigHandling;
|
||||||
runtime·setsig(i, runtime·sighandler, true);
|
runtime·setsig(i, runtime·sighandler, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,18 +43,35 @@ runtime·initsig(void)
|
||||||
void
|
void
|
||||||
runtime·sigenable(uint32 sig)
|
runtime·sigenable(uint32 sig)
|
||||||
{
|
{
|
||||||
int32 i;
|
|
||||||
SigTab *t;
|
SigTab *t;
|
||||||
|
|
||||||
for(i = 0; i<NSIG; i++) {
|
if(sig >= NSIG)
|
||||||
// ~0 means all signals.
|
return;
|
||||||
if(~sig == 0 || i == sig) {
|
|
||||||
t = &runtime·sigtab[i];
|
t = &runtime·sigtab[sig];
|
||||||
if(t->flags & SigDefault) {
|
if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
|
||||||
runtime·setsig(i, runtime·sighandler, true);
|
t->flags |= SigHandling;
|
||||||
t->flags &= ~SigDefault; // make this idempotent
|
if(runtime·getsig(sig) == SIG_IGN)
|
||||||
}
|
t->flags |= SigIgnored;
|
||||||
}
|
runtime·setsig(sig, runtime·sighandler, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime·sigdisable(uint32 sig)
|
||||||
|
{
|
||||||
|
SigTab *t;
|
||||||
|
|
||||||
|
if(sig >= NSIG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
t = &runtime·sigtab[sig];
|
||||||
|
if((t->flags & SigNotify) && (t->flags & SigHandling)) {
|
||||||
|
t->flags &= ~SigHandling;
|
||||||
|
if(t->flags & SigIgnored)
|
||||||
|
runtime·setsig(sig, SIG_IGN, true);
|
||||||
|
else
|
||||||
|
runtime·setsig(sig, SIG_DFL, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,8 +133,6 @@ done:;
|
||||||
|
|
||||||
// Must only be called from a single goroutine at a time.
|
// Must only be called from a single goroutine at a time.
|
||||||
func signal_enable(s uint32) {
|
func signal_enable(s uint32) {
|
||||||
int32 i;
|
|
||||||
|
|
||||||
if(!sig.inuse) {
|
if(!sig.inuse) {
|
||||||
// The first call to signal_enable is for us
|
// The first call to signal_enable is for us
|
||||||
// to use for initialization. It does not pass
|
// to use for initialization. It does not pass
|
||||||
|
|
@ -144,16 +142,16 @@ func signal_enable(s uint32) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(~s == 0) {
|
|
||||||
// Special case: want everything.
|
|
||||||
for(i=0; i<nelem(sig.wanted); i++)
|
|
||||||
sig.wanted[i] = ~(uint32)0;
|
|
||||||
runtime·sigenable(s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s >= nelem(sig.wanted)*32)
|
if(s >= nelem(sig.wanted)*32)
|
||||||
return;
|
return;
|
||||||
sig.wanted[s/32] |= 1U<<(s&31);
|
sig.wanted[s/32] |= 1U<<(s&31);
|
||||||
runtime·sigenable(s);
|
runtime·sigenable(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must only be called from a single goroutine at a time.
|
||||||
|
func signal_disable(s uint32) {
|
||||||
|
if(s >= nelem(sig.wanted)*32)
|
||||||
|
return;
|
||||||
|
sig.wanted[s/32] &= ~(1U<<(s&31));
|
||||||
|
runtime·sigdisable(s);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue