cp -rf py3.13/examples .
cp -rf py3.13/doc .
cp -f py3.13/index.html .
cp -rf py3.13/_multiprocess _multiprocess
cp -rf Python-3.14.0a1/Modules/_multiprocessing Modules/_multiprocess
cp -rf py3.13/multiprocess multiprocess
# ----------------------------------------------------------------------
$ diff /Users/mmckerns/src/Python-3.14.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"
85c85
< _multiprocessing.SemLock.acquire
---
> _multiprocess.SemLock.acquire
94,95c94,95
< _multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking,
<                                       PyObject *timeout_obj)
---
> _multiprocess_SemLock_acquire_impl(SemLockObject *self, int blocking,
>                                    PyObject *timeout_obj)
177c177
< _multiprocessing.SemLock.release
---
> _multiprocess.SemLock.release
183c183
< _multiprocessing_SemLock_release_impl(SemLockObject *self)
---
> _multiprocess_SemLock_release_impl(SemLockObject *self)
303c303
< _multiprocessing.SemLock.acquire
---
> _multiprocess.SemLock.acquire
312,313c312,313
< _multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking,
<                                       PyObject *timeout_obj)
---
> _multiprocess_SemLock_acquire_impl(SemLockObject *self, int blocking,
>                                    PyObject *timeout_obj)
389c389
< _multiprocessing.SemLock.release
---
> _multiprocess.SemLock.release
395c395
< _multiprocessing_SemLock_release_impl(SemLockObject *self)
---
> _multiprocess_SemLock_release_impl(SemLockObject *self)
479c479
< _multiprocessing.SemLock.__new__
---
> _multiprocess.SemLock.__new__
490,491c490,491
< _multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value,
<                               int maxvalue, const char *name, int unlink)
---
> _multiprocess_SemLock_impl(PyTypeObject *type, int kind, int value,
>                            int maxvalue, const char *name, int unlink)
538c538
< _multiprocessing.SemLock._rebuild
---
> _multiprocess.SemLock._rebuild
549,551c549,551
< _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
<                                        int kind, int maxvalue,
<                                        const char *name)
---
> _multiprocess_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
>                                     int kind, int maxvalue,
>                                     const char *name)
591c591
< _multiprocessing.SemLock._count
---
> _multiprocess.SemLock._count
597c597
< _multiprocessing_SemLock__count_impl(SemLockObject *self)
---
> _multiprocess_SemLock__count_impl(SemLockObject *self)
604c604
< _multiprocessing.SemLock._is_mine
---
> _multiprocess.SemLock._is_mine
610c610
< _multiprocessing_SemLock__is_mine_impl(SemLockObject *self)
---
> _multiprocess_SemLock__is_mine_impl(SemLockObject *self)
618c618
< _multiprocessing.SemLock._get_value
---
> _multiprocess.SemLock._get_value
624c624
< _multiprocessing_SemLock__get_value_impl(SemLockObject *self)
---
> _multiprocess_SemLock__get_value_impl(SemLockObject *self)
643c643
< _multiprocessing.SemLock._is_zero
---
> _multiprocess.SemLock._is_zero
649c649
< _multiprocessing_SemLock__is_zero_impl(SemLockObject *self)
---
> _multiprocess_SemLock__is_zero_impl(SemLockObject *self)
671c671
< _multiprocessing.SemLock._after_fork
---
> _multiprocess.SemLock._after_fork
677c677
< _multiprocessing_SemLock__after_fork_impl(SemLockObject *self)
---
> _multiprocess_SemLock__after_fork_impl(SemLockObject *self)
686c686
< _multiprocessing.SemLock.__enter__
---
> _multiprocess.SemLock.__enter__
692c692
< _multiprocessing_SemLock___enter___impl(SemLockObject *self)
---
> _multiprocess_SemLock___enter___impl(SemLockObject *self)
695c695
<     return _multiprocessing_SemLock_acquire_impl(self, 1, Py_None);
---
>     return _multiprocess_SemLock_acquire_impl(self, 1, Py_None);
700c700
< _multiprocessing.SemLock.__exit__
---
> _multiprocess.SemLock.__exit__
711,713c711,713
< _multiprocessing_SemLock___exit___impl(SemLockObject *self,
<                                        PyObject *exc_type,
<                                        PyObject *exc_value, PyObject *exc_tb)
---
> _multiprocess_SemLock___exit___impl(SemLockObject *self,
>                                     PyObject *exc_type,
>                                     PyObject *exc_value, PyObject *exc_tb)
716c716
<     return _multiprocessing_SemLock_release_impl(self);
---
>     return _multiprocess_SemLock_release_impl(self);
731,740c731,740
<     _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
771c771
<     {Py_tp_new, _multiprocessing_SemLock},
---
>     {Py_tp_new, _multiprocess_SemLock},
779c779
<     .name = "_multiprocessing.SemLock",
---
>     .name = "_multiprocess.SemLock",
$ diff /Users/mmckerns/src/Python-3.14.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 /Users/mmckerns/src/Python-3.14.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)
180,182c180,182
<     _MULTIPROCESSING_CLOSESOCKET_METHODDEF
<     _MULTIPROCESSING_RECV_METHODDEF
<     _MULTIPROCESSING_SEND_METHODDEF
---
>     _MULTIPROCESS_CLOSESOCKET_METHODDEF
>     _MULTIPROCESS_RECV_METHODDEF
>     _MULTIPROCESS_SEND_METHODDEF
185c185
<     _MULTIPROCESSING_SEM_UNLINK_METHODDEF
---
>     _MULTIPROCESS_SEM_UNLINK_METHODDEF
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},
284c284
< static struct PyModuleDef multiprocessing_module = {
---
> static struct PyModuleDef multiprocess_module = {
286c286
<     .m_name = "_multiprocessing",
---
>     .m_name = "_multiprocess",
289c289
<     .m_slots = multiprocessing_slots,
---
>     .m_slots = multiprocess_slots,
293c293
< PyInit__multiprocessing(void)
---
> PyInit__multiprocess(void)
295c295
<     return PyModuleDef_Init(&multiprocessing_module);
---
>     return PyModuleDef_Init(&multiprocess_module);
# ----------------------------------------------------------------------
diff Python-3.13.0rc1/Lib/multiprocessing/connection.py Python-3.14.0a1/Lib/multiprocessing/connection.py
13a14
> import itertools
18d18
< import time
20c20
< import itertools
---
> import time
42c42,44
< BUFSIZE = 8192
---
> # 64 KiB is the default PIPE buffer size of most POSIX platforms.
> BUFSIZE = 64 * 1024
> 
395c397,398
<             chunk = read(handle, remaining)
---
>             to_read = min(BUFSIZE, remaining)
>             chunk = read(handle, to_read)
diff Python-3.13.0rc1/Lib/multiprocessing/context.py Python-3.14.0a1/Lib/multiprocessing/context.py
170c170
<         from . import connection
---
>         from . import connection  # noqa: F401
262,268c262,267
<         if sys.platform == 'win32':
<             return ['spawn']
<         else:
<             methods = ['spawn', 'fork'] if sys.platform == 'darwin' else ['fork', 'spawn']
<             if reduction.HAVE_SEND_HANDLE:
<                 methods.append('forkserver')
<             return methods
---
>         default = self._default_context.get_start_method()
>         start_method_names = [default]
>         start_method_names.extend(
>             name for name in _concrete_contexts if name != default
>         )
>         return start_method_names
323,326c322,326
<     if sys.platform == 'darwin':
<         # bpo-33725: running arbitrary code after fork() is no longer reliable
<         # on macOS since macOS 10.14 (Mojave). Use spawn by default instead.
<         _default_context = DefaultContext(_concrete_contexts['spawn'])
---
>     # bpo-33725: running arbitrary code after fork() is no longer reliable
>     # on macOS since macOS 10.14 (Mojave). Use spawn by default instead.
>     # gh-84559: We changed everyones default to a thread safeish one in 3.14.
>     if reduction.HAVE_SEND_HANDLE and sys.platform != 'darwin':
>         _default_context = DefaultContext(_concrete_contexts['forkserver'])
328c328
<         _default_context = DefaultContext(_concrete_contexts['fork'])
---
>         _default_context = DefaultContext(_concrete_contexts['spawn'])
330c330
< else:
---
> else:  # Windows
diff Python-3.13.0rc1/Lib/multiprocessing/managers.py Python-3.14.0a1/Lib/multiprocessing/managers.py
1155,1158c1155,1158
<     '__add__', '__contains__', '__delitem__', '__getitem__', '__len__',
<     '__mul__', '__reversed__', '__rmul__', '__setitem__',
<     'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove',
<     'reverse', 'sort', '__imul__'
---
>     '__add__', '__contains__', '__delitem__', '__getitem__', '__imul__',
>     '__len__', '__mul__', '__reversed__', '__rmul__', '__setitem__',
>     'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop',
>     'remove', 'reverse', 'sort',
1172,1173c1172,1174
<     '__contains__', '__delitem__', '__getitem__', '__iter__', '__len__',
<     '__setitem__', 'clear', 'copy', 'get', 'items',
---
>     '__contains__', '__delitem__', '__getitem__', '__ior__', '__iter__',
>     '__len__', '__or__', '__reversed__', '__ror__',
>     '__setitem__', 'clear', 'copy', 'fromkeys', 'get', 'items',
1180c1181,1183
<     __class_getitem__ = classmethod(types.GenericAlias)
---
>     def __ior__(self, value):
>         self._callmethod('__ior__', (value,))
>         return self
1181a1185
>     __class_getitem__ = classmethod(types.GenericAlias)
diff Python-3.13.0rc1/Lib/multiprocessing/shared_memory.py Python-3.14.0a1/Lib/multiprocessing/shared_memory.py
542c542
<             raise ValueError(f"{value!r} not in this container")
---
>             raise ValueError("ShareableList.index(x): x not in list")
diff Python-3.13.0rc1/Lib/multiprocessing/util.py Python-3.14.0a1/Lib/multiprocessing/util.py
17c17
< from subprocess import _args_from_interpreter_flags
---
> from subprocess import _args_from_interpreter_flags  # noqa: F401
448,449c448
<             False, False, -1, None, None, None, -1, None,
<             subprocess._USE_VFORK)
---
>             False, False, -1, None, None, None, -1, None)
$ diff Python-3.13.0rc1/Lib/test/_test_multiprocessing.py Python-3.14.0a1/Lib/test/_test_multiprocessing.py
5556c5556
<     def test_get_all(self):
---
>     def test_get_all_start_methods(self):
5557a5558
>         self.assertIn('spawn', methods)
5559a5561,5565
>         elif sys.platform == 'darwin':
>             self.assertEqual(methods[0], 'spawn')  # The default is first.
>             # Whether these work or not, they remain available on macOS.
>             self.assertIn('fork', methods)
>             self.assertIn('forkserver', methods)
5561,5564c5567,5578
<             self.assertTrue(methods == ['fork', 'spawn'] or
<                             methods == ['spawn', 'fork'] or
<                             methods == ['fork', 'spawn', 'forkserver'] or
<                             methods == ['spawn', 'fork', 'forkserver'])
---
>             # POSIX
>             self.assertIn('fork', methods)
>             if other_methods := set(methods) - {'fork', 'spawn'}:
>                 # If there are more than those two, forkserver must be one.
>                 self.assertEqual({'forkserver'}, other_methods)
>             # The default is the first method in the list.
>             self.assertIn(methods[0], {'forkserver', 'spawn'},
>                           msg='3.14+ default must not be fork')
>             if methods[0] == 'spawn':
>                 # Confirm that the current default selection logic prefers
>                 # forkserver vs spawn when available.
>                 self.assertNotIn('forkserver', methods)
6092a6107,6122
>         obj += [7]
>         case.assertIsInstance(obj, multiprocessing.managers.ListProxy)
>         case.assertListEqual(list(obj), [5, 7])
>         obj *= 2
>         case.assertIsInstance(obj, multiprocessing.managers.ListProxy)
>         case.assertListEqual(list(obj), [5, 7, 5, 7])
>         double_obj = obj * 2
>         case.assertIsInstance(double_obj, list)
>         case.assertListEqual(list(double_obj), [5, 7, 5, 7, 5, 7, 5, 7])
>         double_obj = 2 * obj
>         case.assertIsInstance(double_obj, list)
>         case.assertListEqual(list(double_obj), [5, 7, 5, 7, 5, 7, 5, 7])
>         copied_obj = obj.copy()
>         case.assertIsInstance(copied_obj, list)
>         case.assertListEqual(list(copied_obj), [5, 7, 5, 7])
>         obj.extend(double_obj + copied_obj)
6097,6098c6127,6130
<         case.assertEqual(len(obj), 1)
<         case.assertEqual(obj.pop(0), 5)
---
>         case.assertEqual(len(obj), 16)
>         case.assertEqual(obj.pop(0), 7)
>         obj.clear()
>         case.assertEqual(len(obj), 0)
6117c6149,6171
<         case.assertTupleEqual(obj.popitem(), ('foo', 5))
---
>         obj |= {'bar': 6}
>         case.assertIsInstance(obj, multiprocessing.managers.DictProxy)
>         case.assertDictEqual(dict(obj), {'foo': 5, 'bar': 6})
>         x = reversed(obj)
>         case.assertIsInstance(x, type(iter([])))
>         case.assertListEqual(list(x), ['bar', 'foo'])
>         x = {'bar': 7, 'baz': 7} | obj
>         case.assertIsInstance(x, dict)
>         case.assertDictEqual(dict(x), {'foo': 5, 'bar': 6, 'baz': 7})
>         x = obj | {'bar': 7, 'baz': 7}
>         case.assertIsInstance(x, dict)
>         case.assertDictEqual(dict(x), {'foo': 5, 'bar': 7, 'baz': 7})
>         x = obj.fromkeys(['bar'], 6)
>         case.assertIsInstance(x, dict)
>         case.assertDictEqual(x, {'bar': 6})
>         x = obj.popitem()
>         case.assertIsInstance(x, tuple)
>         case.assertTupleEqual(x, ('bar', 6))
>         obj.setdefault('bar', 0)
>         obj.update({'bar': 7})
>         case.assertEqual(obj.pop('bar'), 7)
>         obj.clear()
>         case.assertEqual(len(obj), 0)

