]> Cypherpunks repositories - gostls13.git/commitdiff
os/signal: add func Ignored(sig Signal) bool
authorAdam Azarchs <adam.azarchs@10xgenomics.com>
Fri, 20 Apr 2018 02:59:39 +0000 (19:59 -0700)
committerIan Lance Taylor <iant@golang.org>
Sat, 21 Apr 2018 04:18:03 +0000 (04:18 +0000)
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: Ian Lance Taylor <iant@golang.org>
src/os/signal/signal.go
src/os/signal/signal_plan9.go
src/os/signal/signal_test.go
src/os/signal/signal_unix.go
src/runtime/signal_unix.go
src/runtime/sigqueue.go
src/runtime/sigqueue_plan9.go

index e5a21e8532754d7f2383ca38989e252dc1179172..dc6b674c4f82c28334f6a9617b48db48fa5ff8b6 100644 (file)
@@ -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.
index b065ae520d7817a8396f9db5778a8e619190ba5d..a1eb68855ed277325caa69021cb12f3ea73846d8 100644 (file)
@@ -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))
+}
index e4df8af816e0c2c8b1dc02bb92ed14e0d22ed94e..3d79c7a8619a89499fcf19780f3abc2f1561247e 100644 (file)
@@ -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.
index 01b1b14fd19548d1b091c6d1c9eae05f4f31a4a0..0987c1730a70eb60ceba516a078dfa4381fdb70d 100644 (file)
@@ -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))
+}
index d87f1bed16929ec0b9538cc04adc80ad224e95d4..0d8caae7a068b90751b9e0c58cfcdfb77da90a10 100644 (file)
@@ -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
                }
index 98331627eb46c2174ba7e42c2ad8f816c55b25c3..9f5324095448ce7c30ef318021320f6fb1942495 100644 (file)
@@ -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
index 76668045a86c59b6e304af999205315ee1ab6fc3..934742a1f4ceea509586044bb788a365376cd3e5 100644 (file)
@@ -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
+}