Skip to content

bpo-37410: subprocess closes the process handle when done #14391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,13 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
self.pid = pid
_winapi.CloseHandle(ht)


def _set_returncode(self, exitcode):
self.returncode = exitcode
self._handle.Close()
self._handle = None


def _internal_poll(self, _deadstate=None,
_WaitForSingleObject=_winapi.WaitForSingleObject,
_WAIT_OBJECT_0=_winapi.WAIT_OBJECT_0,
Expand All @@ -1313,7 +1320,8 @@ def _internal_poll(self, _deadstate=None,
"""
if self.returncode is None:
if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0:
self.returncode = _GetExitCodeProcess(self._handle)
exitcode = _GetExitCodeProcess(self._handle)
self._set_returncode(exitcode)
return self.returncode


Expand All @@ -1329,7 +1337,8 @@ def _wait(self, timeout):
timeout_millis)
if result == _winapi.WAIT_TIMEOUT:
raise TimeoutExpired(self.args, timeout)
self.returncode = _winapi.GetExitCodeProcess(self._handle)
exitcode = _winapi.GetExitCodeProcess(self._handle)
self._set_returncode(exitcode)
return self.returncode


Expand Down Expand Up @@ -1417,7 +1426,7 @@ def terminate(self):
rc = _winapi.GetExitCodeProcess(self._handle)
if rc == _winapi.STILL_ACTIVE:
raise
self.returncode = rc
self._set_returncode(rc)

kill = terminate

Expand Down Expand Up @@ -1638,7 +1647,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
try:
pid, sts = os.waitpid(self.pid, 0)
if pid == self.pid:
self._handle_exitstatus(sts)
self._set_returncode(sts)
else:
self.returncode = sys.maxsize
except ChildProcessError:
Expand Down Expand Up @@ -1674,7 +1683,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
raise child_exception_type(err_msg)


def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED,
def _set_returncode(self, sts, _WIFSIGNALED=os.WIFSIGNALED,
_WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED,
_WEXITSTATUS=os.WEXITSTATUS, _WIFSTOPPED=os.WIFSTOPPED,
_WSTOPSIG=os.WSTOPSIG):
Expand Down Expand Up @@ -1711,7 +1720,7 @@ def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid,
return self.returncode # Another thread waited.
pid, sts = _waitpid(self.pid, _WNOHANG)
if pid == self.pid:
self._handle_exitstatus(sts)
self._set_returncode(sts)
except OSError as e:
if _deadstate is not None:
self.returncode = _deadstate
Expand Down Expand Up @@ -1758,7 +1767,7 @@ def _wait(self, timeout):
(pid, sts) = self._try_wait(os.WNOHANG)
assert pid == self.pid or pid == 0
if pid == self.pid:
self._handle_exitstatus(sts)
self._set_returncode(sts)
break
finally:
self._waitpid_lock.release()
Expand All @@ -1777,7 +1786,7 @@ def _wait(self, timeout):
# return 0 even without WNOHANG in odd situations.
# http://bugs.python.org/issue14396.
if pid == self.pid:
self._handle_exitstatus(sts)
self._set_returncode(sts)
return self.returncode


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
On Windows, :class:`subprocess.Popen` now closes the process handle when the
process completes. Previously, it was only closed when the Popen object was
destroyed.