package main
import (
"os"
"os/signal"
log "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, unix.SIGHUP)
go func() {
s := <-sigs
log.Info("OS signal: " + s.String())
}()
DoSomething()
}
I compiled the Go code above and executed with following command:
nohup ./build_linux > /dev/null 2>&1 &
But the process still catches HANGUP signal when I exit the terminal.
Seems like signal.Notify
has higher priority, and nohup
command has no effect.
What's going on and why nohup
does not prevent sending hangup signal to process?
Check signal.Ignored()
first:
if !signal.Ignored(unix.SIGHUP) {
signal.Notify(sigs, unix.SIGHUP)
}
tkausl's comment has the correct answer: running:
nohup ./build_linux
from the command line launches the ./build_linux
program with SIGHUP
set to SIG_IGN
(all of these signal names being generic Linux names, rather than Go package names). If you install your own handler for SIGHUP
, this overrides the current setting of SIGHUP
.
In general, in Unix/Linux programs, the correct pattern is to test whether the signal is currently ignored before (or as part of) installing a signal-catch function. If the signal is ignored, restore it to being ignored.
To make this process completely reliable, the most efficient correct pattern to use is:
SIG_IGN
, return the disposition to SIG_IGN
;The holding-and-releasing is done with the Unix/Linux sigprocmask
or pthread_sigmask
system call. The one to use depends on whether you're using threads. Go of course does use threads; see, e.g., this patch to the Cgo runtime startup from 2013 (fixes issue #6811).
Since Go 1.11, which introduced signal.Ignored
, you can just use that, as the Go runtime has already done all the appropriate hold / set-and-test / restore sequence at startup, and cached the result. One should definitely use this for SIGHUP
so as to obey the nohup
convention. One should generally use this for SIGINT
and other keyboard signals as well, and there's almost1 no reason not to use it for all signals.1
1Jenkins, or some version or versions of Jenkins at least, apparently (incorrectly) sets all signals to be ignored at startup when running test suites.