1

I would like to create a subprocess via subprocess.Popen that starts in a suspended state so I can have it ready to run at a later point.

I found a solution for Linux here but couldn't find any solution for Windows. Does anyone know if there's a Windows equivalent to this?

sj95126
  • 6,520
  • 2
  • 15
  • 34
Lafonz
  • 23
  • 6
  • Your question comes down to [How to suspend/resume a process in Windows](https://stackoverflow.com/questions/11010165/how-to-suspend-resume-a-process-in-windows) and then how to call SuspendThread from the Windows API from Python, which you can do with `pywin32`. It's not going to be easy though - why do you want to do this in the first place? What problem are you actually solving? "so I can have it ready to run at a later point" - why not prepare everything you need to start the process, but not actually start the process until you need it? – Grismar Aug 26 '22 at 22:13
  • I would like to cleanup any orphaned child processes when the parent process dies which I don't believe happens by default in Popen. After looking into it I found [this link](https://stackoverflow.com/a/23587108/10671703) which mentions using Windows JobObjects to handle orphaned children. They gave some sample code and mentioned there is a race condition with their solution. In the comments of that post someone mentioned suspending a process before attaching it to a JobObject would fix that racecondition. I would prefer to avoid raceconditions but I'm aware this may not be the best solution. – Lafonz Aug 26 '22 at 22:20
  • 2
    As the author of that answer says "a tiny race condition here in case the child dies in between the Popen and OpenProcess calls, you can decide whether you want to worry about that" - the odds of that happening are vanishingly small. If you are worried about it, wrap the child process with a launcher that simply doesn't launch if its parent is dead before it starts, no need to muck around with suspended processes. (and of course all that assuming you're not actually writing the launched process, otherwise it can just check on its parent itself) – Grismar Aug 26 '22 at 23:21
  • Thanks for the help! I think wrapping the child process seems like it'll be my best bet since I'm not writing the launched process. – Lafonz Aug 29 '22 at 15:53

1 Answers1

0

After some more investigation I managed to create a suspended process and resume it later. Creating a suspended process using Popen and Windows is thankfully pretty simple.

First you will need to install pywin32 by running:

pip install pywin32

Once pywin32 is installed you can create a suspended process with subprocess.Popen by using:

from win32process import CREATE_SUSPENDED
from subprocess import Popen

pipe = subprocess.Popen(<command>, <**kwargs>, creationflags=CREATE_SUSPENDED)

Resuming this suspended process, however, is quite a bit more difficult since it requires a PyHandle for the suspended thread. Unfortunately Popen doesn't return a Thread ID which is required to open a PyHandle for the suspended thread. As a work-around I ended up monkeypatching Popen's _execute_child function to store the Thread ID returned by _winapi.CreateProcess. Now that we have the suspended process' Thread ID we can resume the thread.

To resume a suspended process assuming you monkeypatched Popen to store the Thread ID use:

from win32api import OpenThread, CloseHandle
from win32con import THREAD_SUSPEND_RESUME
from win32process import ResumeThread

thread_handle = OpenThread(THREAD_SUSPEND_RESUME, <inherit handle (T/F)>, pipe.tid)
ResumeThread(thread_handle)
CloseHandle(thread_handle)

If anyone knows a way to get the Thread ID from Popen without monkeypatching _execute_child or any better methods of suspending and resuming a process please share!

Resources:

I also created a wrapper for subprocess.Popen that kills the child process when the parent dies if anyone would like to see my specific implementation.

Lafonz
  • 23
  • 6