Thanks! That's exactly what I was looking for. A little more
background:
"If sig is 0 (the null signal), error checking is performed but no
signal is actually sent. The null signal can be used to check the
validity of pid."
Taken from :
http://www.opengroup.org/onlinepubs/009695399/functions/kill.html
Here are the functions I wrote with this information. There are three
functions:
kill() is similar to os.kill, but returns True if the pid is dead and
throws less exceptions
dead() checks if a process is dead, and gets rid of zombies if
necessary
goodkill() kills a pid by sending gradually harser signals until dead.
def kill(pid, signal=0):
"""sends a signal to a process
returns True if the pid is dead
with no signal argument, sends no signal"""
#if 'ps --no-headers' returns no lines, the pid is dead
from os import kill
try: return kill(pid, signal)
except OSError, e:
#process is dead
if e.errno == 3: return True
#no permissions
elif e.errno == 1: return False
else: raise
def dead(pid):
if kill(pid): return True
#maybe the pid is a zombie that needs us to wait4 it
from os import waitpid, WNOHANG
try: dead = waitpid(pid, WNOHANG)[0]
except OSError, e:
#pid is not a child
if e.errno == 10: return False
else: raise
return dead
#def kill(pid, sig=0): pass #DEBUG: test hang condition
def goodkill(pid, interval=1, hung=20):
"let process die gracefully, gradually send harsher signals if
necessary"
from signal import SIGTERM, SIGINT, SIGHUP, SIGKILL
from time import sleep
for signal in [SIGTERM, SIGINT, SIGHUP]:
if kill(pid, signal): return
if dead(pid): return
sleep(interval)
i = 0
while True:
#infinite-loop protection
if i < hung: i += 1
else:
print "Process %s is hung. Giving up kill." % pid
return
if kill(pid, SIGKILL): return
if dead(pid): return
sleep(interval)