how to kill process and child processes from python? - python

for example from bash:
kill -9 -PID
os.kill(pid, signal.SIGKILL) kill only parent process.

If the parent process is not a "process group" but you want to kill it with the children, you can use psutil (https://psutil.readthedocs.io/en/latest/#processes). os.killpg cannot identify pid of a non-process-group.
import psutil
parent_pid = 30437 # my example
parent = psutil.Process(parent_pid)
for child in parent.children(recursive=True): # or parent.children() for recursive=False
child.kill()
parent.kill()

When you pass a negative PID to kill, it actually sends the signal to the process group by that (absolute) number. You do the equivalent with os.killpg() in Python.

Another solution if your process is not a process group and you don't want to use psutil, is to run this shell command:
pkill -TERM -P 12345
For instance with
os.system('pkill -TERM -P {pid}'.format(pid=12345))

None of answers can helped me, so I made some research and wrote my answer:
you can easily do it using os module, but it is platform sensitive. This mean that some commands are availiable only on Unix, some - on any platform.
So my project starts one Process, and several Child processes in the different places and times. Some of Child starts Grand-Child Processes :)
So I found this solution:
import os
import signal
import platform
# get the current PID for safe terminate server if needed:
PID = os.getpid()
if platform.system() is not 'Windows':
PGID = os.getpgid(PID)
if platform.system() is not 'Windows':
os.killpg(PGID, signal.SIGKILL)
else:
os.kill(PID, signal.SIGTERM)
I use SIGKILL on Linux, to kill process immediatly, and SIGTERM on Windows, because there is no SIGKILL on it.
Also I used killpg() to kill the whole group of processes on Linux.
P.S. Check on Linux, but still doesn't check on Windows, so maybe we need one more additional command for Windows (for example CTRL_C_EVENT or use another answer.)

you should use signal parameter 9 to kill the process tree.
root#localhost:~$ python
>>> import os
>>> os.kill(pid, 9)
if you should use signal.SIGKILL constant, you should use os.killpg(pgid, signal.SIGKILL) to kill the process tree.

I don't know if this is what you asked for, but if you wish to kill other processes of your application and they were all created using multiprocessing package you can do something like this:
import multiprocessing
from time import sleep
...
def on_shutdown():
for child in multiprocessing.active_children():
print('Terminating', child)
child.terminate()
sleep(0.5)

def kill_children_processes(pid):
# TODO: Find a way to not have to use a kill -9.
processes = os.popen("ps -ej | grep -i 'python' | grep -v 'grep' | awk '{ print $2,$3 }'").read()
processes = [p.split(" ") for p in processes.split("\n")[:-1]]
processes = "\n".join([child for child, parent in processes if parent == str(pid) and child != str(pid)])
if processes:
logger.debug(f"Killing ghost processes {processes}")
os.system(f"kill -9 {processes}")

Related

How can I kill multiple processes at once in python?

I have a python script that is responsible for verifying the existence of a process with its respective name, I am using the pip module pgrep, the problem is that it does not allow me to kill the processes with the kill module of pip or with the of os.kill because there are several processes that I want to kill and these are saved in list, for example
pid = [2222, 4444, 6666]
How could you kill those processes at once? since the above modules don't give me results.
You would loop over processes using a for loop. Ideally you should send a SIGTERM before resorting to SIGKILL, because it can allow processes to exit more gracefully.
import time
import os
import signal
# send all the processes a SIGTERM
for p in pid:
os.kill(p, signal.SIGTERM)
# give them a short time to do any cleanup
time.sleep(2)
# in case still exist - send them a SIGKILL to definitively remove them
# if they are already exited, just ignore the error and carry on
for p in pid:
try:
os.kill(p, signal.SIGKILL)
except ProcessLookupError:
pass
Try this it may work
processes = {'pro1', 'pro2', 'pro3'}
for proc in psutil.process_iter():
if proc.name() in processes:
proc.kill()
For more information you can refer here

Running subprocess.run as root not working

