When you close a GNOME Terminal window, a SIGHUP is sent to the shell that it was running. The shell will typically send a SIGHUP to every process group that it knows it created - even ones started with nohup
- and then exit. If the shell is bash
, it will skip sending a SIGHUP to any process group that the user marked with disown
.
Running a command with nohup
makes it ignore SIGHUP, but the process can change that. When the disposition of SIGHUP for a process is the default, then if it receives a SIGHUP, the process will be terminated.
Linux provides some tools to examine a running process's signal settings.
The chromium-browser shell script does an exec
of the compiled app, so its process ID remains the same. So to see its signal settings, I ran nohup chromium-browser &
and then looked at /proc/$!/status
to see the signal disposition.
SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003
Those are hex numbers. This shows that SIGHUP is not caught and is not ignored. Only SIGPIPE (the 13th bit in SigIgn) is ignored. I traced this to the following code:
// Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
void SetupSignalHandlers() {
// Sanitise our signal handling state. Signals that were ignored by our
// parent will also be ignored by us. We also inherit our parent's sigmask.
sigset_t empty_signal_set;
CHECK(0 == sigemptyset(&empty_signal_set));
CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));
struct sigaction sigact;
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = SIG_DFL;
static const int signals_to_reset[] =
{SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP}; // SIGPIPE is set below.
for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
}
// Always ignore SIGPIPE. We check the return value of write().
CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
}
Despite the comment, signals ignored by the parent are not being ignored. A SIGHUP will kill chromium.
The workaround is to do what @xx4h points out: use the disown
command in your bash so that, if bash has to exit, it does not send SIGHUP to the chromium-browser
process group. You can write a function to do this:
mychromium () { /usr/bin/chromium-browser & disown $!; }
So here we do have to pass the file name twice in the function.
They are not quite the same thing as you notice by observing that one of them is used as the argv[0]
value. This doesn't have to be the same as the basename of the executable; many/most things ignore it and you can put whatever you want in there.
The first one is the actual path to the executable, for which there is an obvious necessity. The second one is passed to the process ostensibly as the name used to invoke it, but, e.g.:
execl("/bin/ls", "banana", "-l", NULL);
Will work fine, presuming /bin/ls
is the correct path.
Some applications do, however, make use of argv[0]
. Usually these have one or more symlinks in $PATH
; this is common with compression utilities (sometimes they use shell wrappers instead). If you have xz
installed, stat $(which xzcat)
shows it's a link to xz
, and man xzcat
is the same as man xz
which explains "xzcat is equivalent to xz --decompress --stdout". The way xz can tell how it was invoked is by checking argv[0]
, making these equivalent:
execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);
Best Answer
What's better, a fish or a bicycle?
nohup
andexec
do different things.exec
replaces the shell with another program. Usingexec
in a simple background job isn't useful:exec myprogram; more stuff
replaces the shell withmyprogram
and so doesn't runmore stuff
, unlikemyprogram; more stuff
which runsmore stuff
whenmyprogram
terminates; butexec myprogram & more stuff
startsmyprogram
in the background and then runsmore stuff
, just likemyprogram & more stuff
.nohup
runs the specificed program with the SIGHUP signal ignored. When a terminal is closed, the kernel sends SIGHUP to the controlling process in that terminal (i.e. the shell). The shell in turn sends SIGHUP to all the jobs running in the background. Running a job withnohup
prevents it from being killed in this way if the terminal dies (which happens e.g. if you were logged in remotely and the connection drops, or if you close your terminal emulator).nohup
also redirects the program's output to the filenohup.out
. This avoids the program dying because it isn't able to write to its output or error output. Note thatnohup
doesn't redirect the input. To fully disconnect a program from the terminal where you launched it, use