SIGKILL to a subprocess tree on parent termination

Viewed 319

I have a daemon application that starts several 3rd party executables (all closed-sources and non modifiable).

I would like to have all the child processes to automatically terminate when the parent exits for any reason (including crashes).

Currently, I am using prctl to achieve this (see also this question):

int ret = fork();
if (ret == 0) {
    //Setup other stuff
    prctl (PR_SET_PDEATHSIG, SIGKILL);

    if (execve( "childexecutable" ) < 0) { /*signal error*/}
}

However, if "childexecutable" also forks and spawns "grandchildren", then "grandchildren" is not killed when my process exits.

Maybe I could create an intermediate process that serves as subreaper, that would then kill "someexecutable" when my process dies, but then wait for SIGCHLD and continue to kill child processes until none is left, but it seems very brittle.

Are there better solutions?

1 Answers

Creating a subreaper is not useful in this case, your grandchildren would be reparented to and reaped by init anyway.

What you could do however is:

  1. Start a parent process and fork a child immediately.
  2. The parent will simply wait for the child.
  3. The child will carry out all the work of your actual program, including spawning any other children via fork + execve.
  4. Upon exit of the child for any reason (including deathly signals e.g. a crash) the parent can issue kill(0, SIGKILL) or killpg(getpgid(0), SIGKILL) to kill all the processes in its process group. Issuing a SIGINT/SIGTERM before SIGKILL would probably be a better idea depending on what child processes you want to run, as they could handle such signals and do a graceful cleanup of used resources (including children) before exiting.

Assuming that none of the children or grandchildren changes their process group while running, this will kill the entire tree of processes upon exit of your program. You could also keep the PR_SET_PDEATHSIG before any execve to make this more robust. Again depending on the processes you want to run a PR_SET_PDEATHSIG with SIGINT/SIGTERM could make more sense than SIGKILL.

You can issue setpgid(getpid(), 0) before doing any of the above to create a new process group for your program and avoid killing any parents when issuing kill(0, SIGKILL).

The logic of the "parent" process should be really simple, just a fork + wait in a loop + kill upon the right condition returned by wait. Of course, if this process crashes too then all bets are off, so take care in writing simple and reliable code.

Related