Bug 947974 - Add signal parameter to mozprocess.kill(), r=wlach

This commit is contained in:
Andrew Halberstadt 2014-01-24 16:26:57 -05:00
parent aaf5ba8518
commit 3c22e1b527
4 changed files with 38 additions and 21 deletions

View File

@ -110,7 +110,7 @@ class ProcessHandlerMixin(object):
else:
subprocess.Popen.__del__(self)
def kill(self):
def kill(self, sig=None):
self.returncode = 0
if isWin:
if not self._ignore_children and self._handle and self._job:
@ -127,19 +127,17 @@ class ProcessHandlerMixin(object):
if err is not None:
raise OSError(err)
else:
pass
else:
sig = sig or signal.SIGKILL
if not self._ignore_children:
try:
os.killpg(self.pid, signal.SIGKILL)
os.killpg(self.pid, sig)
except BaseException, e:
if getattr(e, "errno", None) != 3:
# Error 3 is "no such process", which is ok
print >> sys.stdout, "Could not kill process, could not find pid: %s, assuming it's already dead" % self.pid
else:
os.kill(self.pid, signal.SIGKILL)
if self.returncode is None:
self.returncode = subprocess.Popen._internal_poll(self)
os.kill(self.pid, sig)
self.returncode = -sig
self._cleanup()
return self.returncode
@ -643,7 +641,7 @@ falling back to not using job objects for managing child processes"""
self.processOutput(timeout=timeout, outputTimeout=outputTimeout)
def kill(self):
def kill(self, sig=None):
"""
Kills the managed process.
@ -654,9 +652,12 @@ falling back to not using job objects for managing child processes"""
Note that this does not manage any state, save any output etc,
it immediately kills the process.
:param sig: Signal used to kill the process, defaults to SIGKILL
(has no effect on Windows)
"""
try:
return self.proc.kill()
return self.proc.kill(sig=sig)
except AttributeError:
# Try to print a relevant error message.
if not self.proc:

View File

@ -23,7 +23,8 @@ class ProcTestKill(proctest.ProcTest):
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
p.didTimeout,
expectedfail=('returncode',))
def test_process_kill_deep(self):
"""Process is started, we kill it, we use a deep process tree"""
@ -37,7 +38,8 @@ class ProcTestKill(proctest.ProcTest):
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
p.didTimeout,
expectedfail=('returncode',))
def test_process_kill_deep_wait(self):
"""Process is started, we use a deep process tree, we let it spawn
@ -54,7 +56,8 @@ class ProcTestKill(proctest.ProcTest):
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
p.didTimeout,
expectedfail=('returncode',))
def test_process_kill_broad(self):
"""Process is started, we kill it, we use a broad process tree"""
@ -68,7 +71,8 @@ class ProcTestKill(proctest.ProcTest):
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
p.didTimeout,
expectedfail=('returncode',))
if __name__ == '__main__':
unittest.main()

View File

@ -29,7 +29,8 @@ class ProcTestKill(proctest.ProcTest):
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
p.didTimeout,
expectedfail=('returncode',))
if __name__ == '__main__':
unittest.main()

View File

@ -70,17 +70,25 @@ class Runner(object):
"""
Wait for the process to exit.
Returns the process return code if the process exited,
returns None otherwise.
returns -<signal> if the process was killed (Unix only)
returns None if the process is still running.
If timeout is not None, will return after timeout seconds.
Use is_running() to determine whether or not a timeout occured.
Timeout is ignored if interactive was set to True.
:param timeout: if not None, will return after timeout seconds.
Use is_running() to determine whether or not a
timeout occured. Timeout is ignored if
interactive was set to True.
"""
if self.process_handler is not None:
if isinstance(self.process_handler, subprocess.Popen):
self.returncode = self.process_handler.wait()
else:
self.process_handler.wait(timeout)
if not self.process_handler:
# the process was killed by another thread
return self.returncode
# the process terminated, retrieve the return code
self.returncode = self.process_handler.proc.poll()
if self.returncode is not None:
self.process_handler = None
@ -96,13 +104,16 @@ class Runner(object):
return self.process_handler is not None
def stop(self):
def stop(self, sig=None):
"""
Kill the process
:param sig: Signal used to kill the process, defaults to SIGKILL
(has no effect on Windows).
"""
if self.process_handler is None:
return
self.process_handler.kill()
self.returncode = self.process_handler.kill(sig=sig)
self.process_handler = None
def reset(self):