]> granicus.if.org Git - python/commitdiff
Fixes issue #14396: Handle the odd rare case of waitpid returning 0
authorGregory P. Smith <greg@krypto.org>
Sun, 11 Nov 2012 05:06:18 +0000 (21:06 -0800)
committerGregory P. Smith <greg@krypto.org>
Sun, 11 Nov 2012 05:06:18 +0000 (21:06 -0800)
when not expected in subprocess.Popen.wait().

1  2 
Lib/subprocess.py
Misc/NEWS

index 57cc1a4a7d562298bc642e311bf8d19a29fd1ddd,35a98c8969055b66529d4f6448a391a113b73a13..296613ac0b79ce608744838b4a21d2740bd9a93b
@@@ -1466,52 -1425,24 +1466,56 @@@ class Popen(object)
              return self.returncode
  
  
 -        def wait(self):
 +        def _try_wait(self, wait_flags):
 +            try:
 +                (pid, sts) = _eintr_retry_call(os.waitpid, self.pid, wait_flags)
 +            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.
 +                pid = self.pid
 +                sts = 0
 +            return (pid, sts)
 +
 +
 +        def wait(self, timeout=None, endtime=None):
              """Wait for child process to terminate.  Returns returncode
              attribute."""
 -            while self.returncode is None:
 -                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.
 -                    pid = self.pid
 -                    sts = 0
 -                # Check the pid and loop as waitpid has been known to return
 -                # 0 even without WNOHANG in odd situations.  issue14396.
 -                if pid == self.pid:
 -                    self._handle_exitstatus(sts)
 +            if self.returncode is not None:
 +                return self.returncode
 +
 +            # endtime is preferred to timeout.  timeout is only used for
 +            # printing.
 +            if endtime is not None or timeout is not None:
 +                if endtime is None:
 +                    endtime = _time() + timeout
 +                elif timeout is None:
 +                    timeout = self._remaining_time(endtime)
 +
 +            if endtime is not None:
 +                # Enter a busy loop if we have a timeout.  This busy loop was
 +                # cribbed from Lib/threading.py in Thread.wait() at r71065.
 +                delay = 0.0005 # 500 us -> initial delay of 1 ms
 +                while True:
 +                    (pid, sts) = self._try_wait(os.WNOHANG)
 +                    assert pid == self.pid or pid == 0
 +                    if pid == self.pid:
 +                        self._handle_exitstatus(sts)
 +                        break
 +                    remaining = self._remaining_time(endtime)
 +                    if remaining <= 0:
 +                        raise TimeoutExpired(self.args, timeout)
 +                    delay = min(delay * 2, remaining, .05)
 +                    time.sleep(delay)
-             elif self.returncode is None:
-                 (pid, sts) = self._try_wait(0)
-                 self._handle_exitstatus(sts)
++            else:
++                while self.returncode is None:
++                    (pid, sts) = self._try_wait(0)
++                    # Check the pid and loop as waitpid has been known to return
++                    # 0 even without WNOHANG in odd situations.  issue14396.
++                    if pid == self.pid:
++                        self._handle_exitstatus(sts)
              return self.returncode
  
  
diff --cc Misc/NEWS
index 44e0da20cfde1accce81a184d65ea016da24eda4,a4f765a68990495e2e0d82ef37b4ebc5f0f5e526..dea9c8ab6747c0dd7244edbfc38c020e44e7d699
+++ b/Misc/NEWS
@@@ -83,6 -165,6 +83,9 @@@ Core and Builtin
  Library
  -------
  
++- Issue #14396: Handle the odd rare case of waitpid returning 0 when not
++  expected in subprocess.Popen.wait().
++
  - Issue #16411: Fix a bug where zlib.decompressobj().flush() might try to access
    previously-freed memory. Patch by Serhiy Storchaka.