Commit 560cbec1 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Handle ESRCH when sending signals



Upon sending signals, ESRCH can be reported when the target no
longer exists.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent c51580b3
......@@ -459,7 +459,7 @@ class ChildProcess(subprocess.Popen):
"""
logging.info("Sending signal %s to child process", signum)
os.killpg(self.pid, signum)
utils.IgnoreProcessNotFound(os.killpg, self.pid, signum)
def ForceQuit(self):
"""Ensure child process is no longer running.
......
......@@ -2764,7 +2764,7 @@ def AbortImportExport(name):
if pid:
logging.info("Import/export %s is running with PID %s, sending SIGTERM",
name, pid)
os.kill(pid, signal.SIGTERM)
utils.IgnoreProcessNotFound(os.kill, pid, signal.SIGTERM)
def CleanupImportExport(name):
......
......@@ -344,6 +344,7 @@ class ChildIOProcessor(object):
raise
# Process no longer exists
logging.debug("dd exited")
self._dd_pid = None
return True
......
......@@ -2342,8 +2342,7 @@ def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
"""
def _helper(pid, signal_, wait):
"""Simple helper to encapsulate the kill/waitpid sequence"""
os.kill(pid, signal_)
if wait:
if IgnoreProcessNotFound(os.kill, pid, signal_) and wait:
try:
os.waitpid(pid, os.WNOHANG)
except OSError:
......@@ -3122,6 +3121,26 @@ def RunInSeparateProcess(fn, *args):
return bool(exitcode)
def IgnoreProcessNotFound(fn, *args, **kwargs):
"""Ignores ESRCH when calling a process-related function.
ESRCH is raised when a process is not found.
@rtype: bool
@return: Whether process was found
"""
try:
fn(*args, **kwargs)
except EnvironmentError, err:
# Ignore ESRCH
if err.errno == errno.ESRCH:
return False
raise
return True
def IgnoreSignals(fn, *args, **kwargs):
"""Tries to call a function ignoring failures due to EINTR.
......
......@@ -2393,5 +2393,27 @@ class TestFormatSeconds(unittest.TestCase):
self.assertEqual(utils.FormatSeconds(3912.8), "1h 5m 13s")
class RunIgnoreProcessNotFound(unittest.TestCase):
@staticmethod
def _WritePid(fd):
os.write(fd, str(os.getpid()))
os.close(fd)
return True
def test(self):
(pid_read_fd, pid_write_fd) = os.pipe()
# Start short-lived process which writes its PID to pipe
self.assert_(utils.RunInSeparateProcess(self._WritePid, pid_write_fd))
os.close(pid_write_fd)
# Read PID from pipe
pid = int(os.read(pid_read_fd, 1024))
os.close(pid_read_fd)
# Try to send signal to process which exited recently
self.assertFalse(utils.IgnoreProcessNotFound(os.kill, pid, 0))
if __name__ == '__main__':
testutils.GanetiTestProgram()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment