https://github.com/python/cpython/commit/3d1f8cae48566fba109abd071e26cbcceaf5fce3
commit: 3d1f8cae48566fba109abd071e26cbcceaf5fce3
branch: 3.12
author: luccabb <32229669+lucc...@users.noreply.github.com>
committer: vstinner <vstin...@python.org>
date: 2025-03-21T11:15:35+01:00
summary:

[3.12] gh-88887: Cleanup `multiprocessing.resource_tracker.ResourceTracker` 
upon deletion (GH-130429) (#131530)

Co-authored-by: Victor Stinner <vstin...@python.org>
Co-authored-by: Gregory P. Smith <g...@krypto.org>
(cherry picked from commit f53e7de6a84a0f535efb75c3671283b801a1af0f)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-02-21-14-47-46.gh-issue-88887.V3U0CV.rst
M Lib/multiprocessing/resource_tracker.py

diff --git a/Lib/multiprocessing/resource_tracker.py 
b/Lib/multiprocessing/resource_tracker.py
index 23fea295c357a5..e4da1293033412 100644
--- a/Lib/multiprocessing/resource_tracker.py
+++ b/Lib/multiprocessing/resource_tracker.py
@@ -70,22 +70,46 @@ def _reentrant_call_error(self):
         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
+    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._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
 
-            os.waitpid(self._pid, 0)
-            self._pid = None
+        waitpid(self._pid, 0)
+        self._pid = None
 
     def getfd(self):
         self.ensure_running()
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-21-14-47-46.gh-issue-88887.V3U0CV.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-21-14-47-46.gh-issue-88887.V3U0CV.rst
new file mode 100644
index 00000000000000..1a6c9483e2a35e
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-21-14-47-46.gh-issue-88887.V3U0CV.rst
@@ -0,0 +1 @@
+Fixing multiprocessing Resource Tracker process leaking, usually observed when 
running Python as PID 1.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to