Skip to content

Commit 3d1f8ca

Browse files
luccabbvstinnergpshead
authored
[3.12] gh-88887: Cleanup multiprocessing.resource_tracker.ResourceTracker upon deletion (GH-130429) (#131530)
Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Gregory P. Smith <greg@krypto.org> (cherry picked from commit f53e7de)
1 parent 30e38b9 commit 3d1f8ca

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

Lib/multiprocessing/resource_tracker.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,46 @@ def _reentrant_call_error(self):
7070
raise ReentrantCallError(
7171
"Reentrant call into the multiprocessing resource tracker")
7272

73-
def _stop(self):
74-
with self._lock:
75-
# This should not happen (_stop() isn't called by a finalizer)
76-
# but we check for it anyway.
77-
if self._lock._recursion_count() > 1:
78-
return self._reentrant_call_error()
79-
if self._fd is None:
80-
# not running
81-
return
82-
83-
# closing the "alive" file descriptor stops main()
84-
os.close(self._fd)
85-
self._fd = None
73+
def __del__(self):
74+
# making sure child processess are cleaned before ResourceTracker
75+
# gets destructed.
76+
# see https://github.com/python/cpython/issues/88887
77+
self._stop(use_blocking_lock=False)
78+
79+
def _stop(self, use_blocking_lock=True):
80+
if use_blocking_lock:
81+
with self._lock:
82+
self._stop_locked()
83+
else:
84+
acquired = self._lock.acquire(blocking=False)
85+
try:
86+
self._stop_locked()
87+
finally:
88+
if acquired:
89+
self._lock.release()
90+
91+
def _stop_locked(
92+
self,
93+
close=os.close,
94+
waitpid=os.waitpid,
95+
waitstatus_to_exitcode=os.waitstatus_to_exitcode,
96+
):
97+
# This shouldn't happen (it might when called by a finalizer)
98+
# so we check for it anyway.
99+
if self._lock._recursion_count() > 1:
100+
return self._reentrant_call_error()
101+
if self._fd is None:
102+
# not running
103+
return
104+
if self._pid is None:
105+
return
106+
107+
# closing the "alive" file descriptor stops main()
108+
close(self._fd)
109+
self._fd = None
86110

87-
os.waitpid(self._pid, 0)
88-
self._pid = None
111+
waitpid(self._pid, 0)
112+
self._pid = None
89113

90114
def getfd(self):
91115
self.ensure_running()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixing multiprocessing Resource Tracker process leaking, usually observed when running Python as PID 1.

0 commit comments

Comments
 (0)