Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kill a process tree programmatically on Linux using C

I am trying to write a function that spawns a child process, lets it run for a certain amount of time and then kills it if it hasn't finished:

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

In the function, I use fork and execl to spawn the child, and, when it times out, I use kill(pid, SIGTERM) and kill(pid, SIGKILL) after 2 seconds, to ensure 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 am using Linux, and it seems that when a parent process dies, the child is not killed automatically. So the two kill calls will just kill the /bin/sh process and leave the exePath command running, since it is a child process of /bin/sh.

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

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

I do not have control over the exePath binaries/scripts that get executed, so I cannot write my own parent-dies-so-kill-the-children logic in them.

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

I am wondering if there is a flag I can turn on programatically in C that says "hey man, when I die, take all my children and kill them, and repeat recursively for their children" such that the entire process tree started from that program dies (assuming the PID/PPID chain can be followed).

I could use that flag here:

if(pid == 0) {
    turnOnRecursiveDeathFlag();

    system(exePath);
    //execl("/bin/sh", "sh", "-c", exePath);
    exit(127);
}

Is there a way to do that? I've been searching for a while, but all I can find are hacks using ps -ef, or modifying the children processes that you are running etc.

like image 823
Alin Tomescu Avatar asked Mar 28 '13 21:03

Alin Tomescu


People also ask

How do I kill a bunch of processes in Linux?

killall Command – kill the processes by name. By default, it will send a TERM signal. The killall command can kill multiple processes with a single command. If more than one process runs with that name, all of them will be killed.

How do you kill a process tree?

If you select the process at the top of the tree you want kill, then press F9 followed by Enter it will close the process and the entire process tree in one go. In the screen shot below this action would cause Chrome and all sub process to be closed.


1 Answers

Use setpgid in the child to set its GPID equal to its own PID. The parent then 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 spawn a shell, make sure it doesn't enable job control. Otherwise, it will create its own process groups. Your "/bin/sh -c" is fine.

like image 174
DoxyLover Avatar answered Oct 10 '22 17:10

DoxyLover