karlosss karlosss - 3 months ago 19
Linux Question

Check if a process is still running

I have the following problem:

I need my Python script run a bash script. In case the bash script is running more than let's say 10 seconds, I need to kill it. This is what I have so far:

cmd = ["bash", "script.sh", self.get_script_path()]
process = subprocess.Popen(cmd)

time.sleep(10) # process running here...

procinfo = psutil.Process(process.pid)
children = procinfo.children(recursive=True)
for child in children:
os.kill(child.pid, signal.SIGKILL)


The thing I am afraid of is this scenario: The bash script finishes in 1 second, frees its PID and the system passes the PID to another process. After 10 seconds, I kill the PID which I think it belongs to my script but it is not true and I kill some other process. The script needs to be run as root because I require
chroot
in it.

Any ideas?

Answer

Since you are already using psutil I suggest you replace the calls to the subprocess module with calls to psutil.Popen. This class has the same interface of subprocess.Popen but provides all the functionality of psutil.Process.

Also note that the psutil library pre-emptively checks for PID reuse already, at least for a number of methods including terminate and kill (just read the documentation for Process).

This means that the following code:

cmd = ["bash", "script.sh", self.get_script_path()]
process = psutil.Popen(cmd)

time.sleep(10)  # process running here...

children = process.children(recursive=True)
for child in children:
    child.terminate()   # try to close the process "gently" first
    child.kill()

Note that the documentation for children says:

children(recursive=False)

Return the children of this process as a list of Process objects, preemptively checking whether PID has been reused.

In summary this means that:

  1. When you call children the psutil library checks that you want the children of the correct process and not one that happen to have the same pid
  2. When you call terminate or kill the library makes sure that you are killing your child process and not a random process with the same pid.