Suppose I have a process which spawns exactly one child process. Now when the parent process exits for whatever reason (normally or abnormally, by kill, ^C, assert failure or anything else) I want the child process to die. How to do that correctly?
Some similar question on stackoverflow:
- (asked earlier) How can I cause a child process to exit when the parent does?
- (asked later) Are child processes created with fork() automatically killed when the parent is killed?
Some similar question on stackoverflow for Windows:
Under Linux, you can install a parent death signal in the child, e.g.:
Note that storing the parent process id before the fork and testing it in the child after
prctl()
eliminates a race condition betweenprctl()
and the exit of the process that called the child.Also note that the parent death signal of the child is cleared in newly created children of its own. It is not affected by an
execve()
.That test can be simplified if we are certain that the system process who is in charge of adopting all orphans has PID 1:
Relying on that system process being
init
and having PID 1 isn't portable, though. POSIX.1-2008 specifies:Traditionally, the system process adopting all orphans is PID 1, i.e. init - which is the ancestor of all processes.
On modern systems like Linux or FreeBSD another process might have that role. For example, on Linux, a process can call
prctl(PR_SET_CHILD_SUBREAPER, 1)
to establish itself as system process that inherits all orphans of any of its descendants (cf. an example on Fedora 25).Child can ask kernel to deliver
SIGHUP
(or other signal) when parent dies by specifying optionPR_SET_PDEATHSIG
inprctl()
syscall like this:prctl(PR_SET_PDEATHSIG, SIGHUP);
See
man 2 prctl
for details.Edit: This is Linux-only
Install a trap handler to catch SIGINT, which kills off your child process if it's still alive, though other posters are correct that it won't catch SIGKILL.
Open a .lockfile with exclusive access and have the child poll on it trying to open it - if the open succeeds, the child process should exit
Some posters have already mentioned pipes and
kqueue
. In fact you can also create a pair of connected Unix domain sockets by thesocketpair()
call. The socket type should beSOCK_STREAM
.Let us suppose you have the two socket file descriptors fd1, fd2. Now
fork()
to create the child process, which will inherit the fds. In the parent you close fd2 and in the child you close fd1. Now each process canpoll()
the remaining open fd on its own end for thePOLLIN
event. As long as each side doesn't explicitlyclose()
its fd during normal lifetime, you can be fairly sure that aPOLLHUP
flag should indicate the other's termination (no matter clean or not). Upon notified of this event, the child can decide what to do (e.g. to die).You can try compiling the above proof-of-concept code, and run it in a terminal like
./a.out &
. You have roughly 100 seconds to experiment with killing the parent PID by various signals, or it will simply exit. In either case, you should see the message "child: parent hung up".Compared with the method using
SIGPIPE
handler, this method doesn't require trying thewrite()
call.This method is also symmetric, i.e. the processes can use the same channel to monitor each other's existence.
This solution calls only the POSIX functions. I tried this in Linux and FreeBSD. I think it should work on other Unixes but I haven't really tested.
See also:
unix(7)
of Linux man pages,unix(4)
for FreeBSD,poll(2)
,socketpair(2)
,socket(7)
on Linux.Another way to do this that is Linux specific is to have the parent be created in a new PID namespace. It will then be PID 1 in that namespace, and when it exits it all of it's children will be immediately killed with
SIGKILL
.Unfortunately, in order to create a new PID namespace you have to have
CAP_SYS_ADMIN
. But, this method is very effective and requires no real change to the parent or the children beyond the initial launch of the parent.See clone(2), pid_namespaces(7), and unshare(2).