Archive for February, 2008

Fighting zombies with a double fork

February 12, 2008

No, this post is not about a special weapon against Romero’s undeads (though that would be cool :), but about a trick I’ve just discovered after a lot of struggling with child processes that aren’t properly reaped by their parent.
Let me try to be a bit more specific: suppose you have a parent that needs to spawn two kinds of child processes. Processes of the first kind perform a computation and return to the parent immediately (so they are handled via a fork+exec+waitpid combination), while those of the second kind should be started, their pid recorded so that they may be killed later, and then forgotten.
The question is: how to handle the second kind of subprocesses? If you just fork+exec, when you later kill them, you get zombie processes. If you ignore SIGCHLD (so auto-reaping is enabled) you can’t perform a blocking wait on the children of the first kind anymore. Handling SIGCHLD is perhaps possible, but I think you need to keep track of the PIDs of the spawned processes and do some magic in the handler. I didn’t manage to make this working.

What I did manage to get working is the following: just spawn the process in a temporary child process. This way the grandchild will be orphaned and won’t require a wait from its grandfather.

There are however some problems with this approach. Namely, the child needs to send the PID of its own child to the parent. I’ve accomplished that through a pipe. Here is some example code to better illustrate this technique:

from subprocess import Popen, PIPE, STDOUT
import sys

def spawn(cmd):
    cmdline = ('python', __file__) + cmd
    return int(Popen(cmdline, stdout = PIPE).stdout.read())

if __name__ == '__main__':
    print Popen(sys.argv[1:], stdout = open('/dev/null', 'w'), stderr = STDOUT).pid
    sys.exit(0)

Follow

Get every new post delivered to your Inbox.