Commit dfb1b696 authored by Adam Azarchs's avatar Adam Azarchs Committed by Ian Lance Taylor

os/signal: add func Ignored(sig Signal) bool

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 <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 37dd7cd0
......@@ -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.
......
......@@ -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() {
......@@ -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))
}
......@@ -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.
......
......@@ -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() {
......@@ -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))
}
......@@ -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
}
......
......@@ -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
......
......@@ -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
}
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