For a Standard Shell (bash) (POSIX.1)
Start it with &
, make it read from something other then the default stdin
(==/dev/tty
== /dev/stdin
== /dev/fd/0
) + make it write to something other than the default stdout
(==/dev/tty
== /dev/stdin
== /dev/fd/1
) (same for stderr
) and make sure the job isn't or doesn't get suspended(=stopped). If it must get stopped or must read from the terminal and it is to continue after the job's terminal hangs up, make sure the processes in the job have a handler (trap) for the SIGHUP signal. If it must write to the terminal and it is to survive a terminal hang up, make sure the processes that write to the terminal have a handler for SIGPIPE.
Explanation:
Background processes get sent SIGTTIN the moment they try to read from the terminal. The default disposition for SIGTTIN is to stop (=suspend) the process. A terminal hangup will cause the first generation of processes of your background jobs to get reparented to init, causing the process group of the first generation of your job's processes to become an orphaned process group. (Orphaned process groups are those where none of the members have a parent in a different process group but in the same session.) The system will send all stopped (suspended) orphaned process groups SIGHUP followed by SIGCONT (to make sure they get the SIGHUP) on a terminal hangup because by definition, none of the processes in that process group can be awoken by a parent from the same session. Consequently those processes must be awoken by the system, but at the same time in a way that signals that process that it got awoken due to the terminal hanging up rather than due to normal operation. SIGHUP is the mechanism that does that and the default disposition for SIGHUP is to abort.
Hanging up a terminal will also cause subsequent writes to that terminal to raise SIGPIPE, which is also deadly if unhandled.
TL;DR
If your orphaned process groups aren't suspended (via SIGTTIN or ^Z or otherwise, they don't have to be afraid of the SIGHUP signal and if they output to a file rather than the terminal on both stdout
and stderr
and read from a file rather than the terminal, then they don't have to be afraid of SIGPIPE.
If you're running on top of a terminal multiplexer rather than a raw terminal, youd don't have to be afraid of either SIGHUP or SIGPIPE.
For zsh
I played with zsh
and it turns out that while bash
does behave like I described above (the above described behavior should be conforming to POSIX.1), zsh
sends SIGHUP to running background jobs even.
setopt NO_HUP
makes it (or the system; not sure here) only send SIGHUP
in situations described above.
For testing this, you can try running something like:
( rm -f hup; trap 'echo HUP > hup' HUP; sleep 100)
in various ways (background, foreground, stopped) and disconnecting with it. Then you can check whether the hup
file was created, which would mean the job did get a SIGHUP.
/dev/null
(or to a file) instead. To prevent a program from exiting upon receipt of SIGHUP, you need to have it ignore the SIGHUP signal. You can do this by usinggdb
orptrace
to make the necessary system calls. This is all easier if the program was written in C or C++ rather than some other language that has a different I/O, thread, and signal model or that lacks the C library routines to make system calls. – Mark Plotnick Aug 10 '15 at 15:25