Skip to content

Commit a9934de

Browse files
authored
sync with 3.14.0a7, 3.13.3, 3.12.10 (#215)
1 parent fc58188 commit a9934de

File tree

14 files changed

+780
-128
lines changed

14 files changed

+780
-128
lines changed

py3.12/README_MODS

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,3 +1957,165 @@ diff Python-3.12.8/Lib/test/_test_multiprocessing.py Python-3.12.9/Lib/test/_tes
19571957
> # restore sigmask to what it was before executing test
19581958
> signal.pthread_sigmask(signal.SIG_SETMASK, orig_sigmask)
19591959
>
1960+
# ----------------------------------------------------------------------
1961+
diff Python-3.12.9/Lib/multiprocessing/resource_tracker.py Python-3.12.10/Lib/multiprocessing/resource_tracker.py
1962+
73,85c73,109
1963+
< def _stop(self):
1964+
< with self._lock:
1965+
< # This should not happen (_stop() isn't called by a finalizer)
1966+
< # but we check for it anyway.
1967+
< if self._lock._recursion_count() > 1:
1968+
< return self._reentrant_call_error()
1969+
< if self._fd is None:
1970+
< # not running
1971+
< return
1972+
<
1973+
< # closing the "alive" file descriptor stops main()
1974+
< os.close(self._fd)
1975+
< self._fd = None
1976+
---
1977+
> def __del__(self):
1978+
> # making sure child processess are cleaned before ResourceTracker
1979+
> # gets destructed.
1980+
> # see https://github.com/python/cpython/issues/88887
1981+
> self._stop(use_blocking_lock=False)
1982+
>
1983+
> def _stop(self, use_blocking_lock=True):
1984+
> if use_blocking_lock:
1985+
> with self._lock:
1986+
> self._stop_locked()
1987+
> else:
1988+
> acquired = self._lock.acquire(blocking=False)
1989+
> try:
1990+
> self._stop_locked()
1991+
> finally:
1992+
> if acquired:
1993+
> self._lock.release()
1994+
>
1995+
> def _stop_locked(
1996+
> self,
1997+
> close=os.close,
1998+
> waitpid=os.waitpid,
1999+
> waitstatus_to_exitcode=os.waitstatus_to_exitcode,
2000+
> ):
2001+
> # This shouldn't happen (it might when called by a finalizer)
2002+
> # so we check for it anyway.
2003+
> if self._lock._recursion_count() > 1:
2004+
> return self._reentrant_call_error()
2005+
> if self._fd is None:
2006+
> # not running
2007+
> return
2008+
> if self._pid is None:
2009+
> return
2010+
>
2011+
> # closing the "alive" file descriptor stops main()
2012+
> close(self._fd)
2013+
> self._fd = None
2014+
87,88c111,112
2015+
< os.waitpid(self._pid, 0)
2016+
< self._pid = None
2017+
---
2018+
> waitpid(self._pid, 0)
2019+
> self._pid = None
2020+
diff Python-3.12.9/Lib/test/_test_multiprocessing.py Python-3.12.10/Lib/test/_test_multiprocessing.py
2021+
591c591,592
2022+
< p = self.Process(target=time.sleep, args=(DELTA,))
2023+
---
2024+
> event = self.Event()
2025+
> p = self.Process(target=event.wait, args=())
2026+
594,596c595,600
2027+
< p.daemon = True
2028+
< p.start()
2029+
< self.assertIn(p, self.active_children())
2030+
---
2031+
> try:
2032+
> p.daemon = True
2033+
> p.start()
2034+
> self.assertIn(p, self.active_children())
2035+
> finally:
2036+
> event.set()
2037+
1580c1584
2038+
< for i in range(10):
2039+
---
2040+
> for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
2041+
1586,1587c1590
2042+
< time.sleep(DELTA)
2043+
< time.sleep(DELTA)
2044+
---
2045+
>
2046+
1609d1611
2047+
< self.addCleanup(p.join)
2048+
1611,1614c1613,1615
2049+
< p = threading.Thread(target=self.f, args=(cond, sleeping, woken))
2050+
< p.daemon = True
2051+
< p.start()
2052+
< self.addCleanup(p.join)
2053+
---
2054+
> t = threading.Thread(target=self.f, args=(cond, sleeping, woken))
2055+
> t.daemon = True
2056+
> t.start()
2057+
1621,1622c1622
2058+
< time.sleep(DELTA)
2059+
< self.assertReturnsIfImplemented(0, get_value, woken)
2060+
---
2061+
> self.assertReachesEventually(lambda: get_value(woken), 0)
2062+
1630,1631c1630
2063+
< time.sleep(DELTA)
2064+
< self.assertReturnsIfImplemented(1, get_value, woken)
2065+
---
2066+
> self.assertReachesEventually(lambda: get_value(woken), 1)
2067+
1639,1640c1638
2068+
< time.sleep(DELTA)
2069+
< self.assertReturnsIfImplemented(2, get_value, woken)
2070+
---
2071+
> self.assertReachesEventually(lambda: get_value(woken), 2)
2072+
1644c1642,1644
2073+
< p.join()
2074+
---
2075+
>
2076+
> threading_helper.join_thread(t)
2077+
> join_process(p)
2078+
1651a1652
2079+
> workers = []
2080+
1657c1658
2081+
< self.addCleanup(p.join)
2082+
---
2083+
> workers.append(p)
2084+
1663c1664
2085+
< self.addCleanup(t.join)
2086+
---
2087+
> workers.append(t)
2088+
1682c1683
2089+
< self.addCleanup(p.join)
2090+
---
2091+
> workers.append(p)
2092+
1687c1688
2093+
< self.addCleanup(t.join)
2094+
---
2095+
> workers.append(t)
2096+
1703c1704,1706
2097+
< self.assertReachesEventually(lambda: get_value(woken), 6)
2098+
---
2099+
> for i in range(6):
2100+
> woken.acquire()
2101+
> self.assertReturnsIfImplemented(0, get_value, woken)
2102+
1707a1711,1714
2103+
> for w in workers:
2104+
> # NOTE: join_process and join_thread are the same
2105+
> threading_helper.join_thread(w)
2106+
>
2107+
1713a1721
2108+
> workers = []
2109+
1718c1726
2110+
< self.addCleanup(p.join)
2111+
---
2112+
> workers.append(p)
2113+
1723c1731
2114+
< self.addCleanup(t.join)
2115+
---
2116+
> workers.append(t)
2117+
1757a1766,1769
2118+
> for w in workers:
2119+
> # NOTE: join_process and join_thread are the same
2120+
> threading_helper.join_thread(w)
2121+
>

py3.12/multiprocess/resource_tracker.py

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

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

90-
os.waitpid(self._pid, 0)
91-
self._pid = None
114+
waitpid(self._pid, 0)
115+
self._pid = None
92116

93117
def getfd(self):
94118
self.ensure_running()

0 commit comments

Comments
 (0)