Ensuring child processes die on exit with PrCtl

25 November 2012

One issue you encounter when writing software which starts child processes is making sure the children terminate when the parent does. If the child processes are well behaved, or if the parent always exits cleanly under controlled conditions, this might not be much of an issue. But if you find youself stuck working with other, badly behaved software (looking at you PhantomJS) there is a simple solution in the form of Linux’s prctl module.

This module allows a process to specify a signal it should be sent when its parent dies, which you should do after forking the child process but before exec’ing the external code. Python’s subprocess module provides a hook for exactly this purpose (the preexec_fn argument to Popen). And, while the stdlib doesn’t provide a native interface to prctl, ctypes comes to the resuce.

Putting it all together, the following snippet of code does the business:

import signal
from ctypes import cdll

# Constant taken from http://linux.die.net/include/linux/prctl.h
PR_SET_PDEATHSIG = 1

class PrCtlError(Exception):
    pass

def on_parent_exit(signame):
    """
    Return a function to be run in a child process which will trigger
    SIGNAME to be sent when the parent process dies
    """
    signum = getattr(signal, signame)
    def set_parent_exit_signal():
        # http://linux.die.net/man/2/prctl
        result = cdll['libc.so.6'].prctl(PR_SET_PDEATHSIG, signum)
        if result != 0:
            raise PrCtlError('prctl failed with error code %s' % result)
    return set_parent_exit_signal

Usage is simple:

subprocess.Popen(['some-executable'], preexec_fn=on_parent_exit('SIGTERM'))

Canonical version is available as a Gist.

comments powered by Disqus