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: else:
subprocess.Popen.__del__(self) subprocess.Popen.__del__(self)
def kill(self): def kill(self, sig=None):
self.returncode = 0 self.returncode = 0
if isWin: if isWin:
if not self._ignore_children and self._handle and self._job: if not self._ignore_children and self._handle and self._job:
@ -126,20 +126,18 @@ class ProcessHandlerMixin(object):
self._cleanup() self._cleanup()
if err is not None: if err is not None:
raise OSError(err) raise OSError(err)
else:
pass
else: else:
sig = sig or signal.SIGKILL
if not self._ignore_children: if not self._ignore_children:
try: try:
os.killpg(self.pid, signal.SIGKILL) os.killpg(self.pid, sig)
except BaseException, e: except BaseException, e:
if getattr(e, "errno", None) != 3: if getattr(e, "errno", None) != 3:
# Error 3 is "no such process", which is ok # 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 print >> sys.stdout, "Could not kill process, could not find pid: %s, assuming it's already dead" % self.pid
else: else:
os.kill(self.pid, signal.SIGKILL) os.kill(self.pid, sig)
if self.returncode is None: self.returncode = -sig
self.returncode = subprocess.Popen._internal_poll(self)
self._cleanup() self._cleanup()
return self.returncode return self.returncode
@ -417,7 +415,7 @@ falling back to not using job objects for managing child processes"""
threadalive = self._procmgrthread.is_alive() threadalive = self._procmgrthread.is_alive()
else: else:
threadalive = self._procmgrthread.isAlive() threadalive = self._procmgrthread.isAlive()
if self._job and threadalive: if self._job and threadalive:
# Then we are managing with IO Completion Ports # Then we are managing with IO Completion Ports
# wait on a signal so we know when we have seen the last # wait on a signal so we know when we have seen the last
# process come through. # process come through.
@ -643,7 +641,7 @@ falling back to not using job objects for managing child processes"""
self.processOutput(timeout=timeout, outputTimeout=outputTimeout) self.processOutput(timeout=timeout, outputTimeout=outputTimeout)
def kill(self): def kill(self, sig=None):
""" """
Kills the managed process. 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, Note that this does not manage any state, save any output etc,
it immediately kills the process. it immediately kills the process.
:param sig: Signal used to kill the process, defaults to SIGKILL
(has no effect on Windows)
""" """
try: try:
return self.proc.kill() return self.proc.kill(sig=sig)
except AttributeError: except AttributeError:
# Try to print a relevant error message. # Try to print a relevant error message.
if not self.proc: if not self.proc:

View File

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

View File

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

View File

@ -70,17 +70,25 @@ class Runner(object):
""" """
Wait for the process to exit. Wait for the process to exit.
Returns the process return code if the process exited, 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. :param timeout: if not None, will return after timeout seconds.
Use is_running() to determine whether or not a timeout occured. Use is_running() to determine whether or not a
Timeout is ignored if interactive was set to True. timeout occured. Timeout is ignored if
interactive was set to True.
""" """
if self.process_handler is not None: if self.process_handler is not None:
if isinstance(self.process_handler, subprocess.Popen): if isinstance(self.process_handler, subprocess.Popen):
self.returncode = self.process_handler.wait() self.returncode = self.process_handler.wait()
else: else:
self.process_handler.wait(timeout) 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() self.returncode = self.process_handler.proc.poll()
if self.returncode is not None: if self.returncode is not None:
self.process_handler = None self.process_handler = None
@ -96,13 +104,16 @@ class Runner(object):
return self.process_handler is not None return self.process_handler is not None
def stop(self): def stop(self, sig=None):
""" """
Kill the process 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: if self.process_handler is None:
return return
self.process_handler.kill() self.returncode = self.process_handler.kill(sig=sig)
self.process_handler = None self.process_handler = None
def reset(self): def reset(self):