mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-88887: Cleanup multiprocessing.resource_tracker.ResourceTracker
upon deletion (#130429)
Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
parent
00a9844888
commit
f53e7de6a8
2 changed files with 46 additions and 21 deletions
|
@ -75,29 +75,53 @@ class ResourceTracker(object):
|
|||
raise ReentrantCallError(
|
||||
"Reentrant call into the multiprocessing resource tracker")
|
||||
|
||||
def _stop(self):
|
||||
with self._lock:
|
||||
# This should not happen (_stop() isn't called by a finalizer)
|
||||
# but we check for it anyway.
|
||||
if self._lock._recursion_count() > 1:
|
||||
return self._reentrant_call_error()
|
||||
if self._fd is None:
|
||||
# not running
|
||||
return
|
||||
|
||||
# closing the "alive" file descriptor stops main()
|
||||
os.close(self._fd)
|
||||
self._fd = None
|
||||
|
||||
_, status = os.waitpid(self._pid, 0)
|
||||
|
||||
self._pid = None
|
||||
def __del__(self):
|
||||
# making sure child processess are cleaned before ResourceTracker
|
||||
# gets destructed.
|
||||
# see https://github.com/python/cpython/issues/88887
|
||||
self._stop(use_blocking_lock=False)
|
||||
|
||||
def _stop(self, use_blocking_lock=True):
|
||||
if use_blocking_lock:
|
||||
with self._lock:
|
||||
self._stop_locked()
|
||||
else:
|
||||
acquired = self._lock.acquire(blocking=False)
|
||||
try:
|
||||
self._exitcode = os.waitstatus_to_exitcode(status)
|
||||
except ValueError:
|
||||
# os.waitstatus_to_exitcode may raise an exception for invalid values
|
||||
self._exitcode = None
|
||||
self._stop_locked()
|
||||
finally:
|
||||
if acquired:
|
||||
self._lock.release()
|
||||
|
||||
def _stop_locked(
|
||||
self,
|
||||
close=os.close,
|
||||
waitpid=os.waitpid,
|
||||
waitstatus_to_exitcode=os.waitstatus_to_exitcode,
|
||||
):
|
||||
# This shouldn't happen (it might when called by a finalizer)
|
||||
# so we check for it anyway.
|
||||
if self._lock._recursion_count() > 1:
|
||||
return self._reentrant_call_error()
|
||||
if self._fd is None:
|
||||
# not running
|
||||
return
|
||||
if self._pid is None:
|
||||
return
|
||||
|
||||
# closing the "alive" file descriptor stops main()
|
||||
close(self._fd)
|
||||
self._fd = None
|
||||
|
||||
_, status = waitpid(self._pid, 0)
|
||||
|
||||
self._pid = None
|
||||
|
||||
try:
|
||||
self._exitcode = waitstatus_to_exitcode(status)
|
||||
except ValueError:
|
||||
# os.waitstatus_to_exitcode may raise an exception for invalid values
|
||||
self._exitcode = None
|
||||
|
||||
def getfd(self):
|
||||
self.ensure_running()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fixing multiprocessing Resource Tracker process leaking, usually observed when running Python as PID 1.
|
Loading…
Add table
Add a link
Reference in a new issue