cp -rf py3.12/examples .
cp -rf py3.12/doc .
cp -f py3.12/index.html .
cp -rf py3.12/_multiprocess _multiprocess
cp -rf Python-3.13.0a1/Modules/_multiprocessing Modules/_multiprocess
cp -rf py3.12/multiprocess multiprocess
# ----------------------------------------------------------------------
diff /Users/mmckerns/src/Python-3.13.0a1/Modules/_multiprocessing/semaphore.c Modules/_multiprocess/semaphore.c
10c10
< #include "multiprocessing.h"
---
> #include "multiprocess.h"
39,40c39,40
< module _multiprocessing
< class _multiprocessing.SemLock "SemLockObject *" "&_PyMp_SemLockType"
---
> module _multiprocess
> class _multiprocess.SemLock "SemLockObject *" "&_PyMp_SemLockType"
84c84
< _multiprocessing.SemLock.acquire
---
> _multiprocess.SemLock.acquire
93c93
< _multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking,
---
> _multiprocess_SemLock_acquire_impl(SemLockObject *self, int blocking,
175c175
< _multiprocessing.SemLock.release
---
> _multiprocess.SemLock.release
181c181
< _multiprocessing_SemLock_release_impl(SemLockObject *self)
---
> _multiprocess_SemLock_release_impl(SemLockObject *self)
300c300
< _multiprocessing.SemLock.acquire
---
> _multiprocess.SemLock.acquire
309c309
< _multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking,
---
> _multiprocess_SemLock_acquire_impl(SemLockObject *self, int blocking,
385c385
< _multiprocessing.SemLock.release
---
> _multiprocess.SemLock.release
391c391
< _multiprocessing_SemLock_release_impl(SemLockObject *self)
---
> _multiprocess_SemLock_release_impl(SemLockObject *self)
475c475
< _multiprocessing.SemLock.__new__
---
> _multiprocess.SemLock.__new__
486c486
< _multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value,
---
> _multiprocess_SemLock_impl(PyTypeObject *type, int kind, int value,
534c534
< _multiprocessing.SemLock._rebuild
---
> _multiprocess.SemLock._rebuild
545c545
< _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
---
> _multiprocess_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
586c586
< _multiprocessing.SemLock._count
---
> _multiprocess.SemLock._count
592c592
< _multiprocessing_SemLock__count_impl(SemLockObject *self)
---
> _multiprocess_SemLock__count_impl(SemLockObject *self)
599c599
< _multiprocessing.SemLock._is_mine
---
> _multiprocess.SemLock._is_mine
605c605
< _multiprocessing_SemLock__is_mine_impl(SemLockObject *self)
---
> _multiprocess_SemLock__is_mine_impl(SemLockObject *self)
613c613
< _multiprocessing.SemLock._get_value
---
> _multiprocess.SemLock._get_value
619c619
< _multiprocessing_SemLock__get_value_impl(SemLockObject *self)
---
> _multiprocess_SemLock__get_value_impl(SemLockObject *self)
638c638
< _multiprocessing.SemLock._is_zero
---
> _multiprocess.SemLock._is_zero
644c644
< _multiprocessing_SemLock__is_zero_impl(SemLockObject *self)
---
> _multiprocess_SemLock__is_zero_impl(SemLockObject *self)
666c666
< _multiprocessing.SemLock._after_fork
---
> _multiprocess.SemLock._after_fork
672c672
< _multiprocessing_SemLock__after_fork_impl(SemLockObject *self)
---
> _multiprocess_SemLock__after_fork_impl(SemLockObject *self)
680c680
< _multiprocessing.SemLock.__enter__
---
> _multiprocess.SemLock.__enter__
686c686
< _multiprocessing_SemLock___enter___impl(SemLockObject *self)
---
> _multiprocess_SemLock___enter___impl(SemLockObject *self)
689c689
<     return _multiprocessing_SemLock_acquire_impl(self, 1, Py_None);
---
>     return _multiprocess_SemLock_acquire_impl(self, 1, Py_None);
693c693
< _multiprocessing.SemLock.__exit__
---
> _multiprocess.SemLock.__exit__
704c704
< _multiprocessing_SemLock___exit___impl(SemLockObject *self,
---
> _multiprocess_SemLock___exit___impl(SemLockObject *self,
709c709
<     return _multiprocessing_SemLock_release_impl(self);
---
>     return _multiprocess_SemLock_release_impl(self);
724,733c724,733
<     _MULTIPROCESSING_SEMLOCK_ACQUIRE_METHODDEF
<     _MULTIPROCESSING_SEMLOCK_RELEASE_METHODDEF
<     _MULTIPROCESSING_SEMLOCK___ENTER___METHODDEF
<     _MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF
<     _MULTIPROCESSING_SEMLOCK__COUNT_METHODDEF
<     _MULTIPROCESSING_SEMLOCK__IS_MINE_METHODDEF
<     _MULTIPROCESSING_SEMLOCK__GET_VALUE_METHODDEF
<     _MULTIPROCESSING_SEMLOCK__IS_ZERO_METHODDEF
<     _MULTIPROCESSING_SEMLOCK__REBUILD_METHODDEF
<     _MULTIPROCESSING_SEMLOCK__AFTER_FORK_METHODDEF
---
>     _MULTIPROCESS_SEMLOCK_ACQUIRE_METHODDEF
>     _MULTIPROCESS_SEMLOCK_RELEASE_METHODDEF
>     _MULTIPROCESS_SEMLOCK___ENTER___METHODDEF
>     _MULTIPROCESS_SEMLOCK___EXIT___METHODDEF
>     _MULTIPROCESS_SEMLOCK__COUNT_METHODDEF
>     _MULTIPROCESS_SEMLOCK__IS_MINE_METHODDEF
>     _MULTIPROCESS_SEMLOCK__GET_VALUE_METHODDEF
>     _MULTIPROCESS_SEMLOCK__IS_ZERO_METHODDEF
>     _MULTIPROCESS_SEMLOCK__REBUILD_METHODDEF
>     _MULTIPROCESS_SEMLOCK__AFTER_FORK_METHODDEF
764c764
<     {Py_tp_new, _multiprocessing_SemLock},
---
>     {Py_tp_new, _multiprocess_SemLock},
772c772
<     .name = "_multiprocessing.SemLock",
---
>     .name = "_multiprocess.SemLock",
diff ~/src/Python-3.13.0a1/Modules/_multiprocessing/multiprocessing.h Modules/_multiprocess/multiprocess.h 
1,2c1,2
< #ifndef MULTIPROCESSING_H
< #define MULTIPROCESSING_H
---
> #ifndef MULTIPROCESS_H
> #define MULTIPROCESS_H
104c104
< #endif /* MULTIPROCESSING_H */
---
> #endif /* MULTIPROCESS_H */
diff ~/src/Python-3.13.0a1/Modules/_multiprocessing/multiprocessing.c Modules/_multiprocess/multiprocess.c
2c2
<  * Extension module used by multiprocessing package
---
>  * Extension module used by multiprocess package
4c4
<  * multiprocessing.c
---
>  * multiprocess.c
10c10
< #include "multiprocessing.h"
---
> #include "multiprocess.h"
30c30
< module _multiprocessing
---
> module _multiprocess
77c77
< _multiprocessing.closesocket
---
> _multiprocess.closesocket
85c85
< _multiprocessing_closesocket_impl(PyObject *module, HANDLE handle)
---
> _multiprocess_closesocket_impl(PyObject *module, HANDLE handle)
100c100
< _multiprocessing.recv
---
> _multiprocess.recv
109c109
< _multiprocessing_recv_impl(PyObject *module, HANDLE handle, int size)
---
> _multiprocess_recv_impl(PyObject *module, HANDLE handle, int size)
132c132
< _multiprocessing.send
---
> _multiprocess.send
141c141
< _multiprocessing_send_impl(PyObject *module, HANDLE handle, Py_buffer *buf)
---
> _multiprocess_send_impl(PyObject *module, HANDLE handle, Py_buffer *buf)
160c160
< _multiprocessing.sem_unlink
---
> _multiprocess.sem_unlink
168c168
< _multiprocessing_sem_unlink_impl(PyObject *module, const char *name)
---
> _multiprocess_sem_unlink_impl(PyObject *module, const char *name)
196c196
< multiprocessing_exec(PyObject *module)
---
> multiprocess_exec(PyObject *module)
277,278c277,278
< static PyModuleDef_Slot multiprocessing_slots[] = {
<     {Py_mod_exec, multiprocessing_exec},
---
> static PyModuleDef_Slot multiprocess_slots[] = {
>     {Py_mod_exec, multiprocess_exec},
283c283
< static struct PyModuleDef multiprocessing_module = {
---
> static struct PyModuleDef multiprocess_module = {
285c285
<     .m_name = "_multiprocessing",
---
>     .m_name = "_multiprocess",
288c288
<     .m_slots = multiprocessing_slots,
---
>     .m_slots = multiprocess_slots,
292c292
< PyInit__multiprocessing(void)
---
> PyInit__multiprocess(void)
294c294
<     return PyModuleDef_Init(&multiprocessing_module);
---
>     return PyModuleDef_Init(&multiprocess_module);
# ----------------------------------------------------------------------
diff Python-3.12.0rc3/Lib/multiprocessing/connection.py Python-3.13.0a1/Lib/multiprocessing/connection.py
11a12
> import errno
273a275
>         _send_ov = None
275a278,281
>             ov = self._send_ov
>             if ov is not None:
>                 # Interrupt WaitForMultipleObjects() in _send_bytes()
>                 ov.cancel()
278a285,288
>             if self._send_ov is not None:
>                 # A connection should only be used by a single thread
>                 raise ValueError("concurrent send_bytes() calls "
>                                  "are not supported")
279a290
>             self._send_ov = ov
288a300
>                 self._send_ov = None
289a302,306
>             if err == _winapi.ERROR_OPERATION_ABORTED:
>                 # close() was called by another thread while
>                 # WaitForMultipleObjects() was waiting for the overlapped
>                 # operation.
>                 raise OSError(errno.EPIPE, "handle is closed")
diff Python-3.12.0rc3/Lib/multiprocessing/managers.py Python-3.13.0a1/Lib/multiprocessing/managers.py
93c93,96
<     raise convert_to_error(kind, result)
---
>     try:
>         raise convert_to_error(kind, result)
>     finally:
>         del result  # break reference cycle
836c839,842
<         raise convert_to_error(kind, result)
---
>         try:
>             raise convert_to_error(kind, result)
>         finally:
>             del result   # break reference cycle
diff Python-3.12.0rc3/Lib/multiprocessing/pool.py Python-3.13.0a1/Lib/multiprocessing/pool.py
203c203
<             processes = os.cpu_count() or 1
---
>             processes = os.process_cpu_count() or 1
diff Python-3.12.0rc3/Lib/multiprocessing/popen_spawn_win32.py Python-3.13.0a1/Lib/multiprocessing/popen_spawn_win32.py
16a17
> # Exit code used by Popen.terminate()
125,126c126,130
<             except OSError:
<                 if self.wait(timeout=1.0) is None:
---
>             except PermissionError:
>                 # ERROR_ACCESS_DENIED (winerror 5) is received when the
>                 # process already died.
>                 code = _winapi.GetExitCodeProcess(int(self._handle))
>                 if code == _winapi.STILL_ACTIVE:
127a132,134
>                 self.returncode = code
>             else:
>                 self.returncode = -signal.SIGTERM
diff Python-3.12.0rc3/Lib/multiprocessing/queues.py Python-3.13.0a1/Lib/multiprocessing/queues.py
160a161,174
>     def _terminate_broken(self):
>         # Close a Queue on error.
> 
>         # gh-94777: Prevent queue writing to a pipe which is no longer read.
>         self._reader.close()
> 
>         # gh-107219: Close the connection writer which can unblock
>         # Queue._feed() if it was stuck in send_bytes().
>         if sys.platform == 'win32':
>             self._writer.close()
> 
>         self.close()
>         self.join_thread()
> 
172c186,187
<             name='QueueFeederThread'
---
>             name='QueueFeederThread',
>             daemon=True,
174d188
<         self._thread.daemon = True
176,178c190,198
<         debug('doing self._thread.start()')
<         self._thread.start()
<         debug('... done self._thread.start()')
---
>         try:
>             debug('doing self._thread.start()')
>             self._thread.start()
>             debug('... done self._thread.start()')
>         except:
>             # gh-109047: During Python finalization, creating a thread
>             # can fail with RuntimeError.
>             self._thread = None
>             raise
diff Python-3.12.0rc3/Lib/multiprocessing/resource_tracker.py Python-3.13.0a1/Lib/multiprocessing/resource_tracker.py
53a54,57
> class ReentrantCallError(RuntimeError):
>     pass
> 
> 
57c61
<         self._lock = threading.Lock()
---
>         self._lock = threading.RLock()
60a65,72
>     def _reentrant_call_error(self):
>         # gh-109629: this happens if an explicit call to the ResourceTracker
>         # gets interrupted by a garbage collection, invoking a finalizer (*)
>         # that itself calls back into ResourceTracker.
>         #   (*) for example the SemLock finalizer
>         raise ReentrantCallError(
>             "Reentrant call into the multiprocessing resource tracker")
> 
62a75,78
>             # 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()
83a100,102
>             if self._lock._recursion_count() > 1:
>                 # The code below is certainly not reentrant-safe, so bail out
>                 return self._reentrant_call_error()
162c181,191
<         self.ensure_running()
---
>         try:
>             self.ensure_running()
>         except ReentrantCallError:
>             # The code below might or might not work, depending on whether
>             # the resource tracker was already running and still alive.
>             # Better warn the user.
>             # (XXX is warnings.warn itself reentrant-safe? :-)
>             warnings.warn(
>                 f"ResourceTracker called reentrantly for resource cleanup, "
>                 f"which is unsupported. "
>                 f"The {rtype} object {name!r} might leak.")
178a208
> 
224,226c254,257
<                     warnings.warn('resource_tracker: There appear to be %d '
<                                   'leaked %s objects to clean up at shutdown' %
<                                   (len(rtype_cache), rtype))
---
>                     warnings.warn(
>                         f'resource_tracker: There appear to be {len(rtype_cache)} '
>                         f'leaked {rtype} objects to clean up at shutdown: {rtype_cache}'
>                     )
diff Python-3.12.0rc3/Lib/multiprocessing/util.py Python-3.13.0a1/Lib/multiprocessing/util.py
67,68c67
<     logging._acquireLock()
<     try:
---
>     with logging._lock:
82,84d80
<     finally:
<         logging._releaseLock()
< 
# ----------------------------------------------------------------------
diff Python-3.12.0rc3/Lib/test/_test_multiprocessing.py Python-3.13.0a1/Lib/test/_test_multiprocessing.py 
53c53
< from multiprocessing.connection import wait, AuthenticationError
---
> from multiprocessing.connection import wait
81,82c81,82
< if support.check_sanitizer(address=True):
<     # bpo-45200: Skip multiprocessing tests if Python is built with ASAN to
---
> if support.HAVE_ASAN_FORK_BUG:
>     # gh-89363: Skip multiprocessing tests if Python is built with ASAN to
84c84,89
<     raise unittest.SkipTest("libasan has a pthread_create() dead lock")
---
>     raise unittest.SkipTest("libasan has a pthread_create() dead lock related to thread+fork")
> 
> 
> # gh-110666: Tolerate a difference of 100 ms when comparing timings
> # (clock resolution)
> CLOCK_RES = 0.100
560,561c565
<         if os.name != 'nt':
<             self.assertEqual(exitcode, -signal.SIGTERM)
---
>         self.assertEqual(exitcode, -signal.SIGTERM)
566a571,572
>         else:
>             self.assertEqual(exitcode, -signal.SIGTERM)
1653c1659
<             expected = 0.1
---
>             expected = 0.100
1657,1658c1663
<             # borrow logic in assertTimeout() from test/lock_tests.py
<             if not result and expected * 0.6 < dt < expected * 10.0:
---
>             if not result and (expected - CLOCK_RES) <= dt:
1677c1682
<             time.sleep(0.01)
---
>             time.sleep(0.010)
2576c2581
<         res = self.pool.apply_async(sqr, (6, TIMEOUT2 + 1.0))
---
>         res = self.pool.apply_async(sqr, (6, TIMEOUT2 + support.SHORT_TIMEOUT))
2680,2682c2685,2687
<         result = self.pool.map_async(
<             time.sleep, [0.1 for i in range(10000)], chunksize=1
<             )
---
>         # Simulate slow tasks which take "forever" to complete
>         args = [support.LONG_TIMEOUT for i in range(10_000)]
>         result = self.pool.map_async(time.sleep, args, chunksize=1)
2684,2687c2689
<         join = TimingWrapper(self.pool.join)
<         join()
<         # Sanity check the pool didn't wait for all tasks to finish
<         self.assertLess(join.elapsed, 2.0)
---
>         self.pool.join()
3153a3156,3193
> 
> class FakeConnection:
>     def send(self, payload):
>         pass
> 
>     def recv(self):
>         return '#ERROR', pyqueue.Empty()
> 
> class TestManagerExceptions(unittest.TestCase):
>     # Issue 106558: Manager exceptions avoids creating cyclic references.
>     def setUp(self):
>         self.mgr = multiprocessing.Manager()
> 
>     def tearDown(self):
>         self.mgr.shutdown()
>         self.mgr.join()
> 
>     def test_queue_get(self):
>         queue = self.mgr.Queue()
>         if gc.isenabled():
>             gc.disable()
>             self.addCleanup(gc.enable)
>         try:
>             queue.get_nowait()
>         except pyqueue.Empty as e:
>             wr = weakref.ref(e)
>         self.assertEqual(wr(), None)
> 
>     def test_dispatch(self):
>         if gc.isenabled():
>             gc.disable()
>             self.addCleanup(gc.enable)
>         try:
>             multiprocessing.managers.dispatch(FakeConnection(), None, None)
>         except pyqueue.Empty as e:
>             wr = weakref.ref(e)
>         self.assertEqual(wr(), None)
> 
4872c4912
<                 time.sleep(random.random()*0.1)
---
>                 time.sleep(random.random() * 0.100)
4912c4952
<                 time.sleep(random.random()*0.1)
---
>                 time.sleep(random.random() * 0.100)
4961c5001
<         expected = 5
---
>         timeout = 5.0  # seconds
4965c5005
<         res = wait([a, b], expected)
---
>         res = wait([a, b], timeout)
4969,4970c5009
<         self.assertLess(delta, expected * 2)
<         self.assertGreater(delta, expected * 0.5)
---
>         self.assertGreater(delta, timeout - CLOCK_RES)
4973,4974d5011
< 
<         start = time.monotonic()
4976,4977d5012
<         delta = time.monotonic() - start
< 
4979d5013
<         self.assertLess(delta, 0.4)
5437c5471,5473
<         self.assertEqual(results, [2, 1])
---
>         # gh-109706: queue.put(1) can write into the queue before queue.put(2),
>         # there is no synchronization in the test.
>         self.assertSetEqual(set(results), set([2, 1]))
# ----------------------------------------------------------------------
diff Python-3.13.0a1/Modules/_multiprocessing/clinic/posixshmem.c.h Python-3.13.0a2/Modules/_multiprocessing/clinic/posixshmem.c.h
5,9d4
< #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
< #  include "pycore_gc.h"          // PyGC_Head
< #  include "pycore_runtime.h"     // _Py_ID()
< #endif
< 
19c14
<     {"shm_open", _PyCFunction_CAST(_posixshmem_shm_open), METH_FASTCALL|METH_KEYWORDS, _posixshmem_shm_open__doc__},
---
>     {"shm_open", (PyCFunction)(void(*)(void))_posixshmem_shm_open, METH_VARARGS|METH_KEYWORDS, _posixshmem_shm_open__doc__},
26c21
< _posixshmem_shm_open(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
---
> _posixshmem_shm_open(PyObject *module, PyObject *args, PyObject *kwargs)
29,55c24
<     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
< 
<     #define NUM_KEYWORDS 3
<     static struct {
<         PyGC_Head _this_is_not_used;
<         PyObject_VAR_HEAD
<         PyObject *ob_item[NUM_KEYWORDS];
<     } _kwtuple = {
<         .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
<         .ob_item = { &_Py_ID(path), &_Py_ID(flags), &_Py_ID(mode), },
<     };
<     #undef NUM_KEYWORDS
<     #define KWTUPLE (&_kwtuple.ob_base.ob_base)
< 
<     #else  // !Py_BUILD_CORE
<     #  define KWTUPLE NULL
<     #endif  // !Py_BUILD_CORE
< 
<     static const char * const _keywords[] = {"path", "flags", "mode", NULL};
<     static _PyArg_Parser _parser = {
<         .keywords = _keywords,
<         .fname = "shm_open",
<         .kwtuple = KWTUPLE,
<     };
<     #undef KWTUPLE
<     PyObject *argsbuf[3];
<     Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2;
---
>     static char *_keywords[] = {"path", "flags", "mode", NULL};
61,78c30,31
<     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 3, 0, argsbuf);
<     if (!args) {
<         goto exit;
<     }
<     if (!PyUnicode_Check(args[0])) {
<         _PyArg_BadArgument("shm_open", "argument 'path'", "str", args[0]);
<         goto exit;
<     }
<     path = args[0];
<     flags = PyLong_AsInt(args[1]);
<     if (flags == -1 && PyErr_Occurred()) {
<         goto exit;
<     }
<     if (!noptargs) {
<         goto skip_optional_pos;
<     }
<     mode = PyLong_AsInt(args[2]);
<     if (mode == -1 && PyErr_Occurred()) {
---
>     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ui|i:shm_open", _keywords,
>         &path, &flags, &mode))
80,81d32
<     }
< skip_optional_pos:
107c58
<     {"shm_unlink", _PyCFunction_CAST(_posixshmem_shm_unlink), METH_FASTCALL|METH_KEYWORDS, _posixshmem_shm_unlink__doc__},
---
>     {"shm_unlink", (PyCFunction)(void(*)(void))_posixshmem_shm_unlink, METH_VARARGS|METH_KEYWORDS, _posixshmem_shm_unlink__doc__},
113c64
< _posixshmem_shm_unlink(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
---
> _posixshmem_shm_unlink(PyObject *module, PyObject *args, PyObject *kwargs)
116,141c67
<     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
< 
<     #define NUM_KEYWORDS 1
<     static struct {
<         PyGC_Head _this_is_not_used;
<         PyObject_VAR_HEAD
<         PyObject *ob_item[NUM_KEYWORDS];
<     } _kwtuple = {
<         .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
<         .ob_item = { &_Py_ID(path), },
<     };
<     #undef NUM_KEYWORDS
<     #define KWTUPLE (&_kwtuple.ob_base.ob_base)
< 
<     #else  // !Py_BUILD_CORE
<     #  define KWTUPLE NULL
<     #endif  // !Py_BUILD_CORE
< 
<     static const char * const _keywords[] = {"path", NULL};
<     static _PyArg_Parser _parser = {
<         .keywords = _keywords,
<         .fname = "shm_unlink",
<         .kwtuple = KWTUPLE,
<     };
<     #undef KWTUPLE
<     PyObject *argsbuf[1];
---
>     static char *_keywords[] = {"path", NULL};
144,145c70,71
<     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
<     if (!args) {
---
>     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "U:shm_unlink", _keywords,
>         &path))
147,152d72
<     }
<     if (!PyUnicode_Check(args[0])) {
<         _PyArg_BadArgument("shm_unlink", "argument 'path'", "str", args[0]);
<         goto exit;
<     }
<     path = args[0];
168c88
< /*[clinic end generated code: output=2f356903a281d857 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=be0661dbed83ea23 input=a9049054013a1b77]*/
diff Python-3.13.0a1/Modules/_multiprocessing/clinic/semaphore.c.h Python-3.13.0a2/Modules/_multiprocessing/clinic/semaphore.c.h
8a9
> #include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
544c545
< /*[clinic end generated code: output=e8ea65f8cba8e173 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=d57992037e6770b6 input=a9049054013a1b77]*/
diff Python-3.13.0a1/Modules/_multiprocessing/clinic/multiprocessing.c.h Python-3.13.0a2/Modules/_multiprocessing/clinic/multiprocessing.c.h
4a5,6
> #include "pycore_modsupport.h"    // _PyArg_CheckPositional()
> 
105,108d106
<     if (!PyBuffer_IsContiguous(&buf, 'C')) {
<         _PyArg_BadArgument("send", "argument 2", "contiguous buffer", args[1]);
<         goto exit;
<     }
169c167
< /*[clinic end generated code: output=8b91c020d4353cc5 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=73b4cb8428d816da input=a9049054013a1b77]*/
# ----------------------------------------------------------------------
diff Python-3.13.0a1/Modules/_multiprocessing/posixshmem.c Python-3.13.0a2/Modules/_multiprocessing/posixshmem.c
4a5,11
> #include "pyconfig.h"   // Py_GIL_DISABLED
> 
> #ifndef Py_GIL_DISABLED
> // Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
> #define Py_LIMITED_API 0x030c0000
> #endif
> 
7c14
< // for shm_open() and shm_unlink()
---
> #include <errno.h>                // EINTR
9c16
< #include <sys/mman.h>
---
> #  include <sys/mman.h>           // shm_open(), shm_unlink()
11a19
> 
43c51
<     const char *name = PyUnicode_AsUTF8(path);
---
>     const char *name = PyUnicode_AsUTF8AndSize(path, NULL);
82c90
<     const char *name = PyUnicode_AsUTF8(path);
---
>     const char *name = PyUnicode_AsUTF8AndSize(path, NULL);
# ----------------------------------------------------------------------
diff Python-3.13.0a1/Lib/multiprocessing/managers.py Python-3.13.0a2/Lib/multiprocessing/managers.py
1167a1168
>     __class_getitem__ = classmethod(types.GenericAlias)
1169c1170,1171
< DictProxy = MakeProxyType('DictProxy', (
---
> 
> _BaseDictProxy = MakeProxyType('DictProxy', (
1174c1176
< DictProxy._method_to_typeid_ = {
---
> _BaseDictProxy._method_to_typeid_ = {
1176a1179,1180
> class DictProxy(_BaseDictProxy):
>     __class_getitem__ = classmethod(types.GenericAlias)
# ----------------------------------------------------------------------
diff Python-3.13.0a1/Lib/test/_test_multiprocessing.py Python-3.13.0a2/Lib/test/_test_multiprocessing.py 
2441,2442c2441,2445
< def sqr(x, wait=0.0):
<     time.sleep(wait)
---
> def sqr(x, wait=0.0, event=None):
>     if event is None:
>         time.sleep(wait)
>     else:
>         event.wait(wait)
2581,2584c2584,2595
<         res = self.pool.apply_async(sqr, (6, TIMEOUT2 + support.SHORT_TIMEOUT))
<         get = TimingWrapper(res.get)
<         self.assertRaises(multiprocessing.TimeoutError, get, timeout=TIMEOUT2)
<         self.assertTimingAlmostEqual(get.elapsed, TIMEOUT2)
---
>         p = self.Pool(3)
>         try:
>             event = threading.Event() if self.TYPE == 'threads' else None
>             res = p.apply_async(sqr, (6, TIMEOUT2 + support.SHORT_TIMEOUT, event))
>             get = TimingWrapper(res.get)
>             self.assertRaises(multiprocessing.TimeoutError, get, timeout=TIMEOUT2)
>             self.assertTimingAlmostEqual(get.elapsed, TIMEOUT2)
>         finally:
>             if event is not None:
>                 event.set()
>             p.terminate()
>             p.join()
2684a2696,2698
>         if self.TYPE == 'threads':
>             self.skipTest("Threads cannot be terminated")
> 
2685a2700
>         p = self.Pool(3)
2687,2689c2702,2704
<         result = self.pool.map_async(time.sleep, args, chunksize=1)
<         self.pool.terminate()
<         self.pool.join()
---
>         result = p.map_async(time.sleep, args, chunksize=1)
>         p.terminate()
>         p.join()
# ----------------------------------------------------------------------
diff Python-3.13.0a2/Lib/multiprocessing/managers.py Python-3.13.0a3/Lib/multiprocessing/managers.py
159c159
<         self.listener = Listener(address=address, backlog=16)
---
>         self.listener = Listener(address=address, backlog=128)
diff Python-3.13.0a2/Lib/multiprocessing/popen_spawn_win32.py Python-3.13.0a3/Lib/multiprocessing/popen_spawn_win32.py
104,115c104,117
<         if self.returncode is None:
<             if timeout is None:
<                 msecs = _winapi.INFINITE
<             else:
<                 msecs = max(0, int(timeout * 1000 + 0.5))
< 
<             res = _winapi.WaitForSingleObject(int(self._handle), msecs)
<             if res == _winapi.WAIT_OBJECT_0:
<                 code = _winapi.GetExitCodeProcess(self._handle)
<                 if code == TERMINATE:
<                     code = -signal.SIGTERM
<                 self.returncode = code
---
>         if self.returncode is not None:
>             return self.returncode
> 
>         if timeout is None:
>             msecs = _winapi.INFINITE
>         else:
>             msecs = max(0, int(timeout * 1000 + 0.5))
> 
>         res = _winapi.WaitForSingleObject(int(self._handle), msecs)
>         if res == _winapi.WAIT_OBJECT_0:
>             code = _winapi.GetExitCodeProcess(self._handle)
>             if code == TERMINATE:
>                 code = -signal.SIGTERM
>             self.returncode = code
123,134c125,140
<         if self.returncode is None:
<             try:
<                 _winapi.TerminateProcess(int(self._handle), TERMINATE)
<             except PermissionError:
<                 # ERROR_ACCESS_DENIED (winerror 5) is received when the
<                 # process already died.
<                 code = _winapi.GetExitCodeProcess(int(self._handle))
<                 if code == _winapi.STILL_ACTIVE:
<                     raise
<                 self.returncode = code
<             else:
<                 self.returncode = -signal.SIGTERM
---
>         if self.returncode is not None:
>             return
> 
>         try:
>             _winapi.TerminateProcess(int(self._handle), TERMINATE)
>         except PermissionError:
>             # ERROR_ACCESS_DENIED (winerror 5) is received when the
>             # process already died.
>             code = _winapi.GetExitCodeProcess(int(self._handle))
>             if code == _winapi.STILL_ACTIVE:
>                 raise
> 
>         # gh-113009: Don't set self.returncode. Even if GetExitCodeProcess()
>         # returns an exit code different than STILL_ACTIVE, the process can
>         # still be running. Only set self.returncode once WaitForSingleObject()
>         # returns WAIT_OBJECT_0 in wait().
diff Python-3.13.0a2/Lib/multiprocessing/resource_sharer.py Python-3.13.0a3/Lib/multiprocessing/resource_sharer.py
126c126
<         self._listener = Listener(authkey=process.current_process().authkey)
---
>         self._listener = Listener(authkey=process.current_process().authkey, backlog=128)
diff Python-3.13.0a2/Lib/multiprocessing/shared_memory.py Python-3.13.0a3/Lib/multiprocessing/shared_memory.py
73a74
>     _track = True
75c76
<     def __init__(self, name=None, create=False, size=0):
---
>     def __init__(self, name=None, create=False, size=0, *, track=True):
84a86
>         self._track = track
119,120c121,122
< 
<             resource_tracker.register(self._name, "shared_memory")
---
>             if self._track:
>                 resource_tracker.register(self._name, "shared_memory")
239,241c241,250
<         In order to ensure proper cleanup of resources, unlink should be
<         called once (and only once) across all processes which have access
<         to the shared memory block."""
---
>         Unlink should be called once (and only once) across all handles
>         which have access to the shared memory block, even if these
>         handles belong to different processes. Closing and unlinking may
>         happen in any order, but trying to access data inside a shared
>         memory block after unlinking may result in memory errors,
>         depending on platform.
> 
>         This method has no effect on Windows, where the only way to
>         delete a shared memory block is to close all handles."""
> 
244c253,254
<             resource_tracker.unregister(self._name, "shared_memory")
---
>             if self._track:
>                 resource_tracker.unregister(self._name, "shared_memory")
diff Python-3.13.0a2/Lib/multiprocessing/util.py Python-3.13.0a3/Lib/multiprocessing/util.py
46c46
<         _logger.log(SUBDEBUG, msg, *args)
---
>         _logger.log(SUBDEBUG, msg, *args, stacklevel=2)
50c50
<         _logger.log(DEBUG, msg, *args)
---
>         _logger.log(DEBUG, msg, *args, stacklevel=2)
54c54
<         _logger.log(INFO, msg, *args)
---
>         _logger.log(INFO, msg, *args, stacklevel=2)
58c58
<         _logger.log(SUBWARNING, msg, *args)
---
>         _logger.log(SUBWARNING, msg, *args, stacklevel=2)
# ----------------------------------------------------------------------
diff Python-3.13.0a2/Lib/test/_test_multiprocessing.py Python-3.13.0a3/Lib/test/_test_multiprocessing.py 
4457a4458,4510
>     @unittest.skipIf(os.name != "posix", "resource_tracker is posix only")
>     def test_shared_memory_untracking(self):
>         # gh-82300: When a separate Python process accesses shared memory
>         # with track=False, it must not cause the memory to be deleted
>         # when terminating.
>         cmd = '''if 1:
>             import sys
>             from multiprocessing.shared_memory import SharedMemory
>             mem = SharedMemory(create=False, name=sys.argv[1], track=False)
>             mem.close()
>         '''
>         mem = shared_memory.SharedMemory(create=True, size=10)
>         # The resource tracker shares pipes with the subprocess, and so
>         # err existing means that the tracker process has terminated now.
>         try:
>             rc, out, err = script_helper.assert_python_ok("-c", cmd, mem.name)
>             self.assertNotIn(b"resource_tracker", err)
>             self.assertEqual(rc, 0)
>             mem2 = shared_memory.SharedMemory(create=False, name=mem.name)
>             mem2.close()
>         finally:
>             try:
>                 mem.unlink()
>             except OSError:
>                 pass
>             mem.close()
> 
>     @unittest.skipIf(os.name != "posix", "resource_tracker is posix only")
>     def test_shared_memory_tracking(self):
>         # gh-82300: When a separate Python process accesses shared memory
>         # with track=True, it must cause the memory to be deleted when
>         # terminating.
>         cmd = '''if 1:
>             import sys
>             from multiprocessing.shared_memory import SharedMemory
>             mem = SharedMemory(create=False, name=sys.argv[1], track=True)
>             mem.close()
>         '''
>         mem = shared_memory.SharedMemory(create=True, size=10)
>         try:
>             rc, out, err = script_helper.assert_python_ok("-c", cmd, mem.name)
>             self.assertEqual(rc, 0)
>             self.assertIn(
>                 b"resource_tracker: There appear to be 1 leaked "
>                 b"shared_memory objects to clean up at shutdown", err)
>         finally:
>             try:
>                 mem.unlink()
>             except OSError:
>                 pass
>             resource_tracker.unregister(mem._name, "shared_memory")
>             mem.close()
> 
4673a4727,4749
>     def test_filename(self):
>         logger = multiprocessing.get_logger()
>         original_level = logger.level
>         try:
>             logger.setLevel(util.DEBUG)
>             stream = io.StringIO()
>             handler = logging.StreamHandler(stream)
>             logging_format = '[%(levelname)s] [%(filename)s] %(message)s'
>             handler.setFormatter(logging.Formatter(logging_format))
>             logger.addHandler(handler)
>             logger.info('1')
>             util.info('2')
>             logger.debug('3')
>             filename = os.path.basename(__file__)
>             log_record = stream.getvalue()
>             self.assertIn(f'[INFO] [{filename}] 1', log_record)
>             self.assertIn(f'[INFO] [{filename}] 2', log_record)
>             self.assertIn(f'[DEBUG] [{filename}] 3', log_record)
>         finally:
>             logger.setLevel(original_level)
>             logger.removeHandler(handler)
>             handler.close()
> 
# ----------------------------------------------------------------------
diff Python-3.13.0a3/Lib/multiprocessing/connection.py Python-3.13.0a4/Lib/multiprocessing/connection.py
22d21
< import _multiprocessing
30a30
>     import _multiprocessing
1013a1014,1024
>         # Windows limits WaitForMultipleObjects at 64 handles, and we use a
>         # few for synchronisation, so we switch to batched waits at 60.
>         if len(L) > 60:
>             try:
>                 res = _winapi.BatchedWaitForMultipleObjects(L, False, timeout)
>             except TimeoutError:
>                 return []
>             ready.extend(L[i] for i in res)
>             if res:
>                 L = [h for i, h in enumerate(L) if i > res[0] & i not in res]
>             timeout = 0
1015c1026,1027
<             res = _winapi.WaitForMultipleObjects(L, False, timeout)
---
>             short_L = L[:60] if len(L) > 60 else L
>             res = _winapi.WaitForMultipleObjects(short_L, False, timeout)
diff Python-3.13.0a3/Lib/test/_test_multiprocessing.py Python-3.13.0a4/Lib/test/_test_multiprocessing.py 
2695a2696,2698
>         # Simulate slow tasks which take "forever" to complete
>         sleep_time = support.LONG_TIMEOUT
> 
2697c2700,2703
<             self.skipTest("Threads cannot be terminated")
---
>             # Thread pool workers can't be forced to quit, so if the first
>             # task starts early enough, we will end up waiting for it.
>             # Sleep for a shorter time, so the test doesn't block.
>             sleep_time = 1
2699d2704
<         # Simulate slow tasks which take "forever" to complete
2701c2706
<         args = [support.LONG_TIMEOUT for i in range(10_000)]
---
>         args = [sleep_time for i in range(10_000)]
2702a2708
>         time.sleep(0.2)  # give some tasks a chance to start
6109a6116,6133
>     def test_large_pool(self):
>         #
>         # gh-89240: Check that large pools are always okay
>         #
>         testfn = os_helper.TESTFN
>         self.addCleanup(os_helper.unlink, testfn)
>         with open(testfn, 'w', encoding='utf-8') as f:
>             f.write(textwrap.dedent('''\
>                 import multiprocessing
>                 def f(x): return x*x
>                 if __name__ == '__main__':
>                     with multiprocessing.Pool(200) as p:
>                         print(sum(p.map(f, range(1000))))
>             '''))
>         rc, out, err = script_helper.assert_python_ok(testfn)
>         self.assertEqual("332833500", out.decode('utf-8').strip())
>         self.assertFalse(err, msg=err.decode('utf-8'))
> 
# ----------------------------------------------------------------------
diff Python-3.13.0a4/Modules/_multiprocessing/multiprocessing.c Python-3.13.0a5/Modules/_multiprocessing/multiprocessing.c
184c184
< #if !defined(POSIX_SEMAPHORES_NOT_ENABLED) && !defined(__ANDROID__)
---
> #if !defined(POSIX_SEMAPHORES_NOT_ENABLED)
diff Python-3.13.0a4/Modules/_multiprocessing/posixshmem.c Python-3.13.0a5/Modules/_multiprocessing/posixshmem.c
4a5
> // Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
6d6
< 
8,9c8
< // Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
< #define Py_LIMITED_API 0x030c0000
---
> #  define Py_LIMITED_API 0x030c0000
13a13
> #include <string.h>               // strlen()
51c51,52
<     const char *name = PyUnicode_AsUTF8AndSize(path, NULL);
---
>     Py_ssize_t name_size;
>     const char *name = PyUnicode_AsUTF8AndSize(path, &name_size);
54a56,59
>     if (strlen(name) != (size_t)name_size) {
>         PyErr_SetString(PyExc_ValueError, "embedded null character");
>         return -1;
>     }
90c95,96
<     const char *name = PyUnicode_AsUTF8AndSize(path, NULL);
---
>     Py_ssize_t name_size;
>     const char *name = PyUnicode_AsUTF8AndSize(path, &name_size);
93a100,103
>     if (strlen(name) != (size_t)name_size) {
>         PyErr_SetString(PyExc_ValueError, "embedded null character");
>         return NULL;
>     }
diff Python-3.13.0a4/Lib/multiprocessing/connection.py Python-3.13.0a5/Lib/multiprocessing/connection.py
478a479
> 
480c481
<         if self._authkey:
---
>         if self._authkey is not None:
diff Python-3.13.0a4/Lib/multiprocessing/queues.py Python-3.13.0a5/Lib/multiprocessing/queues.py
23,24d22
< import _multiprocessing
< 
diff Python-3.13.0a4/Lib/multiprocessing/resource_tracker.py Python-3.13.0a5/Lib/multiprocessing/resource_tracker.py
31a32,34
> def cleanup_noop(name):
>     raise RuntimeError('noop should never be registered or cleaned up')
> 
33c36,37
<     'noop': lambda: None,
---
>     'noop': cleanup_noop,
>     'dummy': lambda name: None,  # Dummy resource used in tests
63a68
>         self._exitcode = None
87c92,93
<             os.waitpid(self._pid, 0)
---
>             _, status = os.waitpid(self._pid, 0)
> 
89a96,101
>             try:
>                 self._exitcode = os.waitstatus_to_exitcode(status)
>             except ValueError:
>                 # os.waitstatus_to_exitcode may raise an exception for invalid values
>                 self._exitcode = None
> 
121a134
>                 self._exitcode = None
223a237,238
>     exit_code = 0
> 
244a260
>                     exit_code = 3
254,257c270,280
<                     warnings.warn(
<                         f'resource_tracker: There appear to be {len(rtype_cache)} '
<                         f'leaked {rtype} objects to clean up at shutdown: {rtype_cache}'
<                     )
---
>                     exit_code = 1
>                     if rtype == 'dummy':
>                         # The test 'dummy' resource is expected to leak.
>                         # We skip the warning (and *only* the warning) for it.
>                         pass
>                     else:
>                         warnings.warn(
>                             f'resource_tracker: There appear to be '
>                             f'{len(rtype_cache)} leaked {rtype} objects to '
>                             f'clean up at shutdown: {rtype_cache}'
>                         )
267a291
>                         exit_code = 2
270a295,296
> 
>         sys.exit(exit_code)
diff Python-3.13.0a4/Lib/multiprocessing/util.py Python-3.13.0a5/Lib/multiprocessing/util.py
105,109c105
<     if sys.platform == "linux":
<         return True
<     if hasattr(sys, 'getandroidapilevel'):
<         return True
<     return False
---
>     return sys.platform in ("linux", "android")
diff Python-3.13.0a4/Lib/test/_test_multiprocessing.py Python-3.13.0a5/Lib/test/_test_multiprocessing.py 
3506a3507,3530
>     def test_empty_authkey(self):
>         # bpo-43952: allow empty bytes as authkey
>         def handler(*args):
>             raise RuntimeError('Connection took too long...')
> 
>         def run(addr, authkey):
>             client = self.connection.Client(addr, authkey=authkey)
>             client.send(1729)
> 
>         key = b''
> 
>         with self.connection.Listener(authkey=key) as listener:
>             thread = threading.Thread(target=run, args=(listener.address, key))
>             thread.start()
>             try:
>                 with listener.accept() as d:
>                     self.assertEqual(d.recv(), 1729)
>             finally:
>                 thread.join()
> 
>         if self.TYPE == 'processes':
>             with self.assertRaises(OSError):
>                 listener.accept()
> 
3973a3998,4012
>     def test_shared_memory_name_with_embedded_null(self):
>         name_tsmb = self._new_shm_name('test01_null')
>         sms = shared_memory.SharedMemory(name_tsmb, create=True, size=512)
>         self.addCleanup(sms.unlink)
>         with self.assertRaises(ValueError):
>             shared_memory.SharedMemory(name_tsmb + '\0a', create=False, size=512)
>         if shared_memory._USE_POSIX:
>             orig_name = sms._name
>             try:
>                 sms._name = orig_name + '\0a'
>                 with self.assertRaises(ValueError):
>                     sms.unlink()
>             finally:
>                 sms._name = orig_name
> 
4108c4147
<     def test_invalid_shared_memory_cration(self):
---
>     def test_invalid_shared_memory_creation(self):
5612c5651
<                 if rtype == "noop":
---
>                 if rtype in ("noop", "dummy"):
5613a5653
>                     # or tests
5732a5773,5804
>     def _test_resource_tracker_leak_resources(self, cleanup):
>         # We use a separate instance for testing, since the main global
>         # _resource_tracker may be used to watch test infrastructure.
>         from multiprocessing.resource_tracker import ResourceTracker
>         tracker = ResourceTracker()
>         tracker.ensure_running()
>         self.assertTrue(tracker._check_alive())
> 
>         self.assertIsNone(tracker._exitcode)
>         tracker.register('somename', 'dummy')
>         if cleanup:
>             tracker.unregister('somename', 'dummy')
>             expected_exit_code = 0
>         else:
>             expected_exit_code = 1
> 
>         self.assertTrue(tracker._check_alive())
>         self.assertIsNone(tracker._exitcode)
>         tracker._stop()
>         self.assertEqual(tracker._exitcode, expected_exit_code)
> 
>     def test_resource_tracker_exit_code(self):
>         """
>         Test the exit code of the resource tracker.
> 
>         If no leaked resources were found, exit code should be 0, otherwise 1
>         """
>         for cleanup in [True, False]:
>             with self.subTest(cleanup=cleanup):
>                 self._test_resource_tracker_leak_resources(
>                     cleanup=cleanup,
>                 )
# ----------------------------------------------------------------------
diff Python-3.13.0a5/Modules/_multiprocessing/semaphore.c Python-3.13.0a6/Modules/_multiprocessing/semaphore.c
83a84
> @critical_section
95c96
< /*[clinic end generated code: output=f9998f0b6b0b0872 input=e5b45f5cbb775166]*/
---
> /*[clinic end generated code: output=f9998f0b6b0b0872 input=079ca779975f3ad6]*/
174a176
> @critical_section
182c184
< /*[clinic end generated code: output=b22f53ba96b0d1db input=ba7e63a961885d3d]*/
---
> /*[clinic end generated code: output=b22f53ba96b0d1db input=9bd62d3645e7a531]*/
299a302
> @critical_section
311c314
< /*[clinic end generated code: output=f9998f0b6b0b0872 input=e5b45f5cbb775166]*/
---
> /*[clinic end generated code: output=f9998f0b6b0b0872 input=079ca779975f3ad6]*/
384a388
> @critical_section
392c396
< /*[clinic end generated code: output=b22f53ba96b0d1db input=ba7e63a961885d3d]*/
---
> /*[clinic end generated code: output=b22f53ba96b0d1db input=9bd62d3645e7a531]*/
585a590
> @critical_section
593c598
< /*[clinic end generated code: output=5ba8213900e517bb input=36fc59b1cd1025ab]*/
---
> /*[clinic end generated code: output=5ba8213900e517bb input=9fa6e0b321b16935]*/
diff Python-3.13.0a5/Lib/test/_test_multiprocessing.py Python-3.13.0a6/Lib/test/_test_multiprocessing.py 
4665c4665
<             sys.setswitchinterval(1e-6)
---
>             support.setswitchinterval(1e-6)
# ----------------------------------------------------------------------
diff Python-3.13.0a6/Modules/_multiprocessing/multiprocessing.c Python-3.13.0b1/Modules/_multiprocessing/multiprocessing.c
279a280
>     {Py_mod_gil, Py_MOD_GIL_NOT_USED},
diff Python-3.13.0a6/Modules/_multiprocessing/posixshmem.c Python-3.13.0b1/Modules/_multiprocessing/posixshmem.c
5c5
< // Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
---
> // Need limited C API version 3.13 for Py_mod_gil
8c8
< #  define Py_LIMITED_API 0x030c0000
---
> #  define Py_LIMITED_API 0x030d0000
130a131
>     {Py_mod_gil, Py_MOD_GIL_NOT_USED},
diff Python-3.13.0a6/Lib/multiprocessing/forkserver.py Python-3.13.0b1/Lib/multiprocessing/forkserver.py
0a1
> import atexit
273a275,276
>                                 atexit._clear()
>                                 atexit.register(util._exit_function)
280a284
>                                 atexit._run_exitfuncs()
diff Python-3.13.0a6/Lib/multiprocessing/popen_fork.py Python-3.13.0b1/Lib/multiprocessing/popen_fork.py
0a1
> import atexit
68a70,71
>                 atexit._clear()
>                 atexit.register(util._exit_function)
72a76
>                 atexit._run_exitfuncs()
diff Python-3.13.0a6/Lib/multiprocessing/popen_spawn_win32.py Python-3.13.0b1/Lib/multiprocessing/popen_spawn_win32.py
5a6
> from subprocess import STARTUPINFO, STARTF_FORCEOFFFEEDBACK
77c78,79
<                     None, None, False, 0, env, None, None)
---
>                     None, None, False, 0, env, None,
>                     STARTUPINFO(dwFlags=STARTF_FORCEOFFFEEDBACK))
diff Python-3.13.0a6/Lib/multiprocessing/process.py Python-3.13.0b1/Lib/multiprocessing/process.py
313,317c313,314
<             try:
<                 self.run()
<                 exitcode = 0
<             finally:
<                 util._exit_function()
---
>             self.run()
>             exitcode = 0
diff Python-3.13.0a6/Lib/test/_test_multiprocessing.py Python-3.13.0b1/Lib/test/_test_multiprocessing.py 
2815d2814
<         gc.collect()  # For PyPy or other GCs.
2816a2816
>         support.gc_collect()  # For PyPy or other GCs.
6163a6164,6186
> class _TestAtExit(BaseTestCase):
> 
>     ALLOWED_TYPES = ('processes',)
> 
>     @classmethod
>     def _write_file_at_exit(self, output_path):
>         import atexit
>         def exit_handler():
>             with open(output_path, 'w') as f:
>                 f.write("deadbeef")
>         atexit.register(exit_handler)
> 
>     def test_atexit(self):
>         # gh-83856
>         with os_helper.temp_dir() as temp_dir:
>             output_path = os.path.join(temp_dir, 'output.txt')
>             p = self.Process(target=self._write_file_at_exit, args=(output_path,))
>             p.start()
>             p.join()
>             with open(output_path) as f:
>                 self.assertEqual(f.read(), 'deadbeef')
> 
> 
# ----------------------------------------------------------------------
diff Python-3.13.0b1/Modules/_multiprocessing Python-3.13.0rc1/Modules/_multiprocessing/
diff Python-3.13.0b1/Modules/_multiprocessing/semaphore.c Python-3.13.0rc1/Modules/_multiprocessing/semaphore.c
684a685
> @critical_section
692c693
< /*[clinic end generated code: output=beeb2f07c858511f input=c5e27d594284690b]*/
---
> /*[clinic end generated code: output=beeb2f07c858511f input=d35c9860992ee790]*/
697a699
> @critical_section
712c714
< /*[clinic end generated code: output=3b37c1a9f8b91a03 input=7d644b64a89903f8]*/
---
> /*[clinic end generated code: output=3b37c1a9f8b91a03 input=1610c8cc3e0e337e]*/
# ----------------------------------------------------------------------
diff Python-3.13.0b1/Modules/_multiprocessing/clinic/ Python-3.13.0rc1/Modules/_multiprocessing/clinic/
diff Python-3.13.0b1/Modules/_multiprocessing/clinic/semaphore.c.h Python-3.13.0rc1/Modules/_multiprocessing/clinic/semaphore.c.h
476c476,482
<     return _multiprocessing_SemLock___enter___impl(self);
---
>     PyObject *return_value = NULL;
> 
>     Py_BEGIN_CRITICAL_SECTION(self);
>     return_value = _multiprocessing_SemLock___enter___impl(self);
>     Py_END_CRITICAL_SECTION();
> 
>     return return_value;
520a527
>     Py_BEGIN_CRITICAL_SECTION(self);
521a529
>     Py_END_CRITICAL_SECTION();
568c576
< /*[clinic end generated code: output=713b597256233716 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=dea36482d23a355f input=a9049054013a1b77]*/
# ----------------------------------------------------------------------
diff Python-3.13.0b1/Lib/test/_test_multiprocessing.py Python-3.13.0rc1/Lib/test/_test_multiprocessing.py 
25d24
< import pathlib
327,328c326,328
<             sys.executable.encode(),      # bytes
<             pathlib.Path(sys.executable)  # os.PathLike
---
>             os.fsencode(sys.executable),  # bytes
>             os_helper.FakePath(sys.executable),  # os.PathLike
>             os_helper.FakePath(os.fsencode(sys.executable)),  # os.PathLike bytes
1334a1335,1351
>     def test_closed_queue_empty_exceptions(self):
>         # Assert that checking the emptiness of an unused closed queue
>         # does not raise an OSError. The rationale is that q.close() is
>         # a no-op upon construction and becomes effective once the queue
>         # has been used (e.g., by calling q.put()).
>         for q in multiprocessing.Queue(), multiprocessing.JoinableQueue():
>             q.close()  # this is a no-op since the feeder thread is None
>             q.join_thread()  # this is also a no-op
>             self.assertTrue(q.empty())
> 
>         for q in multiprocessing.Queue(), multiprocessing.JoinableQueue():
>             q.put('foo')  # make sure that the queue is 'used'
>             q.close()  # close the feeder thread
>             q.join_thread()  # make sure to join the feeder thread
>             with self.assertRaisesRegex(OSError, 'is closed'):
>                 q.empty()
> 
5817a5835,5843
>     def test_empty_exceptions(self):
>         # Assert that checking emptiness of a closed queue raises
>         # an OSError, independently of whether the queue was used
>         # or not. This differs from Queue and JoinableQueue.
>         q = multiprocessing.SimpleQueue()
>         q.close()  # close the pipe
>         with self.assertRaisesRegex(OSError, 'is closed'):
>             q.empty()
> 
