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()