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:
For completeness sake. On macOS you can use kqueue:
Historically, from UNIX v7, the process system has detected orphanity of processes by checking a process' parent id. As I say, historically, the
init(8)
system process is a special process by only one reason: It cannot die. It cannot die because the kernel algorithm to deal with assigning a new parent process id, depends on this fact. when a process executes itsexit(2)
call (by means of a process system call or by external task as sending it a signal or the like) the kernel reassigns all children of this process the id of the init process as their parent process id. This leads to the most easy test, and most portable way of knowing if a process has got orphan. Just check the result of thegetppid(2)
system call and if it is the process id of theinit(2)
process then the process got orphan before the system call.Two issues emerge from this approach that can lead to issues:
init
process to any user process, so How can we assure that the init process will always be parent of all orphan processes? Well, in theexit
system call code there's a explicit check to see if the process executing the call is the init process (the process with pid equal to 1) and if that's the case, the kernel panics (It should not be able anymore to maintain the process hierarchy) so it is not permitted for the init process to do anexit(2)
call.1
, but that's not warranted by the POSIX approach, that states (as exposed in other response) that only a system's process id is reserved for that purpose. Almost no posix implementation does this, and you can assume in original unix derived systems that having1
as response ofgetppid(2)
system call is enough to assume the process is orphan. Another way to check is to make agetppid(2)
just after the fork and compare that value with the result of a new call. This simply doesn't work in all cases, as both call are not atomic together, and the parent process can die after thefork(2)
and before the firstgetppid(2)
system call. The processparent id only changes once, when its parent does an
exit(2)call, so this should be enough to check if the
getppid(2)result changed between calls to see that parent process has exit. This test is not valid for the actual children of the init process, because they are always children of
init(8)`, but you can assume safely these processes as having no parent either (except when you substitute in a system the init process)Under POSIX, the
exit()
,_exit()
and_Exit()
functions are defined to:So, if you arrange for the parent process to be a controlling process for its process group, the child should get a SIGHUP signal when the parent exits. I'm not absolutely sure that happens when the parent crashes, but I think it does. Certainly, for the non-crash cases, it should work fine.
Note that you may have to read quite a lot of fine print - including the Base Definitions (Definitions) section, as well as the System Services information for
exit()
andsetsid()
andsetpgrp()
- to get the complete picture. (So would I!)I found 2 solutions, both not perfect.
1.Kill all children by kill(-pid) when received SIGTERM signal.
Obviously, this solution can not handle "kill -9", but it do work for most case and very simple because it need not to remember all child processes.
By same way, you can install 'exit' handler like above way if you call process.exit somewhere. Note: Ctrl+C and sudden crash have automatically been processed by OS to kill process group, so no more here.
2.Use chjj/pty.js to spawn your process with controlling terminal attached.
When you kill current process by anyway even kill -9, all child processes will be automatically killed too (by OS?). I guess that because current process hold another side of the terminal, so if current process dies, the child process will get SIGPIPE so dies.
I don't believe it's possible to guarantee that using only standard POSIX calls. Like real life, once a child is spawned, it has a life of its own.
It is possible for the parent process to catch most possible termination events, and attempt to kill the child process at that point, but there's always some that can't be caught.
For example, no process can catch a
SIGKILL
. When the kernel handles this signal it will kill the specified process with no notification to that process whatsoever.To extend the analogy - the only other standard way of doing it is for the child to commit suicide when it finds that it no longer has a parent.
There is a Linux-only way of doing it with
prctl(2)
- see other answers.If parent dies, PPID of orphans change to 1 - you only need to check your own PPID. In a way, this is polling, mentioned above. here is shell piece for that: