Child can ask kernel to deliver SIGHUP (or other signal) when parent dies by specifying option PR_SET_PDEATHSIG in prctl() syscall like this.
Up vote 38 down vote favorite 24 share g+ share fb share tw.
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) stackoverflow.com/questions/269494/how-c... (asked later) stackoverflow.com/questions/395877/are-c... c linux unix process fork link|improve this question edited Dec 28 '08 at 6:11dmckee32.3k44496 asked Nov 12 '08 at 15:37Pawe? Hajdan5,73541540 93% accept rate.
Child can ask kernel to deliver SIGHUP (or other signal) when parent dies by specifying option PR_SET_PDEATHSIG in prctl() syscall like this: prctl(PR_SET_PDEATHSIG, SIGHUP); See man 2 prctl for details. Edit: This is Linux-only.
5 Nice spot - shame it's Linux only... – Alnitak Nov 12 '08 at 16:14 Yeah, Linux-specific. I don't think there is POSIX way to do it. – qrdl Nov 12 '08 at 16:19 1 Please edit to mention this is Linux-only.
– John M Nov 12 '08 at 21:06.
I'm trying to solve the same problem, and since my program must run on OS X, the Linux-only solution didn't work for me. I came to the same conclusion as the other people on this page -- there isn't a POSIX-compatible way of notifying a child when a parent dies. So I kludged up the next-best thing -- having the child poll.
When a parent process dies (for any reason) the child's parent process becomes process 1. If the child simply polls periodically, it can check if its parent is 1. If it is, the child should exit.
This isn't great, but it works, and it's easier than the TCP socket/lockfile polling solutions suggested elsewhere on this page.
3 Excellent solution. Continuesly invoking getppid() until it returns 1 and then exit. This is good and I now use it too.
A non-pollig solution would be nice though. Thank you Schof. – neoneye Apr 11 '10 at 11:58 5 Just for info, on Solaris if you're in a zone, the gettpid() does not become 1 but gets the pid of the zone scheduler (process zsched).
– tristopia Oct 14 '10 at 13:32.
I have achieved this in the past by running the "original" code in the "child" and the "spawned" code in the "parent" (that is: you reverse the usual sense of the test after fork()). Then trap SIGCHLD in the "spawned" code... May not be possible in your case, but cute when it works.
Very nice solution, thanks! The currently accepted one is more generic, but yours is more portable. – Pawe?
Hajdan Nov 12 '08 at 20:47.
If so, you'd receive a SIGPIPE if writing, or get EOF when reading - these conditions could be detected.
1 I found this didn't happen reliably, at least on OS X. – Schof Jan 10 '10 at 1:31.
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.
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.
For completeness sake. On Mac OS X you can use kqueue: void noteProcDeath( CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void* info) { // LOG_DEBUG(@"noteProcDeath... "); struct kevent kev; int fd = CFFileDescriptorGetNativeDescriptor(fdref); kevent(fd, NULL, 0, &kev, 1, NULL); // take action on death of process here unsigned int dead_pid = (unsigned int)kev. Ident; CFFileDescriptorInvalidate(fdref); CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example int our_pid = getpid(); // when our parent dies we die as well.. LOG_INFO(@"exit!
Parent process (pid %u) died. No need for us (pid %i) to stick around", dead_pid, our_pid); exit(EXIT_SUCCESS); } void suicide_if_we_become_a_zombie(int parent_pid) { // int parent_pid = getppid(); // int our_pid = getpid(); // LOG_ERROR(@"suicide_if_we_become_a_zombie(). Parent process (pid %u) that we monitor.
Our pid %i", parent_pid, our_pid); int fd = kqueue(); struct kevent kev; EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL); kevent(fd, &kev, 1, NULL, 0, NULL); CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, true, noteProcDeath, NULL); CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode); CFRelease(source); }.
Under POSIX, the exit(), _exit() and _Exit() functions are defined to: If the process is a controlling process, the SIGHUP signal shall be sent to each process in the foreground process group of the controlling terminal belonging to the calling process. 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() and setsid() and setpgrp() - to get the complete picture. (So would I!
).
2 Hmm. The documentation is vague and contradictory on this, but it appears that the parent process must be the lead process for the session, not just the process group. The lead process for the session was always login, and getting my process to take over as lead process for a new session was beyond my abilities at the moment.
– Schof Jan 10 '10 at 1:33 2 SIGHUP effectively only gets sent to child processes if the exiting process is a login shell. Opengroup.org/onlinepubs/009695399/functions/exit.html "Termination of a process does not directly terminate its children. The sending of a SIGHUP signal as described below indirectly terminates children /in some circumstances/.
" – Rob K Jul 6 '10 at 21:01 @Rob: correct - that's what the quote I gave says, too: that only in some circumstances does the child process get a SIGHUP. And it is strictly an over-simplification to say that it is only a login shell that sends SIGHUP, though that is the most common case. If a process with multiple children sets itself up as the controlling process for itself and its children, then the SIGHUP will (conveniently) be sent to its children when the master dies.
OTOH, processes seldom go to that much trouble - so I more more nit-picking than raising a really significant quibble. – Jonathan Leffler Jul 6 '10 at 22:36 I fooled around with it for a couple of hours and couldn't get it to work. It would have nicely handled a case where I have a daemon with some children that all need to die when the parent exits.
– Rob K Aug 17 '10 at 19:36.
If you're unable to modify the child process, you can try something like the following: int pipes2; pipe(pipes) if (fork() == 0) { close(pipes1); /* Close the writer end in the child*/ dup2(0, pipes0); /* Use reader end as stdin */ exec("sh -c 'set -o monitor; child_process & read dummy; kill %1'") } close(pipes0); /* Close the reader end in the parent */ This runs the child from within a shell process with job control enabled. The child process is spawned in the background. The shell waits for a newline (or an EOF) then kills the child.
When the parent dies--no matter what the reason--it will close its end of the pipe. The child shell will get an EOF from the read and proceed to kill the backgrounded child process.
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: check_parent () { parent=`ps -f|awk '$2=='$PID'{print $3 }'` echo "parent:$parent" let parent=$parent+0 if $parent -eq 1 ; then echo "parent is dead, exiting" exit; fi } PID=$$ cnt=0 while 1 = 1 ; do check_parent ... something done.
I think a quick and dirty way is to create a pipe between child and parent. When parent exits, children will receive a SIGPIPE.
If you send a signal to the pid 0, using for instance kill(0, 2); /* SIGINT */ that signal is sent to the entire process group, thus effectively killing the child. You can test it easily with something like: (cat && kill 0) | python If you then press ^D, you'll see the text "Terminated" as an indication that the Python interpreter have indeed been killed, instead of just exited because of stdin being closed.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.