I am writing a simple process management module in Python. The module can run and kill processes and it must work independently of a single runtime, i.e., a process started in process A could be killed from process B. My current code looks like this:
class Proc:
def __init__(self, cmd):
self.cmd = cmd
self.pid = None
def run(self):
proc = subprocess.Popen(self.cmd)
self.pid = proc.pid
proc.communicate()
self.pid = None
return proc.returncode
def kill(self, sig: int = signal.SIGINT):
if not self.pid:
return
proc = psutil.Process(self.pid)
if self._process_matches_self(proc):
proc.send_signal(sig)
def _process_matches_self(self, proc):
return proc.cmdline() == self.cmd
As you might notice, this code is not very safe. For example, if my process terminates just after if not self.pid
was evaluated and another process with the same PID and command-line starts, the user might kill the wrong process — even though this might be very unlikely.
I would like to calculate a hash value for the started process containing the command-line, environment, working directory, process ID and start time. However, even if I do it immediately after subprocess.Popen
, it could suffer from the same race condition: if the started process returns immediately, psutil.Process
might get the wrong process and I would calculate the hash value for the wrong process.
Is there any way to make this more atomic? As far as I know, psutil
cannot start processes, while subprocess.Popen
only has very bare-bone process properties. Is there any better way to do this?