gh-112736: Refactor del-safe symbol handling in subprocess (#112738)

Refactor delete-safe symbol handling in subprocess.

Only module globals are force-cleared during interpreter finalization, using a class reference instead of individually listing the constants everywhere is simpler.
This commit is contained in:
Russell Keith-Magee 2023-12-05 12:23:17 +08:00 committed by GitHub
parent 304a1b3f3a
commit dc824c5dc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 24 deletions

View File

@ -74,8 +74,8 @@ except ModuleNotFoundError:
else: else:
_mswindows = True _mswindows = True
# wasm32-emscripten and wasm32-wasi do not support processes # some platforms do not support subprocesses
_can_fork_exec = sys.platform not in {"emscripten", "wasi"} _can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"}
if _mswindows: if _mswindows:
import _winapi import _winapi
@ -103,18 +103,22 @@ else:
if _can_fork_exec: if _can_fork_exec:
from _posixsubprocess import fork_exec as _fork_exec from _posixsubprocess import fork_exec as _fork_exec
# used in methods that are called by __del__ # used in methods that are called by __del__
_waitpid = os.waitpid class _del_safe:
_waitstatus_to_exitcode = os.waitstatus_to_exitcode waitpid = os.waitpid
_WIFSTOPPED = os.WIFSTOPPED waitstatus_to_exitcode = os.waitstatus_to_exitcode
_WSTOPSIG = os.WSTOPSIG WIFSTOPPED = os.WIFSTOPPED
_WNOHANG = os.WNOHANG WSTOPSIG = os.WSTOPSIG
WNOHANG = os.WNOHANG
ECHILD = errno.ECHILD
else: else:
_fork_exec = None class _del_safe:
_waitpid = None waitpid = None
_waitstatus_to_exitcode = None waitstatus_to_exitcode = None
_WIFSTOPPED = None WIFSTOPPED = None
_WSTOPSIG = None WSTOPSIG = None
_WNOHANG = None WNOHANG = None
ECHILD = errno.ECHILD
import select import select
import selectors import selectors
@ -1951,20 +1955,16 @@ class Popen:
raise child_exception_type(err_msg) raise child_exception_type(err_msg)
def _handle_exitstatus(self, sts, def _handle_exitstatus(self, sts, _del_safe=_del_safe):
_waitstatus_to_exitcode=_waitstatus_to_exitcode,
_WIFSTOPPED=_WIFSTOPPED,
_WSTOPSIG=_WSTOPSIG):
"""All callers to this function MUST hold self._waitpid_lock.""" """All callers to this function MUST hold self._waitpid_lock."""
# This method is called (indirectly) by __del__, so it cannot # This method is called (indirectly) by __del__, so it cannot
# refer to anything outside of its local scope. # refer to anything outside of its local scope.
if _WIFSTOPPED(sts): if _del_safe.WIFSTOPPED(sts):
self.returncode = -_WSTOPSIG(sts) self.returncode = -_del_safe.WSTOPSIG(sts)
else: else:
self.returncode = _waitstatus_to_exitcode(sts) self.returncode = _del_safe.waitstatus_to_exitcode(sts)
def _internal_poll(self, _deadstate=None, _waitpid=_waitpid, def _internal_poll(self, _deadstate=None, _del_safe=_del_safe):
_WNOHANG=_WNOHANG, _ECHILD=errno.ECHILD):
"""Check if child process has terminated. Returns returncode """Check if child process has terminated. Returns returncode
attribute. attribute.
@ -1980,13 +1980,13 @@ class Popen:
try: try:
if self.returncode is not None: if self.returncode is not None:
return self.returncode # Another thread waited. return self.returncode # Another thread waited.
pid, sts = _waitpid(self.pid, _WNOHANG) pid, sts = _del_safe.waitpid(self.pid, _del_safe.WNOHANG)
if pid == self.pid: if pid == self.pid:
self._handle_exitstatus(sts) self._handle_exitstatus(sts)
except OSError as e: except OSError as e:
if _deadstate is not None: if _deadstate is not None:
self.returncode = _deadstate self.returncode = _deadstate
elif e.errno == _ECHILD: elif e.errno == _del_safe.ECHILD:
# This happens if SIGCLD is set to be ignored or # This happens if SIGCLD is set to be ignored or
# waiting for child processes has otherwise been # waiting for child processes has otherwise been
# disabled for our process. This child is dead, we # disabled for our process. This child is dead, we

View File

@ -0,0 +1 @@
The use of del-safe symbols in ``subprocess`` was refactored to allow for use in cross-platform build environments.