[Maya-Python] Kill child process on exit

2,132 views
Skip to first unread message

Marcus Ottosson

unread,
Mar 4, 2015, 8:10:52 AM3/4/15
to python_in...@googlegroups.com

Hi all,

I’d like something like this.

  1. Maya is launched
  2. A child process is launched; via e.g. subprocess.Popen
  3. Upon exiting Maya, I’d like the child process to be killed

Ideally, it dies no matter how the parent died; be it normally or when crashing. And ideally, it’d be cross-platform, and not rely on third-party module(s), though that’s flexible.

Here’s what I’ve got at the moment.

import atexit
import subprocess

proc = subprocess.Popen(["python"], creationflags=subprocess.CREATE_NEW_CONSOLE)

def kill_child():
    proc.kill()

atexit.register(kill_child)

This works standalone, and in Nuke, but not in Maya. It also doesn’t run when a process is force-quitted/crashed.

So I went a little deeper, looking into OS-specific methods of doing it and found this for Windows.

http://stackoverflow.com/a/23587108/478949

Which works, but relies on a library 25mb in size and quite elaborate bundling requirements.

So then I came across this, which provides an example (at the end) that I can’t quite wrap my head around, but seems to do what I want.

http://stefan.sofa-rockers.org/2013/08/15/handling-sub-process-hierarchies-python-linux-os-x/

But, I can’t successfully adapt it; mainly because I simply don’t understand it well enough. So I was hoping to get some pointers here, either about how to adapt it to my scenario or suggest alternatives.

Any ideas?

Best,
Marcus

--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Mar 4, 2015, 8:13:48 AM3/4/15
to python_in...@googlegroups.com
I might add that, from what I can tell, the Windows method of achieving this is apparently quite different and more difficult than the Unix version, so although Unix suggestions would be great, I'm mainly looking for a solution which works well on Windows; even if it's Windows-only.

Thanks

Justin Israel

unread,
Mar 4, 2015, 8:54:24 PM3/4/15
to python_in...@googlegroups.com
Hey,

I was reading your question a certain way at first (which is more complicated) and posed it to a colleague since he loves process management questions. He actually read it the other way, and gave me an answer that addresses how to manage the standard parent-child relationship where Maya is started, and Maya then launches a subprocess.

The way I had actually read it was that you had some process that first launched Maya, and then also launched another subprocess, and you wanted those two child processes linked.

Can you confirm which one that was?



On Thu, Mar 5, 2015 at 2:13 AM Marcus Ottosson <konstr...@gmail.com> wrote:
I might add that, from what I can tell, the Windows method of achieving this is apparently quite different and more difficult than the Unix version, so although Unix suggestions would be great, I'm mainly looking for a solution which works well on Windows; even if it's Windows-only.

Thanks

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmODST502Tu2093d2fJ4zxMm1eZaC2BkjYxTqjv21MhmXjQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Marcus Ottosson

unread,
Mar 5, 2015, 3:24:00 AM3/5/15
to python_in...@googlegroups.com
Good point, it is the other way; A launches B which launches C. That is, Maya launches the child process.​

Justin Israel

unread,
Mar 5, 2015, 4:44:49 PM3/5/15
to python_in...@googlegroups.com

Ok yea, then that is what my colleague thought you meant. His solution looks like this, but it is linux-only:

import signal

import subprocess
from ctypes import cdll

libc = cdll.LoadLibrary('libc.so.6')

child = subprocess.Popen(["/bin/sleep", "100"], preexec_fn=lambda *args: libc.prctl(1, signal.SIGTERM, 0, 0, 0))

That would use the C prctrl to set the child death signal to SIGTERM when the parent dies.

So yea, it isn’t portable, and you would have to search for whatever the equivalent is in Windows or BSD. That is probably why you might have to just take on a cross-platform library that handles this stuff.

On Thu, Mar 5, 2015 at 9:23 PM Marcus Ottosson <konstr...@gmail.com> wrote:

Good point, it is the other way; A launches B which launches C. That is, Maya launches the child process.​

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Marcus Ottosson

unread,
Mar 5, 2015, 4:52:39 PM3/5/15
to python_in...@googlegroups.com
Yeah, that's not particularly Windows-friendly unfortunately, and I don't know of any cross-platform library that does this. Thanks for sharing anyway.

Justin Israel

unread,
Mar 5, 2015, 4:59:55 PM3/5/15
to python_in...@googlegroups.com
Does this solution help?


It uses the Windows "Job Object" constructs. 


On Fri, Mar 6, 2015 at 10:52 AM Marcus Ottosson <konstr...@gmail.com> wrote:
Yeah, that's not particularly Windows-friendly unfortunately, and I don't know of any cross-platform library that does this. Thanks for sharing anyway.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmODL%3DOPW-whTiYiMiHAPsEhTJyiGm%3DHjNMc2nLR8-ea08Q%40mail.gmail.com.

Marcus Ottosson

unread,
Mar 5, 2015, 5:17:44 PM3/5/15
to python_in...@googlegroups.com

That’s actually the same solution I posted in my initial post, and it’s based on a non-standard library (pywin32) which is a little tricky to bundle and is quite large, but yes, based on only a few tests, it seems to do the job.

It seems to differ across Windows distributions though.

From the stackoverflow post:

One downside to using a job object is that when running on Vista or Win7, if your program is launched from the Windows shell (i.e., by clicking on an icon), then there will probably already be a job object assigned and trying to create a new job object will fail. Win8 fixes this (by allowing job objects to be nested), or if your program is run from the command line then it should be fine.

Would you mind having a gander at this and see what you can make of it?

http://stefan.sofa-rockers.org/2013/08/15/handling-sub-process-hierarchies-python-linux-os-x/#example

It’s the recursive nature of how the script launches itself that throws me off, but other than that the results look to be what I’m after.

Justin Israel

unread,
Mar 5, 2015, 8:20:52 PM3/5/15
to python_in...@googlegroups.com
On Fri, Mar 6, 2015 at 11:17 AM Marcus Ottosson <konstr...@gmail.com> wrote:

That’s actually the same solution I posted in my initial post, and it’s based on a non-standard library (pywin32) which is a little tricky to bundle and is quite large, but yes, based on only a few tests, it seems to do the job.

It seems to differ across Windows distributions though.


Sorry, I didn't realize I was posting the same suggestion. It seems like if you don't want to carry a large external dependency, you would have to drop down into doing your own basic ctypes solution for window.
 

From the stackoverflow post:

One downside to using a job object is that when running on Vista or Win7, if your program is launched from the Windows shell (i.e., by clicking on an icon), then there will probably already be a job object assigned and trying to create a new job object will fail. Win8 fixes this (by allowing job objects to be nested), or if your program is run from the command line then it should be fine.

Would you mind having a gander at this and see what you can make of it?

http://stefan.sofa-rockers.org/2013/08/15/handling-sub-process-hierarchies-python-linux-os-x/#example

It’s the recursive nature of how the script launches itself that throws me off, but other than that the results look to be what I’m after.


The logic with the script calling itself is just purely for the example of having it spawn a child which spawns a child, to demonstrate the signal handling. With that aside, it is just basic signal handling of watching for INT/TERM(/BREAK). The problem is that it won't solve your requirement for handling Maya crashing because the child will just end up orphaned (I'm not totally familiar on the process handling in windows). The problem you are trying to solve is getting a signal from the parent to the child if the parent actually dies, which as you are finding requires some non-portable solutions. 
 

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Mar 6, 2015, 10:46:17 AM3/6/15
to python_in...@googlegroups.com

No problem, Justin, it’s not terribly obvious that it’s using pywin32 as it isn’t showing up in the imports; it looks like it’s got quite a few different names, all prefixed win32.

A ctypes approach seems reasonable. Haven’t considered it beyond a few non-working examples, but I bet it must be able to deal with Job objects too.

Other than that, there is one detail about my requirements which might enable another method or achieving what I want; which is that the child is just another Python interpreter under my control. So what I could do is pass the pid of the parent to the child and have it poll every n-seconds for whether the parent is still running. If not, clean-up and self-destruct.

Though polling a process for activity seems a challenge on it’s own.. (on Windows, that is. Sigh)

Fredrik Averpil

unread,
Mar 6, 2015, 1:58:25 PM3/6/15
to python_in...@googlegroups.com
I think you can poll a pid using psutil. Check out its Process class.

// F
--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Justin Israel

unread,
Mar 6, 2015, 3:36:17 PM3/6/15
to python_in...@googlegroups.com

On posix, the value of the parent pid changes if it dies and the child orphans , to either 1 or 0. Not sure what the behaviour is on Windows. You would have to be careful about trying to poll exactly for a specific pid of the parent since it is possible for the pid to get reused.
The actual polling should be really easy, even without psutil, just using the "os" module and a thread.


Justin Israel

unread,
Mar 6, 2015, 4:18:47 PM3/6/15
to python_in...@googlegroups.com
Nevermind on what I said about psutil. On windows its a heavy handed operation to get a parent process id, or check if a pid exists because process management on windows is harder. So yea polling with psutil in a thread may be the only cross platform approach. I found a windows approach that mimics what psutil does, using ctypes if you want to try and avoid a dependency: 


On Sat, Mar 7, 2015 at 9:36 AM Justin Israel <justin...@gmail.com> wrote:

On posix, the value of the parent pid changes if it dies and the child orphans , to either 1 or 0. Not sure what the behaviour is on Windows. You would have to be careful about trying to poll exactly for a specific pid of the parent since it is possible for the pid to get reused.
The actual polling should be really easy, even without psutil, just using the "os" module and a thread.


On Sat, 7 Mar 2015 7:58 AM Fredrik Averpil <fredrik...@gmail.com> wrote:
I think you can poll a pid using psutil. Check out its Process class.

// F
fre 6 mar 2015 kl. 16:46 skrev Marcus Ottosson <konstr...@gmail.com>:

No problem, Justin, it’s not terribly obvious that it’s using pywin32 as it isn’t showing up in the imports; it looks like it’s got quite a few different names, all prefixed win32.

A ctypes approach seems reasonable. Haven’t considered it beyond a few non-working examples, but I bet it must be able to deal with Job objects too.

Other than that, there is one detail about my requirements which might enable another method or achieving what I want; which is that the child is just another Python interpreter under my control. So what I could do is pass the pid of the parent to the child and have it poll every n-seconds for whether the parent is still running. If not, clean-up and self-destruct.

Though polling a process for activity seems a challenge on it’s own.. (on Windows, that is. Sigh)

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Marcus Ottosson

unread,
Mar 7, 2015, 2:22:53 PM3/7/15
to python_in...@googlegroups.com

Thanks a lot, guys. psutil is looking amazing so far.

I mean, how cool is this?

# Kill children of process id 1234

import psutil

for child in psutil.Process(1234).children():
    child.kill()

For polling, I’m thinking something like this will suffice.

psutil.Process(1234).wait()
sys.exit()

On windows its a heavy handed operation to get a parent process id

I did find a pretty straightforward way to do this:

import os
os.getpid()

Until a better solution pops up, this fits the bill I think.

Thanks!

Justin Israel

unread,
Mar 7, 2015, 2:48:49 PM3/7/15
to python_in...@googlegroups.com


On Sun, 8 Mar 2015 8:22 AM Marcus Ottosson <konstr...@gmail.com> wrote:

Thanks a lot, guys. psutil is looking amazing so far.

I mean, how cool is this?

# Kill children of process id 1234 import psutil for child in psutil.Process(1234).children(): child.kill()

For polling, I’m thinking something like this will suffice.

psutil.Process(1234).wait() sys.exit()

On windows its a heavy handed operation to get a parent process id


I did find a pretty straightforward way to do this:

import os os.getpid()

Not heavy to get the pid of the current process. Heavy to do the whole parent process lookup. From the win32 calls, it looked like psutil needed to cache the ppid because it involves pulling all processes and comparing the id. psutil does it all in its windows specific code

Until a better solution pops up, this fits the bill I think.

Thanks!

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmOCGn0MFu1zvvqJLuuAVOv9e8ZP%2BXmHWJos8s9NfYgp08g%40mail.gmail.com.

Reply all
Reply to author
Forward
0 new messages