I have a program spawning and communicating with CPU heavy, unstable processes, not created by me. If my app crashes or is killed by SIGKILL
, I want the subprocesses to get killed as well, so the user don´t have to track them down and kill them manually.
I know this topic has been covered before, but I have tried all methods described, and none of them seem to live up to survive the test.
I know it must be possible, since terminals do it all the time. If I run something in a terminal, and kill the terminal, the stuff always dies.
I have tried atexit
, double fork and ptys
. atexit
doesn't work for sigkill
; double fork doesn't work at all; and ptys
I have found no way to work with using python.
Today, I found out about prctl(PR_SET_PDEATHSIG, SIGKILL)
, which should be a way for child processes to order a kill on themselves, when their parent dies.
I tried to use it with popen
, but it seams to have no effect at all:
import ctypes, subprocess
libc = ctypes.CDLL('/lib/libc.so.6')
PR_SET_PDEATHSIG = 1; TERM = 15
implant_bomb = lambda: libc.prctl(PR_SET_PDEATHSIG, TERM)
subprocess.Popen(['gnuchess'], preexec_fn=implant_bomb)
In the above, the child is created and the parent exits. Now you would expect gnuchess
to receive a SIGKILL
and die, but it doesn't. I can still find it in my process manager using 100% CPU.
Can anybody tell me if there is something wrong with my use of prctl
?,
or do you know how terminals manage to kill their children?
I know it's been years, but I found a simple (slightly hacky) solution to this problem. From your parent process, wrapping all your calls around a very simple C program that calls prctl() and then exec() solves this problem on Linux. I call it "yeshup":
#include <linux/prctl.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, char **argv) {
if(argc < 2)
return 1;
prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
return execvp(argv[1], &argv[1]);
}
When spawning your child processes from Python (or any other language), you can run "yeshup gnuchess [argments]." You'll find that, when the parent process is killed, all your child processes (should) be given SIGHUP nicely.
This works because Linux will honor the call to prctl (not clear it) even after execvp is called (which effectively "transforms" the yeshup process into a gnuchess process, or whatever command you specify there), unlike fork().