How to programmatically destroy a process tree in Linux using C

I am trying to write a function that spawns a child process, allows it to run for a certain time, and then kills it if it has not ended:

int sysExecTimeout(const char * exePath, int timeoutSec); 

In the function, I use fork and execl to spawn a child, and when it expires, I use kill(pid, SIGTERM) and kill(pid, SIGKILL) after 2 seconds to ensure that the child dies:

 pid_t pid = fork(); if(pid == 0) { execl("/bin/sh", "sh", "-c", exePath); exit(127); } else if(pid != -1) { // timeout code if(timeout) { kill(pid, SIGTERM); sleep(2); kill(pid, SIGKILL); } } 

I use Linux, and it seems that when the parent process dies, the child does not kill automatically. Thus, two kill calls will simply kill the /bin/sh process and leave the exePath command running, since it is a child of /bin/sh .

I am trying to write the sysExecTimeout function so that it destroys the entire process tree rooted in pid , where pid is the PID from pid = fork()

I need this because the exePath command will spawn other commands that can also spawn other commands that can get stuck and consume resources.

I have no control over exePath executable binaries / scripts, so I cannot write my own parent matrix-dll-kill-the-children.

I tried using kill(0, SIGTERM) , which almost completed the task, except that it also killed my own process :)

I am wondering if there is a flag that I can programmatically include in C that says β€œhey when I die, take all my children, kill them and repeat them recursively for my children” so that the whole process tree from this program starts, it dies (when provided that the PID / PPID chain can be followed).

I could use this flag here:

 if(pid == 0) { turnOnRecursiveDeathFlag(); system(exePath); //execl("/bin/sh", "sh", "-c", exePath); exit(127); } 

Is there any way to do this? I searched for a while, but all I can find is hacks using ps -ef , or modifying the child processes you use, etc.

+4
source share
1 answer

Use setpgid in the child element to set its GPID equal to its own PID. Then the parent can kill (-pid, ...) to signal the entire group.

 pid_t pid = fork(); if(pid == 0) { setpgid(0, 0); execl("/bin/sh", "sh", "-c", exePath); exit(127); } else if(pid == -1) { // timeout code if(timeout) { kill(-pid, SIGTERM); sleep(2); kill(-pid, SIGKILL); } } 

That should do it.

One more thing when you create a shell, make sure that it does not include task management. Otherwise, it will create its own process groups. Your "/ bin / sh -c" is fine.

+10
source

All Articles