I am trying to kill a subprocess via its pid by using subprocess.call() to do it. I obtain the pid by assigning return to a value like this:
return = subprocess.Popen(["sudo", "scrolling-text-example", "-y7"])
x= return.pid
When when I am ready to end this subprocess I am using this code:
subprocess.call(["sudo","kill",str(x)])
This does not kill the subprocess, but if I open terminal (let's say x is 1234), and type: sudo kill 1234 , it will kill the subprocess.
Use x = str(return pid) and subprocess.call(["sudo","kill","-9",x]) and then try to grant root privileges. And, this allows to turn the process number to a string before calling the subprocess. Also, as I mentioned, use -9 (or -15 if you prefer using that). (Try to kill 1014 process too).
I found that the main process I identify with x = return.pid actually runs a child process which is the one I needed to kill, so from the parent process identified, we need to kill a child processes. The addition of "-P" includes child processes in this situation.
The following command structure is what I needed:
subprocess.call(["sudo","pkill","-9","-P",x])

Python: how to kill child process(es) when parent dies?

The child process is started with
subprocess.Popen(arg)
Is there a way to ensure it is killed when parent terminates abnormally? I need this to work both on Windows and Linux. I am aware of this solution for Linux.
Edit:
the requirement of starting a child process with subprocess.Popen(arg) can be relaxed, if a solution exists using a different method of starting a process.
Heh, I was just researching this myself yesterday! Assuming you can't alter the child program:
On Linux, prctl(PR_SET_PDEATHSIG, ...) is probably the only reliable choice. (If it's absolutely necessary that the child process be killed, then you might want to set the death signal to SIGKILL instead of SIGTERM; the code you linked to uses SIGTERM, but the child does have the option of ignoring SIGTERM if it wants to.)
On Windows, the most reliable options is to use a Job object. The idea is that you create a "Job" (a kind of container for processes), then you place the child process into the Job, and you set the magic option that says "when no-one holds a 'handle' for this Job, then kill the processes that are in it". By default, the only 'handle' to the job is the one that your parent process holds, and when the parent process dies, the OS will go through and close all its handles, and then notice that this means there are no open handles for the Job. So then it kills the child, as requested. (If you have multiple child processes, you can assign them all to the same job.) This answer has sample code for doing this, using the win32api module. That code uses CreateProcess to launch the child, instead of subprocess.Popen. The reason is that they need to get a "process handle" for the spawned child, and CreateProcess returns this by default. If you'd rather use subprocess.Popen, then here's an (untested) copy of the code from that answer, that uses subprocess.Popen and OpenProcess instead of CreateProcess:
import subprocess
import win32api
import win32con
import win32job
hJob = win32job.CreateJobObject(None, "")
extended_info = win32job.QueryInformationJobObject(hJob, win32job.JobObjectExtendedLimitInformation)
extended_info['BasicLimitInformation']['LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
win32job.SetInformationJobObject(hJob, win32job.JobObjectExtendedLimitInformation, extended_info)
child = subprocess.Popen(...)
# Convert process id to process handle:
perms = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA
hProcess = win32api.OpenProcess(perms, False, child.pid)
win32job.AssignProcessToJobObject(hJob, hProcess)
Technically, there's 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.
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.
If you can modify the child (e.g., like when using multiprocessing), then probably the best option is to somehow pass the parent's PID to the child (e.g. as a command line argument, or in the args= argument to multiprocessing.Process), and then:
On POSIX: Spawn a thread in the child that just calls os.getppid() occasionally, and if the return value ever stops matching the pid passed in from the parent, then call os._exit(). (This approach is portable to all Unixes, including OS X, while the prctl trick is Linux-specific.)
On Windows: Spawn a thread in the child that uses OpenProcess and os.waitpid. Example using ctypes:
from ctypes import WinDLL, WinError
from ctypes.wintypes import DWORD, BOOL, HANDLE
# Magic value from http://msdn.microsoft.com/en-us/library/ms684880.aspx
SYNCHRONIZE = 0x00100000
kernel32 = WinDLL("kernel32.dll")
kernel32.OpenProcess.argtypes = (DWORD, BOOL, DWORD)
kernel32.OpenProcess.restype = HANDLE
parent_handle = kernel32.OpenProcess(SYNCHRONIZE, False, parent_pid)
# Block until parent exits
os.waitpid(parent_handle, 0)
os._exit(0)
This avoids any of the possible issues with job objects that I mentioned.
If you want to be really, really sure, then you can combine all these solutions.
Hope that helps!
The Popen object offers the terminate and kill methods.
https://docs.python.org/2/library/subprocess.html#subprocess.Popen.terminate
These send the SIGTERM and SIGKILL signals for you.
You can do something akin to the below:
from subprocess import Popen
p = None
try:
p = Popen(arg)
# some code here
except Exception as ex:
print 'Parent program has exited with the below error:\n{0}'.format(ex)
if p:
p.terminate()
UPDATE:
You are correct--the above code will not protect against hard-crashing or someone killing your process. In that case you can try wrapping the child process in a class and employ a polling model to watch the parent process.
Be aware psutil is non-standard.
import os
import psutil
from multiprocessing import Process
from time import sleep
class MyProcessAbstraction(object):
def __init__(self, parent_pid, command):
"""
#type parent_pid: int
#type command: str
"""
self._child = None
self._cmd = command
self._parent = psutil.Process(pid=parent_pid)
def run_child(self):
"""
Start a child process by running self._cmd.
Wait until the parent process (self._parent) has died, then kill the
child.
"""
print '---- Running command: "%s" ----' % self._cmd
self._child = psutil.Popen(self._cmd)
try:
while self._parent.status == psutil.STATUS_RUNNING:
sleep(1)
except psutil.NoSuchProcess:
pass
finally:
print '---- Terminating child PID %s ----' % self._child.pid
self._child.terminate()
if __name__ == "__main__":
parent = os.getpid()
child = MyProcessAbstraction(parent, 'ping -t localhost')
child_proc = Process(target=child.run_child)
child_proc.daemon = True
child_proc.start()
print '---- Try killing PID: %s ----' % parent
while True:
sleep(1)
In this example I run 'ping -t localhost' b/c that will run forever. If you kill the parent process, the child process (the ping command) will also be killed.
Since, from what I can tell, the PR_SET_PDEATHSIG solution can result in a deadlock when any threads are running in the parent process, I didn't want to use that and figured out another way. I created a separate auto-terminate process that detects when its parent process is done and kills the other subprocess that is its target.
To accomplish this, you need to pip install psutil, and then write code similar to the following:
def start_auto_cleanup_subprocess(target_pid):
cleanup_script = f"""
import os
import psutil
import signal
from time import sleep
try:
# Block until stdin is closed which means the parent process
# has terminated.
input()
except Exception:
# Should be an EOFError, but if any other exception happens,
# assume we should respond in the same way.
pass
if not psutil.pid_exists({target_pid}):
# Target process has already exited, so nothing to do.
exit()
os.kill({target_pid}, signal.SIGTERM)
for count in range(10):
if not psutil.pid_exists({target_pid}):
# Target process no longer running.
exit()
sleep(1)
os.kill({target_pid}, signal.SIGKILL)
# Don't bother waiting to see if this works since if it doesn't,
# there is nothing else we can do.
"""
return Popen(
[
sys.executable, # Python executable
'-c', cleanup_script
],
stdin=subprocess.PIPE
)
This is similar to https://stackoverflow.com/a/23436111/396373 that I had failed to notice, but I think the way that I came up with is easier for me to use because the process that is the target of cleanup is created directly by the parent. Also note that it is not necessary to poll the status of the parent, though it is still necessary to use psutil and to poll the status of the target subprocess during the termination sequence if you want to try, as in this example, to terminate, monitor, and then kill if terminate didn't work expeditiously.
Hook exit of your process using SetConsoleCtrlHandler, and kill subprocess. I think I do a bit of a overkill there, but it works :)
import psutil, os
def kill_proc_tree(pid, including_parent=True):
parent = psutil.Process(pid)
children = parent.children(recursive=True)
for child in children:
child.kill()
gone, still_alive = psutil.wait_procs(children, timeout=5)
if including_parent:
parent.kill()
parent.wait(5)
def func(x):
print("killed")
if anotherproc:
kill_proc_tree(anotherproc.pid)
kill_proc_tree(os.getpid())
import win32api,shlex
win32api.SetConsoleCtrlHandler(func, True)
PROCESSTORUN="your process"
anotherproc=None
cmdline=f"/c start /wait \"{PROCESSTORUN}\" "
anotherproc=subprocess.Popen(executable='C:\\Windows\\system32\\cmd.EXE', args=shlex.split(cmdline,posix="false"))
...
run program
...
Took kill_proc_tree from:
subprocess: deleting child processes in Windows

Kill process by ppid in python?

In python using: os.kill() will kill a process by pid using a specified signal,
How would one go about killing all processes with the same ppid?
Let's say your parent process ID is 7773.
I haven't done this myself, but you might try:
import subprocess
ppid = '7773'
subprocess.call(['pkill', '-STOP', '-P', ppid])
To get the ppid of the current process:
import os
ppid = os.getppid()
Perhaps there is a solution that is strictly python. If so, I don't know what it is.
EDIT: psutil
If you want a true python solution, the psutil package might have what you're looking for.

Kill a running subprocess call

I'm launching a program with subprocess on Python.
In some cases the program may freeze. This is out of my control. The only thing I can do from the command line it is launched from is CtrlEsc which kills the program quickly.
Is there any way to emulate this with subprocess? I am using subprocess.Popen(cmd, shell=True) to launch the program.
Well, there are a couple of methods on the object returned by subprocess.Popen() which may be of use: Popen.terminate() and Popen.kill(), which send a SIGTERM and SIGKILL respectively.
For example...
import subprocess
import time
process = subprocess.Popen(cmd, shell=True)
time.sleep(5)
process.terminate()
...would terminate the process after five seconds.
Or you can use os.kill() to send other signals, like SIGINT to simulate CTRL-C, with...
import subprocess
import time
import os
import signal
process = subprocess.Popen(cmd, shell=True)
time.sleep(5)
os.kill(process.pid, signal.SIGINT)
p = subprocess.Popen("echo 'foo' && sleep 60 && echo 'bar'", shell=True)
p.kill()
Check out the docs on the subprocess module for more info: http://docs.python.org/2/library/subprocess.html
You can use two signals to kill a running subprocess call i.e., signal.SIGTERM and signal.SIGKILL; for example
import subprocess
import os
import signal
import time
..
process = subprocess.Popen(..)
..
# killing all processes in the group
os.killpg(process.pid, signal.SIGTERM)
time.sleep(2)
if process.poll() is None: # Force kill if process is still alive
time.sleep(3)
os.killpg(process.pid, signal.SIGKILL)
Your question is not too clear, but If I assume that you are about to launch a process wich goes to zombie and you want to be able to control that in some state of your script. If this in the case, I propose you the following:
p = subprocess.Popen([cmd_list], shell=False)
This in not really recommanded to pass through the shell.
I would suggest you ti use shell=False, this way you risk less an overflow.
# Get the process id & try to terminate it gracefuly
pid = p.pid
p.terminate()
# Check if the process has really terminated & force kill if not.
try:
os.kill(pid, 0)
p.kill()
print "Forced kill"
except OSError, e:
print "Terminated gracefully"
Following command worked for me
os.system("pkill -TERM -P %s"%process.pid)
Try wrapping your subprocess.Popen call in a try except block. Depending on why your process is hanging, you may be able to cleanly exit. Here is a list of exceptions you can check for: Python 3 - Exceptions Handling

Categories