def terminateProcess(
pid, done, *, term_after=0.0, quit_after=5.0, kill_after=10.0):
"""Terminate the given process.
A "sensible" way to terminate a process. Does the following:
1. Sends SIGTERM to the process identified by `pid`.
2. Waits for up to 5 seconds.
3. Sends SIGQUIT to the process *group* of process `pid`.
4. Waits for up to an additional 5 seconds.
5. Sends SIGKILL to the process *group* of process `pid`.
Steps #3 and #5 have a safeguard: if the process identified by `pid` has
the same process group as the invoking process the signal is sent only to
the process and not to the process group. This prevents the caller from
inadvertently killing itself. For best effect, ensure that new processes
become process group leaders soon after spawning.
:param pid: The PID to terminate.
:param done: A `Deferred` that fires when the process exits.
"""
ppgid = os.getpgrp()
def kill(sig):
"""Attempt to send `signal` to the given `pid`."""
try:
_os_kill(pid, sig)
except ProcessLookupError:
pass # Already exited.
def killpg(sig):
"""Attempt to send `signal` to the progress group of `pid`.
If `pid` is running in the same process group as the invoking process,
this falls back to using kill(2) instead of killpg(2).
"""
try:
pgid = os.getpgid(pid)
if pgid == ppgid:
_os_kill(pid, sig)
else:
_os_killpg(pgid, sig)
except ProcessLookupError:
pass # Already exited.
killers = (
reactor.callLater(term_after, kill, signal.SIGTERM),
reactor.callLater(quit_after, killpg, signal.SIGQUIT),
reactor.callLater(kill_after, killpg, signal.SIGKILL),
)
def ended():
for killer in killers:
if killer.active():
killer.cancel()
done.addBoth(callOut, ended)
评论列表
文章目录