8000 gh-88887: Cleanup `multiprocessing.resource_tracker.ResourceTracker` … · python/cpython@f53e7de · GitHub
[go: up one dir, main page]

Skip to content

Commit f53e7de

Browse files
luccabbvstinnergpshead
authored
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>
1 parent 00a9844 commit f53e7de

File tree

2 files changed

+45
-20
lines changed

2 files changed

+45
-20
lines changed

Lib/multiprocessing/resource_tracker.py

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,29 +75,53 @@ def _reentrant_call_error(self):
7575
raise ReentrantCallError(
7676
"Reentrant call into the multiprocessing resource tracker")
7777

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

92-
_, status = os.waitpid(self._pid, 0)
116+
_, status = waitpid(self._pid, 0)
93117

94-
self._pid = None
118+
self._pid = None
95119

96-
try:
97-
self._exitcode = os.waitstatus_to_exitcode(status)
98-
except ValueError:
99-
# os.waitstatus_to_exitcode may raise an exception for invalid values
100-
self._exitcode = None
120+
try:
121+
self._exitcode = waitstatus_to_exitcode(status)
122+
except ValueError:
123+
# os.waitstatus_to_exitcode may raise an exception for invalid values
124+
self._exitcode = None
101125

102126
def getfd(self):
103127
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)
0