From b740e76af01bdd34e53d3c03b812e452f5d9a4e8 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Tue, 14 Dec 2010 15:16:24 +0000 Subject: Merged revisions 87233 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r87233 | gregory.p.smith | 2010-12-14 06:38:00 -0800 (Tue, 14 Dec 2010) | 4 lines Issue #1731717: Fixed the problem where subprocess.wait() could cause an OSError exception when The OS had been told to ignore SIGCLD in our process or otherwise not wait for exiting child processes. ........ --- Lib/subprocess.py | 16 ++++++++++++++-- Lib/test/subprocessdata/sigchild_ignore.py | 6 ++++++ Lib/test/test_subprocess.py | 11 +++++++++++ Misc/NEWS | 4 ++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 Lib/test/subprocessdata/sigchild_ignore.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 0dd55e0..5684d52 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1149,7 +1149,11 @@ class Popen(object): os.close(errpipe_read) if data: - _eintr_retry_call(os.waitpid, self.pid, 0) + try: + _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError as e: + if e.errno != errno.ECHILD: + raise child_exception = pickle.loads(data) for fd in (p2cwrite, c2pread, errread): if fd is not None: @@ -1195,7 +1199,15 @@ class Popen(object): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: - pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + try: + pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError as e: + if e.errno != errno.ECHILD: + raise + # This happens if SIGCLD is set to be ignored or waiting + # for child processes has otherwise been disabled for our + # process. This child is dead, we can't get the status. + sts = 0 self._handle_exitstatus(sts) return self.returncode diff --git a/Lib/test/subprocessdata/sigchild_ignore.py b/Lib/test/subprocessdata/sigchild_ignore.py new file mode 100644 index 0000000..1d03303 --- /dev/null +++ b/Lib/test/subprocessdata/sigchild_ignore.py @@ -0,0 +1,6 @@ +import signal, subprocess, sys +# On Linux this causes os.waitpid to fail with OSError as the OS has already +# reaped our child process. The wait() passing the OSError on to the caller +# and causing us to exit with an error is what we are testing against. +signal.signal(signal.SIGCLD, signal.SIG_IGN) +subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait() diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 2379b3e..adf00a5 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -793,6 +793,17 @@ class ProcessTestCase(BaseTestCase): stdout = stdout.rstrip(b'\n\r') self.assertEqual(stdout, value_repr) + def test_wait_when_sigchild_ignored(self): + # NOTE: sigchild_ignore.py may not be an effective test on all OSes. + sigchild_ignore = support.findfile("sigchild_ignore.py", + subdir="subprocessdata") + p = subprocess.Popen([sys.executable, sigchild_ignore], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + self.assertEqual(0, p.returncode, "sigchild_ignore.py exited" + " non-zero with this error:\n%s" % stderr) + + # # Windows tests # diff --git a/Misc/NEWS b/Misc/NEWS index 0f9a785..058b02a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,10 @@ Library - Issue #10464: netrc now correctly handles lines with embedded '#' characters. +- Issue #1731717: Fixed the problem where subprocess.wait() could cause an + OSError exception when The OS had been told to ignore SIGCLD in our process + or otherwise not wait for exiting child processes. + Extensions ---------- -- cgit v0.12