Skip to content

Commit 89d4cf5

Browse files
CPython developersyouknowone
authored andcommitted
Update multiprocessing from CPython 3.10.5
1 parent 464e216 commit 89d4cf5

24 files changed

+2123
-609
lines changed

Lib/multiprocessing/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@
1919
# Copy stuff from default context
2020
#
2121

22-
globals().update((name, getattr(context._default_context, name))
23-
for name in context._default_context.__all__)
24-
__all__ = context._default_context.__all__
22+
__all__ = [x for x in dir(context._default_context) if not x.startswith('_')]
23+
globals().update((name, getattr(context._default_context, name)) for name in __all__)
2524

2625
#
2726
# XXX These should not really be documented or public.

Lib/multiprocessing/connection.py

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@
5757

5858

5959
def _init_timeout(timeout=CONNECTION_TIMEOUT):
60-
return time.time() + timeout
60+
return time.monotonic() + timeout
6161

6262
def _check_timeout(t):
63-
return time.time() > t
63+
return time.monotonic() > t
6464

6565
#
6666
#
@@ -73,6 +73,11 @@ def arbitrary_address(family):
7373
if family == 'AF_INET':
7474
return ('localhost', 0)
7575
elif family == 'AF_UNIX':
76+
# Prefer abstract sockets if possible to avoid problems with the address
77+
# size. When coding portable applications, some implementations have
78+
# sun_path as short as 92 bytes in the sockaddr_un struct.
79+
if util.abstract_sockets_supported:
80+
return f"\0listener-{os.getpid()}-{next(_mmap_counter)}"
7681
return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir())
7782
elif family == 'AF_PIPE':
7883
return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' %
@@ -102,7 +107,7 @@ def address_type(address):
102107
return 'AF_INET'
103108
elif type(address) is str and address.startswith('\\\\'):
104109
return 'AF_PIPE'
105-
elif type(address) is str:
110+
elif type(address) is str or util.is_abstract_socket_namespace(address):
106111
return 'AF_UNIX'
107112
else:
108113
raise ValueError('address type of %r unrecognized' % address)
@@ -389,23 +394,33 @@ def _recv(self, size, read=_read):
389394

390395
def _send_bytes(self, buf):
391396
n = len(buf)
392-
# For wire compatibility with 3.2 and lower
393-
header = struct.pack("!i", n)
394-
if n > 16384:
395-
# The payload is large so Nagle's algorithm won't be triggered
396-
# and we'd better avoid the cost of concatenation.
397+
if n > 0x7fffffff:
398+
pre_header = struct.pack("!i", -1)
399+
header = struct.pack("!Q", n)
400+
self._send(pre_header)
397401
self._send(header)
398402
self._send(buf)
399403
else:
400-
# Issue #20540: concatenate before sending, to avoid delays due
401-
# to Nagle's algorithm on a TCP socket.
402-
# Also note we want to avoid sending a 0-length buffer separately,
403-
# to avoid "broken pipe" errors if the other end closed the pipe.
404-
self._send(header + buf)
404+
# For wire compatibility with 3.7 and lower
405+
header = struct.pack("!i", n)
406+
if n > 16384:
407+
# The payload is large so Nagle's algorithm won't be triggered
408+
# and we'd better avoid the cost of concatenation.
409+
self._send(header)
410+
self._send(buf)
411+
else:
412+
# Issue #20540: concatenate before sending, to avoid delays due
413+
# to Nagle's algorithm on a TCP socket.
414+
# Also note we want to avoid sending a 0-length buffer separately,
415+
# to avoid "broken pipe" errors if the other end closed the pipe.
416+
self._send(header + buf)
405417

406418
def _recv_bytes(self, maxsize=None):
407419
buf = self._recv(4)
408420
size, = struct.unpack("!i", buf.getvalue())
421+
if size == -1:
422+
buf = self._recv(8)
423+
size, = struct.unpack("!Q", buf.getvalue())
409424
if maxsize is not None and size > maxsize:
410425
return None
411426
return self._recv(size)
@@ -465,8 +480,13 @@ def close(self):
465480
self._listener = None
466481
listener.close()
467482

468-
address = property(lambda self: self._listener._address)
469-
last_accepted = property(lambda self: self._listener._last_accepted)
483+
@property
484+
def address(self):
485+
return self._listener._address
486+
487+
@property
488+
def last_accepted(self):
489+
return self._listener._last_accepted
470490

471491
def __enter__(self):
472492
return self
@@ -582,7 +602,8 @@ def __init__(self, address, family, backlog=1):
582602
self._family = family
583603
self._last_accepted = None
584604

585-
if family == 'AF_UNIX':
605+
if family == 'AF_UNIX' and not util.is_abstract_socket_namespace(address):
606+
# Linux abstract socket namespaces do not need to be explicitly unlinked
586607
self._unlink = util.Finalize(
587608
self, os.unlink, args=(address,), exitpriority=0
588609
)
@@ -715,7 +736,9 @@ def PipeClient(address):
715736

716737
def deliver_challenge(connection, authkey):
717738
import hmac
718-
assert isinstance(authkey, bytes)
739+
if not isinstance(authkey, bytes):
740+
raise ValueError(
741+
"Authkey must be bytes, not {0!s}".format(type(authkey)))
719742
message = os.urandom(MESSAGE_LENGTH)
720743
connection.send_bytes(CHALLENGE + message)
721744
digest = hmac.new(authkey, message, 'md5').digest()
@@ -728,7 +751,9 @@ def deliver_challenge(connection, authkey):
728751

729752
def answer_challenge(connection, authkey):
730753
import hmac
731-
assert isinstance(authkey, bytes)
754+
if not isinstance(authkey, bytes):
755+
raise ValueError(
756+
"Authkey must be bytes, not {0!s}".format(type(authkey)))
732757
message = connection.recv_bytes(256) # reject large message
733758
assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message
734759
message = message[len(CHALLENGE):]
@@ -780,8 +805,7 @@ def XmlClient(*args, **kwds):
780805
# Wait
781806
#
782807

783-
# XXX RustPython TODO: implement all the functions in this block
784-
if sys.platform == 'win32' and False:
808+
if sys.platform == 'win32':
785809

786810
def _exhaustive_wait(handles, timeout):
787811
# Return ALL handles which are currently signalled. (Only
@@ -906,15 +930,15 @@ def wait(object_list, timeout=None):
906930
selector.register(obj, selectors.EVENT_READ)
907931

908932
if timeout is not None:
909-
deadline = time.time() + timeout
933+
deadline = time.monotonic() + timeout
910934

911935
while True:
912936
ready = selector.select(timeout)
913937
if ready:
914938
return [key.fileobj for (key, events) in ready]
915939
else:
916940
if timeout is not None:
917-
timeout = deadline - time.time()
941+
timeout = deadline - time.monotonic()
918942
if timeout < 0:
919943
return ready
920944

Lib/multiprocessing/context.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from . import process
66
from . import reduction
77

8-
__all__ = [] # things are copied from here to __init__.py
8+
__all__ = ()
99

1010
#
1111
# Exceptions
@@ -24,7 +24,7 @@ class AuthenticationError(ProcessError):
2424
pass
2525

2626
#
27-
# Base type for contexts
27+
# Base type for contexts. Bound methods of an instance of this type are included in __all__ of __init__.py
2828
#
2929

3030
class BaseContext(object):
@@ -35,6 +35,7 @@ class BaseContext(object):
3535
AuthenticationError = AuthenticationError
3636

3737
current_process = staticmethod(process.current_process)
38+
parent_process = staticmethod(process.parent_process)
3839
active_children = staticmethod(process.active_children)
3940

4041
def cpu_count(self):
@@ -189,14 +190,14 @@ def get_context(self, method=None):
189190
try:
190191
ctx = _concrete_contexts[method]
191192
except KeyError:
192-
raise ValueError('cannot find context for %r' % method)
193+
raise ValueError('cannot find context for %r' % method) from None
193194
ctx._check_available()
194195
return ctx
195196

196197
def get_start_method(self, allow_none=False):
197198
return self._name
198199

199-
def set_start_method(self, method=None):
200+
def set_start_method(self, method, force=False):
200201
raise ValueError('cannot set start method of concrete context')
201202

202203
@property
@@ -256,12 +257,11 @@ def get_all_start_methods(self):
256257
if sys.platform == 'win32':
257258
return ['spawn']
258259
else:
260+
methods = ['spawn', 'fork'] if sys.platform == 'darwin' else ['fork', 'spawn']
259261
if reduction.HAVE_SEND_HANDLE:
260-
return ['fork', 'spawn', 'forkserver']
261-
else:
262-
return ['fork', 'spawn']
262+
methods.append('forkserver')
263+
return methods
263264

264-
DefaultContext.__all__ = list(x for x in dir(DefaultContext) if x[0] != '_')
265265

266266
#
267267
# Context types for fixed start method
@@ -310,7 +310,12 @@ def _check_available(self):
310310
'spawn': SpawnContext(),
311311
'forkserver': ForkServerContext(),
312312
}
313-
_default_context = DefaultContext(_concrete_contexts['fork'])
313+
if sys.platform == 'darwin':
314+
# bpo-33725: running arbitrary code after fork() is no longer reliable
315+
# on macOS since macOS 10.14 (Mojave). Use spawn by default instead.
316+
_default_context = DefaultContext(_concrete_contexts['spawn'])
317+
else:
318+
_default_context = DefaultContext(_concrete_contexts['fork'])
314319

315320
else:
316321

Lib/multiprocessing/dummy/__init__.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
4141
self._parent = current_process()
4242

4343
def start(self):
44-
assert self._parent is current_process()
44+
if self._parent is not current_process():
45+
raise RuntimeError(
46+
"Parent is {0!r} but current_process is {1!r}".format(
47+
self._parent, current_process()))
4548
self._start_called = True
4649
if hasattr(self._parent, '_children'):
4750
self._parent._children[self] = None
@@ -77,7 +80,7 @@ def freeze_support():
7780
#
7881

7982
class Namespace(object):
80-
def __init__(self, **kwds):
83+
def __init__(self, /, **kwds):
8184
self.__dict__.update(kwds)
8285
def __repr__(self):
8386
items = list(self.__dict__.items())
@@ -98,11 +101,15 @@ class Value(object):
98101
def __init__(self, typecode, value, lock=True):
99102
self._typecode = typecode
100103
self._value = value
101-
def _get(self):
104+
105+
@property
106+
def value(self):
102107
return self._value
103-
def _set(self, value):
108+
109+
@value.setter
110+
def value(self, value):
104111
self._value = value
105-
value = property(_get, _set)
112+
106113
def __repr__(self):
107114
return '<%s(%r, %r)>'%(type(self).__name__,self._typecode,self._value)
108115

Lib/multiprocessing/dummy/connection.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ def accept(self):
2626
def close(self):
2727
self._backlog_queue = None
2828

29-
address = property(lambda self: self._backlog_queue)
29+
@property
30+
def address(self):
31+
return self._backlog_queue
3032

3133
def __enter__(self):
3234
return self

0 commit comments

Comments
 (0)