Skip to content

Commit

Permalink
os/signal: add func Ignored(sig Signal) bool
Browse files Browse the repository at this point in the history
Ignored reports whether sig is currently ignored.

This implementation only works applies on Unix systems for now.  However, at
the moment that is also the case for Ignore() and several other signal
interaction methods, so that seems fair.

Fixes #22497

Change-Id: I7c1b1a5e12373ca5da44709500ff5acedc6f1316
Reviewed-on: https://go-review.googlesource.com/108376
Run-TryBot: Ian Lance Taylor <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
adam-azarchs authored and ianlancetaylor committed Apr 21, 2018
1 parent 37dd7cd commit dfb1b69
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/os/signal/signal.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ func Ignore(sig ...os.Signal) {
cancel(sig, ignoreSignal)
}

// Ignored reports whether sig is currently ignored.
func Ignored(sig os.Signal) bool {
if sn := signum(sig); sn < 0 {
return false
} else {
return signalIgnored(sn)
}
}

// Notify causes package signal to relay incoming signals to c.
// If no signals are provided, all incoming signals will be relayed to c.
// Otherwise, just the provided signals will.
Expand Down
5 changes: 5 additions & 0 deletions src/os/signal/signal_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var sigtab = make(map[os.Signal]int)
func signal_disable(uint32)
func signal_enable(uint32)
func signal_ignore(uint32)
func signal_ignored(uint32) bool
func signal_recv() string

func init() {
Expand Down Expand Up @@ -58,3 +59,7 @@ func disableSignal(sig int) {
func ignoreSignal(sig int) {
signal_ignore(uint32(sig))
}

func signalIgnored(sig int) bool {
return signal_ignored(uint32(sig))
}
59 changes: 59 additions & 0 deletions src/os/signal/signal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,65 @@ func TestIgnore(t *testing.T) {
testCancel(t, true)
}

// Test that Ignored correctly detects changes to the ignored status of a signal.
func TestIgnored(t *testing.T) {
// Ask to be notified on SIGWINCH.
c := make(chan os.Signal, 1)
Notify(c, syscall.SIGWINCH)

// If we're being notified, then the signal should not be ignored.
if Ignored(syscall.SIGWINCH) {
t.Errorf("expected SIGWINCH to not be ignored.")
}
Stop(c)
Ignore(syscall.SIGWINCH)

// We're no longer paying attention to this signal.
if !Ignored(syscall.SIGWINCH) {
t.Errorf("expected SIGWINCH to be ignored when explicitly ignoring it.")
}

Reset()
}

var checkSighupIgnored = flag.Bool("check_sighup_ignored", false, "if true, TestDetectNohup will fail if SIGHUP is not ignored.")

// Test that Ignored(SIGHUP) correctly detects whether it is being run under nohup.
func TestDetectNohup(t *testing.T) {
if *checkSighupIgnored {
if !Ignored(syscall.SIGHUP) {
t.Fatal("SIGHUP is not ignored.")
} else {
t.Log("SIGHUP is ignored.")
}
} else {
defer Reset()
// 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)
if out, err := exec.Command(os.Args[0], "-test.run=TestDetectNohup", "-check_sighup_ignored").CombinedOutput(); err == nil {
t.Errorf("ran test with -check_sighup_ignored and it succeeded: expected failure.\nOutput:\n%s", 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")
}
Ignore(syscall.SIGHUP)
os.Remove("nohup.out")
out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestDetectNohup", "-check_sighup_ignored").CombinedOutput()

data, _ := ioutil.ReadFile("nohup.out")
os.Remove("nohup.out")
if err != nil {
t.Errorf("ran test with -check_sighup_ignored under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", err, out, data)
}
}
}

var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")

// Test that Stop cancels the channel's registrations.
Expand Down
5 changes: 5 additions & 0 deletions src/os/signal/signal_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
func signal_disable(uint32)
func signal_enable(uint32)
func signal_ignore(uint32)
func signal_ignored(uint32) bool
func signal_recv() uint32

func loop() {
Expand Down Expand Up @@ -56,3 +57,7 @@ func disableSignal(sig int) {
func ignoreSignal(sig int) {
signal_ignore(uint32(sig))
}

func signalIgnored(sig int) bool {
return signal_ignored(uint32(sig))
}
2 changes: 2 additions & 0 deletions src/runtime/signal_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ func initsig(preinit bool) {
// set SA_ONSTACK if necessary.
if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN {
setsigstack(i)
} else if fwdSig[i] == _SIG_IGN {
sigInitIgnored(i)
}
continue
}
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/sigqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,16 @@ func signal_ignore(s uint32) {
atomic.Store(&sig.ignored[s/32], i)
}

// sigInitIgnored marks the signal as already ignored. This is called at
// program start by siginit.
func sigInitIgnored(s uint32) {
i := sig.ignored[s/32]
i |= 1 << (s & 31)
atomic.Store(&sig.ignored[s/32], i)
}

// Checked by signal handlers.
//go:linkname signal_ignored os/signal.signal_ignored
func signal_ignored(s uint32) bool {
i := atomic.Load(&sig.ignored[s/32])
return i&(1<<(s&31)) != 0
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/sigqueue_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,8 @@ func signal_disable(s uint32) {
//go:linkname signal_ignore os/signal.signal_ignore
func signal_ignore(s uint32) {
}

//go:linkname signal_ignored os/signal.signal_ignored
func signal_ignored(s uint32) bool {
return false
}

0 comments on commit dfb1b69

Please sign in to comment.