# ----------------------------------------------------------------------
diff Python-3.14.0a1/Modules/_multiprocessing/semaphore.c Python-3.14.0a2/Modules/_multiprocessing/semaphore.c
17a18
> // These match the values in Lib/multiprocessing/synchronize.py
diff Python-3.14.0a1/Modules/_multiprocessing/clinic/semaphore.c.h Python-3.14.0a2/Modules/_multiprocessing/clinic/semaphore.c.h
61c61,62
<     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf);
---
>     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
>             /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
166c167,168
<     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf);
---
>     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
>             /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
266c268,269
<     fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 5, 5, 0, argsbuf);
---
>     fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
>             /*minpos*/ 5, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
576c579
< /*[clinic end generated code: output=dea36482d23a355f input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=9023d3e48a24afd2 input=a9049054013a1b77]*/
diff Python-3.14.0a1/Lib/multiprocessing/forkserver.py Python-3.14.0a2/Lib/multiprocessing/forkserver.py
170a171,172
>         if sys_path is not None:
>             sys.path[:] = sys_path
diff Python-3.14.0a1/Lib/multiprocessing/managers.py Python-3.14.0a2/Lib/multiprocessing/managers.py
20a21
> import collections.abc
760a762,765
>     # Each instance gets a `_serial` number. Unlike `id(...)`, this number
>     # is never reused.
>     _next_serial = 1
> 
764,767c769,775
<             tls_idset = BaseProxy._address_to_local.get(token.address, None)
<             if tls_idset is None:
<                 tls_idset = util.ForkAwareLocal(), ProcessLocalSet()
<                 BaseProxy._address_to_local[token.address] = tls_idset
---
>             tls_serials = BaseProxy._address_to_local.get(token.address, None)
>             if tls_serials is None:
>                 tls_serials = util.ForkAwareLocal(), ProcessLocalSet()
>                 BaseProxy._address_to_local[token.address] = tls_serials
> 
>             self._serial = BaseProxy._next_serial
>             BaseProxy._next_serial += 1
771c779
<         self._tls = tls_idset[0]
---
>         self._tls = tls_serials[0]
773,774c781,782
<         # self._idset is used to record the identities of all shared
<         # objects for which the current process owns references and
---
>         # self._all_serials is a set used to record the identities of all
>         # shared objects for which the current process owns references and
776c784
<         self._idset = tls_idset[1]
---
>         self._all_serials = tls_serials[1]
859c867
<         self._idset.add(self._id)
---
>         self._all_serials.add(self._serial)
865,866c873,874
<             args=(self._token, self._authkey, state,
<                   self._tls, self._idset, self._Client),
---
>             args=(self._token, self._serial, self._authkey, state,
>                   self._tls, self._all_serials, self._Client),
871,872c879,880
<     def _decref(token, authkey, state, tls, idset, _Client):
<         idset.discard(token.id)
---
>     def _decref(token, serial, authkey, state, tls, idset, _Client):
>         idset.discard(serial)
1169a1178
> collections.abc.MutableSequence.register(BaseListProxy)
1171c1180
< _BaseDictProxy = MakeProxyType('DictProxy', (
---
> _BaseDictProxy = MakeProxyType('_BaseDictProxy', (
1186a1196,1197
> collections.abc.MutableMapping.register(_BaseDictProxy)
> 
diff Python-3.14.0a1/Lib/multiprocessing/synchronize.py Python-3.14.0a2/Lib/multiprocessing/synchronize.py
24,26c24
< # Try to import the mp.synchronize module cleanly, if it fails
< # raise ImportError for platforms lacking a working sem_open implementation.
< # See issue 3770
---
> # TODO: Do any platforms still lack a functioning sem_open?
29c27
< except (ImportError):
---
> except ImportError:
31,33c29
<                       " implementation, therefore, the required" +
<                       " synchronization primitives needed will not" +
<                       " function, see issue 3770.")
---
>                       " implementation. https://github.com/python/cpython/issues/48020.")
39c35,38
< RECURSIVE_MUTEX, SEMAPHORE = list(range(2))
---
> # These match the enum in Modules/_multiprocessing/semaphore.c
> RECURSIVE_MUTEX = 0
> SEMAPHORE = 1
> 
177c176
<             elif self._semlock._get_value() == 1:
---
>             elif not self._semlock._is_zero():
203c202
<             elif self._semlock._get_value() == 1:
---
>             elif not self._semlock._is_zero():
diff Python-3.14.0a1/Lib/multiprocessing/util.py Python-3.14.0a2/Lib/multiprocessing/util.py
441d440
<     import subprocess
diff Python-3.14.0a1/Lib/test/_test_multiprocessing.py Python-3.14.0a2/Lib/test/_test_multiprocessing.py 
14a15
> import importlib
18a20
> import collections.abc
21a24
> import shutil
23a27
> import tempfile
256a261,263
>     # If not empty, limit which start method suites run this class.
>     START_METHODS: set[str] = set()
>     start_method = None  # set by install_tests_in_module_dict()
1364a1372,1431
>     @staticmethod
>     def _acquire(lock, l=None):
>         lock.acquire()
>         if l is not None:
>             l.append(repr(lock))
> 
>     @staticmethod
>     def _acquire_event(lock, event):
>         lock.acquire()
>         event.set()
>         time.sleep(1.0)
> 
>     def test_repr_lock(self):
>         if self.TYPE != 'processes':
>             self.skipTest('test not appropriate for {}'.format(self.TYPE))
> 
>         lock = self.Lock()
>         self.assertEqual(f'<Lock(owner=None)>', repr(lock))
> 
>         lock.acquire()
>         self.assertEqual(f'<Lock(owner=MainProcess)>', repr(lock))
>         lock.release()
> 
>         tname = 'T1'
>         l = []
>         t = threading.Thread(target=self._acquire,
>                              args=(lock, l),
>                              name=tname)
>         t.start()
>         time.sleep(0.1)
>         self.assertEqual(f'<Lock(owner=MainProcess|{tname})>', l[0])
>         lock.release()
> 
>         t = threading.Thread(target=self._acquire,
>                              args=(lock,),
>                              name=tname)
>         t.start()
>         time.sleep(0.1)
>         self.assertEqual('<Lock(owner=SomeOtherThread)>', repr(lock))
>         lock.release()
> 
>         pname = 'P1'
>         l = multiprocessing.Manager().list()
>         p = self.Process(target=self._acquire,
>                          args=(lock, l),
>                          name=pname)
>         p.start()
>         p.join()
>         self.assertEqual(f'<Lock(owner={pname})>', l[0])
> 
>         lock = self.Lock()
>         event = self.Event()
>         p = self.Process(target=self._acquire_event,
>                          args=(lock, event),
>                          name='P2')
>         p.start()
>         event.wait()
>         self.assertEqual(f'<Lock(owner=SomeOtherProcess)>', repr(lock))
>         p.terminate()
> 
1371a1439,1500
>     @staticmethod
>     def _acquire_release(lock, timeout, l=None, n=1):
>         for _ in range(n):
>             lock.acquire()
>         if l is not None:
>             l.append(repr(lock))
>         time.sleep(timeout)
>         for _ in range(n):
>             lock.release()
> 
>     def test_repr_rlock(self):
>         if self.TYPE != 'processes':
>             self.skipTest('test not appropriate for {}'.format(self.TYPE))
> 
>         lock = self.RLock()
>         self.assertEqual('<RLock(None, 0)>', repr(lock))
> 
>         n = 3
>         for _ in range(n):
>             lock.acquire()
>         self.assertEqual(f'<RLock(MainProcess, {n})>', repr(lock))
>         for _ in range(n):
>             lock.release()
> 
>         t, l = [], []
>         for i in range(n):
>             t.append(threading.Thread(target=self._acquire_release,
>                                       args=(lock, 0.1, l, i+1),
>                                       name=f'T{i+1}'))
>             t[-1].start()
>         for t_ in t:
>             t_.join()
>         for i in range(n):
>             self.assertIn(f'<RLock(MainProcess|T{i+1}, {i+1})>', l)
> 
> 
>         t = threading.Thread(target=self._acquire_release,
>                                  args=(lock, 0.2),
>                                  name=f'T1')
>         t.start()
>         time.sleep(0.1)
>         self.assertEqual('<RLock(SomeOtherThread, nonzero)>', repr(lock))
>         time.sleep(0.2)
> 
>         pname = 'P1'
>         l = multiprocessing.Manager().list()
>         p = self.Process(target=self._acquire_release,
>                          args=(lock, 0.1, l),
>                          name=pname)
>         p.start()
>         p.join()
>         self.assertEqual(f'<RLock({pname}, 1)>', l[0])
> 
>         event = self.Event()
>         lock = self.RLock()
>         p = self.Process(target=self._acquire_event,
>                          args=(lock, event))
>         p.start()
>         event.wait()
>         self.assertEqual('<RLock(SomeOtherProcess, nonzero)>', repr(lock))
>         p.join()
> 
2333a2463,2479
>     def test_list_isinstance(self):
>         a = self.list()
>         self.assertIsInstance(a, collections.abc.MutableSequence)
> 
>         # MutableSequence also has __iter__, but we can iterate over
>         # ListProxy using __getitem__ instead. Adding __iter__ to ListProxy
>         # would change the behavior of a list modified during iteration.
>         mutable_sequence_methods = (
>             '__contains__', '__delitem__', '__getitem__', '__iadd__',
>             '__len__', '__reversed__', '__setitem__', 'append',
>             'clear', 'count', 'extend', 'index', 'insert', 'pop', 'remove',
>             'reverse',
>         )
>         for name in mutable_sequence_methods:
>             with self.subTest(name=name):
>                 self.assertTrue(callable(getattr(a, name)))
> 
2373a2520,2532
>     def test_dict_isinstance(self):
>         a = self.dict()
>         self.assertIsInstance(a, collections.abc.MutableMapping)
> 
>         mutable_mapping_methods = (
>             '__contains__', '__delitem__', '__eq__', '__getitem__', '__iter__',
>             '__len__', '__ne__', '__setitem__', 'clear', 'get', 'items',
>             'keys', 'pop', 'popitem', 'setdefault', 'update', 'values',
>         )
>         for name in mutable_mapping_methods:
>             with self.subTest(name=name):
>                 self.assertTrue(callable(getattr(a, name)))
> 
5763a5923,5924
>     @unittest.skipIf(sys.platform.startswith("netbsd"),
>                      "gh-125620: Skip on NetBSD due to long wait for SIGKILL process termination.")
6266a6428,6497
> class _TestSpawnedSysPath(BaseTestCase):
>     """Test that sys.path is setup in forkserver and spawn processes."""
> 
>     ALLOWED_TYPES = {'processes'}
>     # Not applicable to fork which inherits everything from the process as is.
>     START_METHODS = {"forkserver", "spawn"}
> 
>     def setUp(self):
>         self._orig_sys_path = list(sys.path)
>         self._temp_dir = tempfile.mkdtemp(prefix="test_sys_path-")
>         self._mod_name = "unique_test_mod"
>         module_path = os.path.join(self._temp_dir, f"{self._mod_name}.py")
>         with open(module_path, "w", encoding="utf-8") as mod:
>             mod.write("# A simple test module\n")
>         sys.path[:] = [p for p in sys.path if p]  # remove any existing ""s
>         sys.path.insert(0, self._temp_dir)
>         sys.path.insert(0, "")  # Replaced with an abspath in child.
>         self.assertIn(self.start_method, self.START_METHODS)
>         self._ctx = multiprocessing.get_context(self.start_method)
> 
>     def tearDown(self):
>         sys.path[:] = self._orig_sys_path
>         shutil.rmtree(self._temp_dir, ignore_errors=True)
> 
>     @staticmethod
>     def enq_imported_module_names(queue):
>         queue.put(tuple(sys.modules))
> 
>     def test_forkserver_preload_imports_sys_path(self):
>         if self._ctx.get_start_method() != "forkserver":
>             self.skipTest("forkserver specific test.")
>         self.assertNotIn(self._mod_name, sys.modules)
>         multiprocessing.forkserver._forkserver._stop()  # Must be fresh.
>         self._ctx.set_forkserver_preload(
>             ["test.test_multiprocessing_forkserver", self._mod_name])
>         q = self._ctx.Queue()
>         proc = self._ctx.Process(
>                 target=self.enq_imported_module_names, args=(q,))
>         proc.start()
>         proc.join()
>         child_imported_modules = q.get()
>         q.close()
>         self.assertIn(self._mod_name, child_imported_modules)
> 
>     @staticmethod
>     def enq_sys_path_and_import(queue, mod_name):
>         queue.put(sys.path)
>         try:
>             importlib.import_module(mod_name)
>         except ImportError as exc:
>             queue.put(exc)
>         else:
>             queue.put(None)
> 
>     def test_child_sys_path(self):
>         q = self._ctx.Queue()
>         proc = self._ctx.Process(
>                 target=self.enq_sys_path_and_import, args=(q, self._mod_name))
>         proc.start()
>         proc.join()
>         child_sys_path = q.get()
>         import_error = q.get()
>         q.close()
>         self.assertNotIn("", child_sys_path)  # replaced by an abspath
>         self.assertIn(self._temp_dir, child_sys_path)  # our addition
>         # ignore the first element, it is the absolute "" replacement
>         self.assertEqual(child_sys_path[1:], sys.path[1:])
>         self.assertIsNone(import_error, msg=f"child could not import {self._mod_name}")
> 
> 
6460a6692,6693
>             if base.START_METHODS and start_method not in base.START_METHODS:
>                 continue  # class not intended for this start method.
6473a6707
>                 Temp.start_method = start_method
# ----------------------------------------------------------------------
diff Python-3.14.0a2/Lib/multiprocessing/connection.py Python-3.14.0a3/Lib/multiprocessing/connection.py
183a184,187
>     def _detach(self):
>         """Stop managing the underlying file descriptor or handle."""
>         self._handle = None
> 
962c966
<         raise AuthenticationError('challenge too short: {len(message)} bytes')
---
>         raise AuthenticationError(f'challenge too short: {len(message)} bytes')
diff Python-3.14.0a2/Lib/multiprocessing/forkserver.py Python-3.14.0a3/Lib/multiprocessing/forkserver.py
11a12
> from . import AuthenticationError
27a29
> _AUTHKEY_LEN = 32  # <= PIPEBUF so it fits a single write to an empty pipe.
35a38
>         self._forkserver_authkey = None
61a65
>         self._forkserver_authkey = None
85a90
>         assert self._forkserver_authkey
95a101,112
>                 client.setblocking(True)
>                 wrapped_client = connection.Connection(client.fileno())
>                 # The other side of this exchange happens in the child as
>                 # implemented in main().
>                 try:
>                     connection.answer_challenge(
>                             wrapped_client, self._forkserver_authkey)
>                     connection.deliver_challenge(
>                             wrapped_client, self._forkserver_authkey)
>                 finally:
>                     wrapped_client._detach()
>                     del wrapped_client
122a140
>                 self._forkserver_authkey = None
133c151
<                 data = {x: y for x, y in data.items() if x in desired_keys}
---
>                 main_kws = {x: y for x, y in data.items() if x in desired_keys}
135c153
<                 data = {}
---
>                 main_kws = {}
146a165,166
>                 # A short lived pipe to initialize the forkserver authkey.
>                 authkey_r, authkey_w = os.pipe()
148c168,169
<                     fds_to_pass = [listener.fileno(), alive_r]
---
>                     fds_to_pass = [listener.fileno(), alive_r, authkey_r]
>                     main_kws['authkey_r'] = authkey_r
150c171
<                             data)
---
>                             main_kws)
156a178
>                     os.close(authkey_w)
159a182,189
>                     os.close(authkey_r)
>                 # Authenticate our control socket to prevent access from
>                 # processes we have not shared this key with.
>                 try:
>                     self._forkserver_authkey = os.urandom(_AUTHKEY_LEN)
>                     os.write(authkey_w, self._forkserver_authkey)
>                 finally:
>                     os.close(authkey_w)
168,169c198,209
< def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
<     '''Run forkserver.'''
---
> def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
>          *, authkey_r=None):
>     """Run forkserver."""
>     if authkey_r is not None:
>         try:
>             authkey = os.read(authkey_r, _AUTHKEY_LEN)
>             assert len(authkey) == _AUTHKEY_LEN, f'{len(authkey)} < {_AUTHKEY_LEN}'
>         finally:
>             os.close(authkey_r)
>     else:
>         authkey = b''
> 
260,261c300,317
<                         # Receive fds from client
<                         fds = reduction.recvfds(s, MAXFDS_TO_SEND + 1)
---
>                         try:
>                             if authkey:
>                                 wrapped_s = connection.Connection(s.fileno())
>                                 # The other side of this exchange happens in
>                                 # in connect_to_new_process().
>                                 try:
>                                     connection.deliver_challenge(
>                                             wrapped_s, authkey)
>                                     connection.answer_challenge(
>                                             wrapped_s, authkey)
>                                 finally:
>                                     wrapped_s._detach()
>                                     del wrapped_s
>                             # Receive fds from client
>                             fds = reduction.recvfds(s, MAXFDS_TO_SEND + 1)
>                         except (EOFError, BrokenPipeError, AuthenticationError):
>                             s.close()
>                             continue
diff Python-3.14.0a2/Lib/multiprocessing/reduction.py Python-3.14.0a3/Lib/multiprocessing/reduction.py
142,144d141
<     # On MacOSX we should acknowledge receipt of fds -- see Issue14669
<     ACKNOWLEDGE = sys.platform == 'darwin'
< 
150c147
<         if ACKNOWLEDGE and sock.recv(1) != b'A':
---
>         if sock.recv(1) != b'A':
161,162c158,162
<             if ACKNOWLEDGE:
<                 sock.send(b'A')
---
>             # We send/recv an Ack byte after the fds to work around an old
>             # macOS bug; it isn't clear if this is still required but it
>             # makes unit testing fd sending easier.
>             # See: https://github.com/python/cpython/issues/58874
>             sock.send(b'A')  # Acknowledge
diff Python-3.14.0a2/Lib/test/_test_multiprocessing.py Python-3.14.0a3/Lib/test/_test_multiprocessing.py 
849,850c849,850
<     @classmethod
<     def _sleep_and_set_event(self, evt, delay=0.0):
---
>     @staticmethod
>     def _sleep_and_set_event(evt, delay=0.0):
900a901,950
>     def test_forkserver_auth_is_enabled(self):
>         if self.TYPE == "threads":
>             self.skipTest(f"test not appropriate for {self.TYPE}")
>         if multiprocessing.get_start_method() != "forkserver":
>             self.skipTest("forkserver start method specific")
> 
>         forkserver = multiprocessing.forkserver._forkserver
>         forkserver.ensure_running()
>         self.assertTrue(forkserver._forkserver_pid)
>         authkey = forkserver._forkserver_authkey
>         self.assertTrue(authkey)
>         self.assertGreater(len(authkey), 15)
>         addr = forkserver._forkserver_address
>         self.assertTrue(addr)
> 
>         # Demonstrate that a raw auth handshake, as Client performs, does not
>         # raise an error.
>         client = multiprocessing.connection.Client(addr, authkey=authkey)
>         client.close()
> 
>         # That worked, now launch a quick process.
>         proc = self.Process(target=sys.exit)
>         proc.start()
>         proc.join()
>         self.assertEqual(proc.exitcode, 0)
> 
>     def test_forkserver_without_auth_fails(self):
>         if self.TYPE == "threads":
>             self.skipTest(f"test not appropriate for {self.TYPE}")
>         if multiprocessing.get_start_method() != "forkserver":
>             self.skipTest("forkserver start method specific")
> 
>         forkserver = multiprocessing.forkserver._forkserver
>         forkserver.ensure_running()
>         self.assertTrue(forkserver._forkserver_pid)
>         authkey_len = len(forkserver._forkserver_authkey)
>         with unittest.mock.patch.object(
>                 forkserver, '_forkserver_authkey', None):
>             # With an incorrect authkey we should get an auth rejection
>             # rather than the above protocol error.
>             forkserver._forkserver_authkey = b'T' * authkey_len
>             proc = self.Process(target=sys.exit)
>             with self.assertRaises(multiprocessing.AuthenticationError):
>                 proc.start()
>             del proc
> 
>         # authkey restored, launching processes should work again.
>         proc = self.Process(target=sys.exit)
>         proc.start()
>         proc.join()
# ----------------------------------------------------------------------
diff Python-3.14.0a3/Lib/multiprocessing/resource_tracker.py Python-3.14.0a4/Lib/multiprocessing/resource_tracker.py
157a158
>                 prev_sigmask = None
160c161
<                         signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS)
---
>                         prev_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS)
163,164c164,165
<                     if _HAVE_SIGMASK:
<                         signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS)
---
>                     if prev_sigmask is not None:
>                         signal.pthread_sigmask(signal.SIG_SETMASK, prev_sigmask)
diff Python-3.14.0a3/Lib/test/_test_multiprocessing.py Python-3.14.0a4/Lib/test/_test_multiprocessing.py 
6047a6048,6068
>     @unittest.skipUnless(hasattr(signal, "pthread_sigmask"), "pthread_sigmask is not available")
>     def test_resource_tracker_blocked_signals(self):
>         #
>         # gh-127586: Check that resource_tracker does not override blocked signals of caller.
>         #
>         from multiprocessing.resource_tracker import ResourceTracker
>         orig_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, set())
>         signals = {signal.SIGTERM, signal.SIGINT, signal.SIGUSR1}
> 
>         try:
>             for sig in signals:
>                 signal.pthread_sigmask(signal.SIG_SETMASK, {sig})
>                 self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig})
>                 tracker = ResourceTracker()
>                 tracker.ensure_running()
>                 self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig})
>                 tracker._stop()
>         finally:
>             # restore sigmask to what it was before executing test
>             signal.pthread_sigmask(signal.SIG_SETMASK, orig_sigmask)
> 
# ----------------------------------------------------------------------
diff Python-3.14.0a4/Modules/_multiprocessing/semaphore.c Python-3.14.0a5/Modules/_multiprocessing/semaphore.c
30a31,32
> #define _SemLockObject_CAST(op) ((SemLockObject *)(op))
> 
579c581
< semlock_dealloc(SemLockObject* self)
---
> semlock_dealloc(PyObject *op)
580a583
>     SemLockObject *self = _SemLockObject_CAST(op);
721c724
< semlock_traverse(SemLockObject *s, visitproc visit, void *arg)
---
> semlock_traverse(PyObject *s, visitproc visit, void *arg)
diff Python-3.14.0a4/Modules/_multiprocessing/clinic/semaphore.c.h Python-3.14.0a5/Modules/_multiprocessing/clinic/semaphore.c.h
28c28
< _multiprocessing_SemLock_acquire(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
---
> _multiprocessing_SemLock_acquire(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
81c81
<     return_value = _multiprocessing_SemLock_acquire_impl(self, blocking, timeout_obj);
---
>     return_value = _multiprocessing_SemLock_acquire_impl((SemLockObject *)self, blocking, timeout_obj);
105c105
< _multiprocessing_SemLock_release(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock_release(PyObject *self, PyObject *Py_UNUSED(ignored))
110c110
<     return_value = _multiprocessing_SemLock_release_impl(self);
---
>     return_value = _multiprocessing_SemLock_release_impl((SemLockObject *)self);
134c134
< _multiprocessing_SemLock_acquire(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
---
> _multiprocessing_SemLock_acquire(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
187c187
<     return_value = _multiprocessing_SemLock_acquire_impl(self, blocking, timeout_obj);
---
>     return_value = _multiprocessing_SemLock_acquire_impl((SemLockObject *)self, blocking, timeout_obj);
211c211
< _multiprocessing_SemLock_release(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock_release(PyObject *self, PyObject *Py_UNUSED(ignored))
216c216
<     return_value = _multiprocessing_SemLock_release_impl(self);
---
>     return_value = _multiprocessing_SemLock_release_impl((SemLockObject *)self);
361c361
< _multiprocessing_SemLock__count(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock__count(PyObject *self, PyObject *Py_UNUSED(ignored))
366c366
<     return_value = _multiprocessing_SemLock__count_impl(self);
---
>     return_value = _multiprocessing_SemLock__count_impl((SemLockObject *)self);
389c389
< _multiprocessing_SemLock__is_mine(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock__is_mine(PyObject *self, PyObject *Py_UNUSED(ignored))
391c391
<     return _multiprocessing_SemLock__is_mine_impl(self);
---
>     return _multiprocessing_SemLock__is_mine_impl((SemLockObject *)self);
411c411
< _multiprocessing_SemLock__get_value(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock__get_value(PyObject *self, PyObject *Py_UNUSED(ignored))
413c413
<     return _multiprocessing_SemLock__get_value_impl(self);
---
>     return _multiprocessing_SemLock__get_value_impl((SemLockObject *)self);
433c433
< _multiprocessing_SemLock__is_zero(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock__is_zero(PyObject *self, PyObject *Py_UNUSED(ignored))
435c435
<     return _multiprocessing_SemLock__is_zero_impl(self);
---
>     return _multiprocessing_SemLock__is_zero_impl((SemLockObject *)self);
455c455
< _multiprocessing_SemLock__after_fork(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock__after_fork(PyObject *self, PyObject *Py_UNUSED(ignored))
457c457
<     return _multiprocessing_SemLock__after_fork_impl(self);
---
>     return _multiprocessing_SemLock__after_fork_impl((SemLockObject *)self);
477c477
< _multiprocessing_SemLock___enter__(SemLockObject *self, PyObject *Py_UNUSED(ignored))
---
> _multiprocessing_SemLock___enter__(PyObject *self, PyObject *Py_UNUSED(ignored))
482c482
<     return_value = _multiprocessing_SemLock___enter___impl(self);
---
>     return_value = _multiprocessing_SemLock___enter___impl((SemLockObject *)self);
507c507
< _multiprocessing_SemLock___exit__(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs)
---
> _multiprocessing_SemLock___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
531c531
<     return_value = _multiprocessing_SemLock___exit___impl(self, exc_type, exc_value, exc_tb);
---
>     return_value = _multiprocessing_SemLock___exit___impl((SemLockObject *)self, exc_type, exc_value, exc_tb);
579c579
< /*[clinic end generated code: output=9023d3e48a24afd2 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=e28d0fdbfefd1235 input=a9049054013a1b77]*/
diff Python-3.14.0a4/Lib/multiprocessing/connection.py Python-3.14.0a5/Lib/multiprocessing/connection.py
856c856
< def _get_digest_name_and_payload(message: bytes) -> (str, bytes):
---
> def _get_digest_name_and_payload(message):  # type: (bytes) -> tuple[str, bytes]
diff Python-3.14.0a4/Lib/multiprocessing/forkserver.py Python-3.14.0a5/Lib/multiprocessing/forkserver.py
385,389c385,389
<     data = b''
<     length = SIGNED_STRUCT.size
<     while len(data) < length:
<         s = os.read(fd, length - len(data))
<         if not s:
---
>     data = bytearray(SIGNED_STRUCT.size)
>     unread = memoryview(data)
>     while unread:
>         count = os.readinto(fd, unread)
>         if count == 0:
391c391,392
<         data += s
---
>         unread = unread[count:]
> 
diff Python-3.14.0a4/Lib/multiprocessing/synchronize.py Python-3.14.0a5/Lib/multiprocessing/synchronize.py
362c362
<     def __repr__(self) -> str:
---
>     def __repr__(self):
diff Python-3.14.0a4/Lib/test/_test_multiprocessing.py Python-3.14.0a5/Lib/test/_test_multiprocessing.py 
322c322
<         self.assertTrue(not current.daemon)
---
>         self.assertFalse(current.daemon)
466c466
<         self.assertTrue(type(self.active_children()) is list)
---
>         self.assertIs(type(self.active_children()), list)
586,587c586,587
<         self.assertTrue(type(cpus) is int)
<         self.assertTrue(cpus >= 1)
---
>         self.assertIsInstance(cpus, int)
>         self.assertGreaterEqual(cpus, 1)
2385,2386c2385,2386
<         self.assertFalse(hasattr(arr4, 'get_lock'))
<         self.assertFalse(hasattr(arr4, 'get_obj'))
---
>         self.assertNotHasAttr(arr4, 'get_lock')
>         self.assertNotHasAttr(arr4, 'get_obj')
2391,2392c2391,2392
<         self.assertFalse(hasattr(arr5, 'get_lock'))
<         self.assertFalse(hasattr(arr5, 'get_obj'))
---
>         self.assertNotHasAttr(arr5, 'get_lock')
>         self.assertNotHasAttr(arr5, 'get_obj')
2465,2466c2465,2466
<         self.assertFalse(hasattr(arr4, 'get_lock'))
<         self.assertFalse(hasattr(arr4, 'get_obj'))
---
>         self.assertNotHasAttr(arr4, 'get_lock')
>         self.assertNotHasAttr(arr4, 'get_obj')
2471,2472c2471,2472
<         self.assertFalse(hasattr(arr5, 'get_lock'))
<         self.assertFalse(hasattr(arr5, 'get_obj'))
---
>         self.assertNotHasAttr(arr5, 'get_lock')
>         self.assertNotHasAttr(arr5, 'get_obj')
2660,2661c2660,2661
<         self.assertTrue(hasattr(n, 'name'))
<         self.assertTrue(not hasattr(n, 'job'))
---
>         self.assertHasAttr(n, 'name')
>         self.assertNotHasAttr(n, 'job')
4941,4942c4941
<             self.assertTrue(hasattr(mod, '__all__'), name)
< 
---
>             self.assertHasAttr(mod, '__all__', name)
4944,4947c4943
<                 self.assertTrue(
<                     hasattr(mod, attr),
<                     '%r does not have attribute %r' % (mod, attr)
<                     )
---
>                 self.assertHasAttr(mod, attr)
4960c4956
<         self.assertTrue(logger is not None)
---
>         self.assertIsNotNone(logger)
5756,5758c5752,5753
<                 self.assertTrue(type(ctx).__name__.lower().startswith(method))
<                 self.assertTrue(
<                     ctx.Process.__name__.lower().startswith(method))
---
>                 self.assertStartsWith(type(ctx).__name__.lower(), method)
>                 self.assertStartsWith(ctx.Process.__name__.lower(), method)
5959,5961c5954,5956
<                 self.assertTrue(issubclass(the_warn.category, UserWarning))
<                 self.assertTrue("resource_tracker: process died"
<                                 in str(the_warn.message))
---
>                 self.assertIsSubclass(the_warn.category, UserWarning)
>                 self.assertIn("resource_tracker: process died",
>                               str(the_warn.message))
6166,6167c6161,6162
<         self.assertFalse(
<             any(process.is_alive() for process in forked_processes))
---
>         for process in forked_processes:
>             self.assertFalse(process.is_alive(), process)
# ----------------------------------------------------------------------
diff Python-3.14.0a5/Modules/_multiprocessing/clinic/semaphore.c.h Python-3.14.0a6/Modules/_multiprocessing/clinic/semaphore.c.h
326c326
< _multiprocessing_SemLock__rebuild(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs)
---
> _multiprocessing_SemLock__rebuild(PyObject *type, PyObject *const *args, Py_ssize_t nargs)
338c338
<     return_value = _multiprocessing_SemLock__rebuild_impl(type, handle, kind, maxvalue, name);
---
>     return_value = _multiprocessing_SemLock__rebuild_impl((PyTypeObject *)type, handle, kind, maxvalue, name);
579c579
< /*[clinic end generated code: output=e28d0fdbfefd1235 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=dddd8e989525f565 input=a9049054013a1b77]*/
diff Python-3.14.0a5/Lib/multiprocessing/managers.py Python-3.14.0a6/Lib/multiprocessing/managers.py
1197a1198,1227
> _BaseSetProxy = MakeProxyType("_BaseSetProxy", (
>     '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__',
>     '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__',
>     '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__',
>     '__ge__', '__gt__', '__le__', '__lt__',
>     'add', 'clear', 'copy', 'difference', 'difference_update', 'discard',
>     'intersection', 'intersection_update', 'isdisjoint', 'issubset',
>     'issuperset', 'pop', 'remove', 'symmetric_difference',
>     'symmetric_difference_update', 'union', 'update',
> ))
> 
> class SetProxy(_BaseSetProxy):
>     def __ior__(self, value):
>         self._callmethod('__ior__', (value,))
>         return self
>     def __iand__(self, value):
>         self._callmethod('__iand__', (value,))
>         return self
>     def __ixor__(self, value):
>         self._callmethod('__ixor__', (value,))
>         return self
>     def __isub__(self, value):
>         self._callmethod('__isub__', (value,))
>         return self
> 
>     __class_getitem__ = classmethod(types.GenericAlias)
> 
> collections.abc.MutableMapping.register(_BaseSetProxy)
> 
> 
1247a1278
> SyncManager.register('set', set, SetProxy)
diff Python-3.14.0a5/Lib/test/_test_multiprocessing.py Python-3.14.0a6/Lib/test/_test_multiprocessing.py 
592c592,593
<         p = self.Process(target=time.sleep, args=(DELTA,))
---
>         event = self.Event()
>         p = self.Process(target=event.wait, args=())
595,597c596,601
<         p.daemon = True
<         p.start()
<         self.assertIn(p, self.active_children())
---
>         try:
>             p.daemon = True
>             p.start()
>             self.assertIn(p, self.active_children())
>         finally:
>             event.set()
1524,1527c1528,1529
< 
<         t = threading.Thread(target=self._acquire_release,
<                                  args=(lock, 0.2),
<                                  name=f'T1')
---
>         rlock = self.RLock()
>         t = threading.Thread(target=rlock.acquire)
1529,1531c1531,1532
<         time.sleep(0.1)
<         self.assertEqual('<RLock(SomeOtherThread, nonzero)>', repr(lock))
<         time.sleep(0.2)
---
>         t.join()
>         self.assertEqual('<RLock(SomeOtherThread, nonzero)>', repr(rlock))
1542,1545c1543,1544
<         event = self.Event()
<         lock = self.RLock()
<         p = self.Process(target=self._acquire_event,
<                          args=(lock, event))
---
>         rlock = self.RLock()
>         p = self.Process(target=self._acquire, args=(rlock,))
1547,1548d1545
<         event.wait()
<         self.assertEqual('<RLock(SomeOtherProcess, nonzero)>', repr(lock))
1549a1547
>         self.assertEqual('<RLock(SomeOtherProcess, nonzero)>', repr(rlock))
1631c1629
<         for i in range(10):
---
>         for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
1637,1638c1635
<             time.sleep(DELTA)
<         time.sleep(DELTA)
---
> 
1660d1656
<         self.addCleanup(p.join)
1662,1665c1658,1660
<         p = threading.Thread(target=self.f, args=(cond, sleeping, woken))
<         p.daemon = True
<         p.start()
<         self.addCleanup(p.join)
---
>         t = threading.Thread(target=self.f, args=(cond, sleeping, woken))
>         t.daemon = True
>         t.start()
1672,1673c1667
<         time.sleep(DELTA)
<         self.assertReturnsIfImplemented(0, get_value, woken)
---
>         self.assertReachesEventually(lambda: get_value(woken), 0)
1681,1682c1675
<         time.sleep(DELTA)
<         self.assertReturnsIfImplemented(1, get_value, woken)
---
>         self.assertReachesEventually(lambda: get_value(woken), 1)
1690,1691c1683
<         time.sleep(DELTA)
<         self.assertReturnsIfImplemented(2, get_value, woken)
---
>         self.assertReachesEventually(lambda: get_value(woken), 2)
1695c1687,1689
<         p.join()
---
> 
>         threading_helper.join_thread(t)
>         join_process(p)
1702a1697
>         workers = []
1708c1703
<             self.addCleanup(p.join)
---
>             workers.append(p)
1714c1709
<             self.addCleanup(t.join)
---
>             workers.append(t)
1733c1728
<             self.addCleanup(p.join)
---
>             workers.append(p)
1738c1733
<             self.addCleanup(t.join)
---
>             workers.append(t)
1754c1749,1751
<         self.assertReachesEventually(lambda: get_value(woken), 6)
---
>         for i in range(6):
>             woken.acquire()
>         self.assertReturnsIfImplemented(0, get_value, woken)
1758a1756,1759
>         for w in workers:
>             # NOTE: join_process and join_thread are the same
>             threading_helper.join_thread(w)
> 
1764a1766
>         workers = []
1769c1771
<             self.addCleanup(p.join)
---
>             workers.append(p)
1774c1776
<             self.addCleanup(t.join)
---
>             workers.append(t)
1808a1811,1814
>         for w in workers:
>             # NOTE: join_process and join_thread are the same
>             threading_helper.join_thread(w)
> 
6443a6450,6593
>     @classmethod
>     def _test_set_operator_symbols(cls, obj):
>         case = unittest.TestCase()
>         obj.update(['a', 'b', 'c'])
>         case.assertEqual(len(obj), 3)
>         case.assertIn('a', obj)
>         case.assertNotIn('d', obj)
>         result = obj | {'d', 'e'}
>         case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'})
>         result = {'d', 'e'} | obj
>         case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'})
>         obj |= {'d', 'e'}
>         case.assertSetEqual(obj, {'a', 'b', 'c', 'd', 'e'})
>         case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         result = {'a', 'b', 'd'} - obj
>         case.assertSetEqual(result, {'d'})
>         result = obj - {'a', 'b'}
>         case.assertSetEqual(result, {'c'})
>         obj -= {'a', 'b'}
>         case.assertSetEqual(obj, {'c'})
>         case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         result = {'b', 'c', 'd'} ^ obj
>         case.assertSetEqual(result, {'a', 'd'})
>         result = obj ^ {'b', 'c', 'd'}
>         case.assertSetEqual(result, {'a', 'd'})
>         obj ^= {'b', 'c', 'd'}
>         case.assertSetEqual(obj, {'a', 'd'})
>         case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         result = obj & {'b', 'c', 'd'}
>         case.assertSetEqual(result, {'b', 'c'})
>         result = {'b', 'c', 'd'} & obj
>         case.assertSetEqual(result, {'b', 'c'})
>         obj &= {'b', 'c', 'd'}
>         case.assertSetEqual(obj, {'b', 'c'})
>         case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         case.assertSetEqual(set(obj), {'a', 'b', 'c'})
> 
>     @classmethod
>     def _test_set_operator_methods(cls, obj):
>         case = unittest.TestCase()
>         obj.add('d')
>         case.assertIn('d', obj)
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         copy_obj = obj.copy()
>         case.assertSetEqual(copy_obj, obj)
>         obj.remove('a')
>         case.assertNotIn('a', obj)
>         case.assertRaises(KeyError, obj.remove, 'a')
> 
>         obj.clear()
>         obj.update(['a'])
>         obj.discard('a')
>         case.assertNotIn('a', obj)
>         obj.discard('a')
>         case.assertNotIn('a', obj)
>         obj.update(['a'])
>         popped = obj.pop()
>         case.assertNotIn(popped, obj)
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         result = obj.intersection({'b', 'c', 'd'})
>         case.assertSetEqual(result, {'b', 'c'})
>         obj.intersection_update({'b', 'c', 'd'})
>         case.assertSetEqual(obj, {'b', 'c'})
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         result = obj.difference({'a', 'b'})
>         case.assertSetEqual(result, {'c'})
>         obj.difference_update({'a', 'b'})
>         case.assertSetEqual(obj, {'c'})
> 
>         obj.clear()
>         obj.update(['a', 'b', 'c'])
>         result = obj.symmetric_difference({'b', 'c', 'd'})
>         case.assertSetEqual(result, {'a', 'd'})
>         obj.symmetric_difference_update({'b', 'c', 'd'})
>         case.assertSetEqual(obj, {'a', 'd'})
> 
>     @classmethod
>     def _test_set_comparisons(cls, obj):
>         case = unittest.TestCase()
>         obj.update(['a', 'b', 'c'])
>         result = obj.union({'d', 'e'})
>         case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'})
>         case.assertTrue(obj.isdisjoint({'d', 'e'}))
>         case.assertFalse(obj.isdisjoint({'a', 'd'}))
> 
>         case.assertTrue(obj.issubset({'a', 'b', 'c', 'd'}))
>         case.assertFalse(obj.issubset({'a', 'b'}))
>         case.assertLess(obj, {'a', 'b', 'c', 'd'})
>         case.assertLessEqual(obj, {'a', 'b', 'c'})
> 
>         case.assertTrue(obj.issuperset({'a', 'b'}))
>         case.assertFalse(obj.issuperset({'a', 'b', 'd'}))
>         case.assertGreater(obj, {'a'})
>         case.assertGreaterEqual(obj, {'a', 'b'})
> 
>     def test_set(self):
>         o = self.manager.set()
>         self.run_worker(self._test_set_operator_symbols, o)
>         o = self.manager.set()
>         self.run_worker(self._test_set_operator_methods, o)
>         o = self.manager.set()
>         self.run_worker(self._test_set_comparisons, o)
> 
>     def test_set_init(self):
>         o = self.manager.set({'a', 'b', 'c'})
>         self.assertSetEqual(o, {'a', 'b', 'c'})
>         o = self.manager.set(["a", "b", "c"])
>         self.assertSetEqual(o, {"a", "b", "c"})
>         o = self.manager.set({"a": 1, "b": 2, "c": 3})
>         self.assertSetEqual(o, {"a", "b", "c"})
>         self.assertRaises(RemoteError, self.manager.set, 1234)
> 
>     def test_set_contain_all_method(self):
>         o = self.manager.set()
>         set_methods = {
>             '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__',
>             '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__',
>             '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__',
>             '__ge__', '__gt__', '__le__', '__lt__',
>             'add', 'clear', 'copy', 'difference', 'difference_update', 'discard',
>             'intersection', 'intersection_update', 'isdisjoint', 'issubset',
>             'issuperset', 'pop', 'remove', 'symmetric_difference',
>             'symmetric_difference_update', 'union', 'update',
>         }
>         self.assertLessEqual(set_methods, set(dir(o)))
> 
# ----------------------------------------------------------------------
diff Python-3.14.0a6/Modules/_multiprocessing/semaphore.c Python-3.14.0a7/Modules/_multiprocessing/semaphore.c
68c68
< _GetSemaphoreValue(HANDLE handle, long *value)
---
> _GetSemaphoreValue(HANDLE handle, int *value)
diff Python-3.14.0a6/Modules/_multiprocessing/clinic/semaphore.c.h Python-3.14.0a7/Modules/_multiprocessing/clinic/semaphore.c.h
36a37
>         Py_hash_t ob_hash;
39a41
>         .ob_hash = -1,
142a145
>         Py_hash_t ob_hash;
145a149
>         .ob_hash = -1,
239a244
>         Py_hash_t ob_hash;
242a248
>         .ob_hash = -1,
579c585
< /*[clinic end generated code: output=dddd8e989525f565 input=a9049054013a1b77]*/
---
> /*[clinic end generated code: output=d1e349d4ee3d4bbf input=a9049054013a1b77]*/
diff Python-3.14.0a6/Lib/multiprocessing/connection.py Python-3.14.0a7/Lib/multiprocessing/connection.py
324a325,327
> 
>                     sentinel = object()
>                     return_value = sentinel
326,329c329,344
<                         if err == _winapi.ERROR_IO_PENDING:
<                             waitres = _winapi.WaitForMultipleObjects(
<                                 [ov.event], False, INFINITE)
<                             assert waitres == WAIT_OBJECT_0
---
>                         try:
>                             if err == _winapi.ERROR_IO_PENDING:
>                                 waitres = _winapi.WaitForMultipleObjects(
>                                     [ov.event], False, INFINITE)
>                                 assert waitres == WAIT_OBJECT_0
>                         except:
>                             ov.cancel()
>                             raise
>                         finally:
>                             nread, err = ov.GetOverlappedResult(True)
>                             if err == 0:
>                                 f = io.BytesIO()
>                                 f.write(ov.getbuffer())
>                                 return_value = f
>                             elif err == _winapi.ERROR_MORE_DATA:
>                                 return_value = self._get_more_data(ov, maxsize)
331,340c346,350
<                         ov.cancel()
<                         raise
<                     finally:
<                         nread, err = ov.GetOverlappedResult(True)
<                         if err == 0:
<                             f = io.BytesIO()
<                             f.write(ov.getbuffer())
<                             return f
<                         elif err == _winapi.ERROR_MORE_DATA:
<                             return self._get_more_data(ov, maxsize)
---
>                         if return_value is sentinel:
>                             raise
> 
>                     if return_value is not sentinel:
>                         return return_value
diff Python-3.14.0a6/Lib/multiprocessing/managers.py Python-3.14.0a7/Lib/multiprocessing/managers.py
1062c1062
<     _exposed_ = ('acquire', 'release')
---
>     _exposed_ = ('acquire', 'release', 'locked')
1067a1068,1069
>     def locked(self):
>         return self._callmethod('locked')
1075c1077
<     _exposed_ = ('acquire', 'release', 'wait', 'notify', 'notify_all')
---
>     _exposed_ = ('acquire', 'release', 'locked', 'wait', 'notify', 'notify_all')
diff Python-3.14.0a6/Lib/multiprocessing/resource_tracker.py Python-3.14.0a7/Lib/multiprocessing/resource_tracker.py
78,86c78,94
<     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
---
>     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()
88,90c96,114
<             # closing the "alive" file descriptor stops main()
<             os.close(self._fd)
<             self._fd = None
---
>     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
92c116
<             _, status = os.waitpid(self._pid, 0)
---
>         _, status = waitpid(self._pid, 0)
94c118
<             self._pid = None
---
>         self._pid = None
96,100c120,124
<             try:
<                 self._exitcode = os.waitstatus_to_exitcode(status)
<             except ValueError:
<                 # os.waitstatus_to_exitcode may raise an exception for invalid values
<                 self._exitcode = None
---
>         try:
>             self._exitcode = waitstatus_to_exitcode(status)
>         except ValueError:
>             # os.waitstatus_to_exitcode may raise an exception for invalid values
>             self._exitcode = None
diff Python-3.14.0a6/Lib/multiprocessing/synchronize.py Python-3.14.0a7/Lib/multiprocessing/synchronize.py
92a93,95
>     def locked(self):
>         return self._semlock._count() != 0
> 
diff Python-3.14.0a6/Lib/test/_test_multiprocessing.py Python-3.14.0a7/Lib/test/_test_multiprocessing.py 
1488a1489
>         self.assertTrue(lock.locked())
1490a1492
>         self.assertFalse(lock.locked())
1551a1554
>         self.assertTrue(lock.locked())
1554a1558
>         self.assertTrue(lock.locked())
1556a1561
>         self.assertFalse(lock.locked())
1560,1561c1565,1570
<         with self.Lock():
<             pass
---
>         with self.Lock() as locked:
>             self.assertTrue(locked)
> 
>     def test_rlock_context(self):
>         with self.RLock() as locked:
>             self.assertTrue(locked)
6256a6266
>         obj.locked()
6267a6278
>         obj.locked()
6269c6280
<     def test_rlock(self, lname="Lock"):
---
>     def test_rlock(self, lname="RLock"):
