Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I found myself getting very confused a while back by some changes that I found when moving Python scripts from Linux over to OS X...

On Linux, if a Python script has called os.system(), and the calling process is killed, the called process will be killed at the same time.

On OS X, however, if the main process is killed, anything that it launched is left behind.

Is there something somewhere in OS X/Python where I can change this behaviour?

This is causing problems on our render farm, where the processes can be killed from the management GUI, but the top level process is really just a wrapper, so, while the render farm management might think that the process has gone and the machine is freed up for another task, the actual processor-intensive task is still running, which can lead to huge blockages.

I know that I could write more logic to catch the kill signal and pass it on to the child processes, but I was hoping that it might be something that could be enabled at a lower level.

share|improve this question
There is nothing inherent in the relationship established by generic system(3) that would propagate signals from a process to its children. Orphaned processes will be adopted by init(8) (or launchd(8) on Mac OS X), but are not otherwise directly affected by losing their parent. There may be auxiliary relationships that cause an orphaned child to exit, though (e.g. if there was a pipe between the parent and the child, the child may get an EPIPE from read(2)/write(2)/etc. or receive a SIGPIPE which might cause it to exit/die). – Chris Johnsen Jan 24 '10 at 8:03
Perhaps process groups are involved. If the Python process were the process group leader for itself and its child, then you could killpg(2)/killpg(3) its PID to send a signal to both it and its child. How, exactly, are you starting and killing the Python process? Are you using a shell? Which shell? Does you shell exec the Python process? Which kill are you using? (shell-builtin-kill/kill(1)/kill(2)) Are you using a negative PID? (indicates killpg-style usage) Are you using killpg(2)/killpg(3) directly? – Chris Johnsen Jan 24 '10 at 9:05
I'm not actually sure, to be perfectly honest - it's another application that's doing the killing. I think what I need to do is catch the kill signal in my script and make sure it's passed on to all subprocesses. The initial python processes are launched through tcsh. – Hugh Jan 24 '10 at 11:58
Sure, as long as it is not SIGKILL, you could catch it and pass it along to the child. But if you want to isolate the difference between the platforms, you need to gather more information. You said that tcsh (ick) is starting the Python wrapper process. Is it done with the exec command prefix, or is it just a regular command in a script? On the kill side, you might use something like strace (Linux) or ktrace+kdump (Mac OS X) to find out how the signal is being sent (kill/killpg? negative PID argument?). These will give clues for further investigations. – Chris Johnsen Jan 24 '10 at 13:02
Will take a look and see... Thanks for the tips! – Hugh Jan 24 '10 at 18:18
up vote 4 down vote accepted

On Linux, when you kill a parent the child gets sent a SIGHUP which will generally kill it unless it was meant to stay alive as a daemon in which case it will trap sighup. (I think this is why one usually uses SIGHUP to tell a daemon to refresh itself, since it's conveniently always trapped).

On Mac OS X I can't find documentation, but it appears that no SIGHUP gets sent. As a result, the child process is orphaned, and its new parent is the grandparent.

The way you deal with this is you send the kill signal to the process group of the parent, not the parent process itself. This will nuke all the children and grand children as well with one caveat. If any child process does a setpgrp() or setsid() then it escapes the process group membership. It will not get the kill sent to its old process group. Usually one need not worry about the latter since it's usually intentional when used to achieve that purpose.

share|improve this answer
That sounds great - I'll have a look and give it a go - thanks – Hugh May 20 '10 at 10:01
You can write a simple shell test proving that a signal is not passed to a child. The child will simply be adopted by init, as explained above by Chris Johnsen. Also, sighup is not meant to refresh a deamon, unless the deamon was specifically designed to do so. The default process behavior is to exit when it receives sighup. – Philippe A. Feb 1 '12 at 20:09

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.