Index: subprocess.py =================================================================== --- subprocess.py (revision 39605) +++ subprocess.py (working copy) @@ -411,13 +411,19 @@ True = 1 _active = [] def _cleanup(): for inst in _active[:]: - inst.poll() + if inst.poll(_deadstate=sys.maxint) >= 0: + try: + _active.remove(inst) + except ValueError: + # This can happen if two threads create a new Popen instance. + # It's harmless that it was already removed, so ignore. + pass PIPE = -1 STDOUT = -2 def call(*popenargs, **kwargs): @@ -589,19 +595,26 @@ if errread: if universal_newlines: self.stderr = os.fdopen(errread, 'rU', bufsize) else: self.stderr = os.fdopen(errread, 'rb', bufsize) - _active.append(self) - def _translate_newlines(self, data): data = data.replace("\r\n", "\n") data = data.replace("\r", "\n") return data + + + def __del__(self): + # In case the child hasn't been waited on, check if it's done. + self.poll(_deadstate=sys.maxint) + if self.returncode is None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + def communicate(self, input=None): """Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data @@ -792,29 +805,27 @@ if c2pwrite is not None: c2pwrite.Close() if errwrite is not None: errwrite.Close() - def poll(self): + def poll(self, _deadstate=None): """Check if child process has terminated. Returns returncode attribute.""" if self.returncode is None: if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: self.returncode = GetExitCodeProcess(self._handle) - _active.remove(self) return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: obj = WaitForSingleObject(self._handle, INFINITE) self.returncode = GetExitCodeProcess(self._handle) - _active.remove(self) return self.returncode def _readerthread(self, fh, buffer): buffer.append(fh.read()) @@ -1039,25 +1050,24 @@ elif os.WIFEXITED(sts): self.returncode = os.WEXITSTATUS(sts) else: # Should never happen raise RuntimeError("Unknown child exit status!") - _active.remove(self) - def poll(self): """Check if child process has terminated. Returns returncode attribute.""" if self.returncode is None: try: pid, sts = os.waitpid(self.pid, os.WNOHANG) if pid == self.pid: self._handle_exitstatus(sts) except os.error: - pass + if _deadstate is not None: + self.returncode = _deadstate return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute."""