Index: Lib/popen2.py =================================================================== --- Lib/popen2.py (revision 43241) +++ Lib/popen2.py (working copy) @@ -8,6 +8,7 @@ import os import sys +import errno __all__ = ["popen2", "popen3", "popen4"] @@ -75,26 +76,36 @@ finally: os._exit(1) + def _wait_on_pid(self, flag): + try: + pid, sts = os.waitpid(self.pid, flag) + child_is_dead = pid == self.pid + except os.error, e: + # If the child no longer exists, it must have been waited on + # by someone else. We don't know what the status is, + # but we want to stop polling, so set to zero. + sts = 0 + child_is_dead = e.errno == errno.ECHILD + + if child_is_dead: + self.sts = sts + try: + _active.remove(self) + except ValueError: + # We must have been removed by another thread, just ignore. + pass + def poll(self): """Return the exit status of the child process if it has finished, or -1 if it hasn't finished yet.""" if self.sts < 0: - try: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - if pid == self.pid: - self.sts = sts - _active.remove(self) - except os.error: - pass + self._wait_on_pid(os.WNOHANG) return self.sts def wait(self): """Wait for and return the exit status of the child process.""" if self.sts < 0: - pid, sts = os.waitpid(self.pid, 0) - if pid == self.pid: - self.sts = sts - _active.remove(self) + self._wait_on_pid(0) return self.sts