Shenghong commited on
Commit
2ddfa19
·
verified ·
1 Parent(s): 1be6e6c

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.1/multiprocessing/__init__.py +37 -0
  2. lib/python3.1/multiprocessing/__pycache__/__init__.cpython-310.pyc +0 -0
  3. lib/python3.1/multiprocessing/__pycache__/connection.cpython-310.pyc +0 -0
  4. lib/python3.1/multiprocessing/__pycache__/context.cpython-310.pyc +0 -0
  5. lib/python3.1/multiprocessing/__pycache__/forkserver.cpython-310.pyc +0 -0
  6. lib/python3.1/multiprocessing/__pycache__/heap.cpython-310.pyc +0 -0
  7. lib/python3.1/multiprocessing/__pycache__/managers.cpython-310.pyc +0 -0
  8. lib/python3.1/multiprocessing/__pycache__/pool.cpython-310.pyc +0 -0
  9. lib/python3.1/multiprocessing/__pycache__/popen_fork.cpython-310.pyc +0 -0
  10. lib/python3.1/multiprocessing/__pycache__/popen_forkserver.cpython-310.pyc +0 -0
  11. lib/python3.1/multiprocessing/__pycache__/popen_spawn_posix.cpython-310.pyc +0 -0
  12. lib/python3.1/multiprocessing/__pycache__/popen_spawn_win32.cpython-310.pyc +0 -0
  13. lib/python3.1/multiprocessing/__pycache__/process.cpython-310.pyc +0 -0
  14. lib/python3.1/multiprocessing/__pycache__/queues.cpython-310.pyc +0 -0
  15. lib/python3.1/multiprocessing/__pycache__/reduction.cpython-310.pyc +0 -0
  16. lib/python3.1/multiprocessing/__pycache__/resource_sharer.cpython-310.pyc +0 -0
  17. lib/python3.1/multiprocessing/__pycache__/resource_tracker.cpython-310.pyc +0 -0
  18. lib/python3.1/multiprocessing/__pycache__/shared_memory.cpython-310.pyc +0 -0
  19. lib/python3.1/multiprocessing/__pycache__/sharedctypes.cpython-310.pyc +0 -0
  20. lib/python3.1/multiprocessing/__pycache__/spawn.cpython-310.pyc +0 -0
  21. lib/python3.1/multiprocessing/__pycache__/synchronize.cpython-310.pyc +0 -0
  22. lib/python3.1/multiprocessing/__pycache__/util.cpython-310.pyc +0 -0
  23. lib/python3.1/multiprocessing/connection.py +973 -0
  24. lib/python3.1/multiprocessing/context.py +376 -0
  25. lib/python3.1/multiprocessing/dummy/__init__.py +126 -0
  26. lib/python3.1/multiprocessing/dummy/__pycache__/__init__.cpython-310.pyc +0 -0
  27. lib/python3.1/multiprocessing/dummy/__pycache__/connection.cpython-310.pyc +0 -0
  28. lib/python3.1/multiprocessing/dummy/connection.py +75 -0
  29. lib/python3.1/multiprocessing/forkserver.py +348 -0
  30. lib/python3.1/multiprocessing/heap.py +337 -0
  31. lib/python3.1/multiprocessing/managers.py +1378 -0
  32. lib/python3.1/multiprocessing/pool.py +957 -0
  33. lib/python3.1/multiprocessing/popen_fork.py +83 -0
  34. lib/python3.1/multiprocessing/popen_forkserver.py +74 -0
  35. lib/python3.1/multiprocessing/popen_spawn_posix.py +72 -0
  36. lib/python3.1/multiprocessing/popen_spawn_win32.py +131 -0
  37. lib/python3.1/multiprocessing/process.py +438 -0
  38. lib/python3.1/multiprocessing/queues.py +379 -0
  39. lib/python3.1/multiprocessing/reduction.py +281 -0
  40. lib/python3.1/multiprocessing/resource_sharer.py +154 -0
  41. lib/python3.1/multiprocessing/resource_tracker.py +239 -0
  42. lib/python3.1/multiprocessing/shared_memory.py +534 -0
  43. lib/python3.1/multiprocessing/sharedctypes.py +240 -0
  44. lib/python3.1/multiprocessing/spawn.py +297 -0
  45. lib/python3.1/multiprocessing/synchronize.py +394 -0
  46. lib/python3.1/multiprocessing/util.py +489 -0
  47. lib/python3.1/site-packages/README.txt +2 -0
  48. lib/python3.1/site-packages/aiohttp/.hash/_cparser.pxd.hash +1 -0
  49. lib/python3.1/site-packages/aiohttp/.hash/_find_header.pxd.hash +1 -0
  50. lib/python3.1/site-packages/aiohttp/.hash/_http_parser.pyx.hash +1 -0
lib/python3.1/multiprocessing/__init__.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Package analogous to 'threading.py' but using processes
3
+ #
4
+ # multiprocessing/__init__.py
5
+ #
6
+ # This package is intended to duplicate the functionality (and much of
7
+ # the API) of threading.py but uses processes instead of threads. A
8
+ # subpackage 'multiprocessing.dummy' has the same API but is a simple
9
+ # wrapper for 'threading'.
10
+ #
11
+ # Copyright (c) 2006-2008, R Oudkerk
12
+ # Licensed to PSF under a Contributor Agreement.
13
+ #
14
+
15
+ import sys
16
+ from . import context
17
+
18
+ #
19
+ # Copy stuff from default context
20
+ #
21
+
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__)
24
+
25
+ #
26
+ # XXX These should not really be documented or public.
27
+ #
28
+
29
+ SUBDEBUG = 5
30
+ SUBWARNING = 25
31
+
32
+ #
33
+ # Alias for main module -- will be reset by bootstrapping child processes
34
+ #
35
+
36
+ if '__main__' in sys.modules:
37
+ sys.modules['__mp_main__'] = sys.modules['__main__']
lib/python3.1/multiprocessing/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (923 Bytes). View file
 
lib/python3.1/multiprocessing/__pycache__/connection.cpython-310.pyc ADDED
Binary file (25.8 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/context.cpython-310.pyc ADDED
Binary file (13.1 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/forkserver.cpython-310.pyc ADDED
Binary file (8.68 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/heap.cpython-310.pyc ADDED
Binary file (7.92 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/managers.cpython-310.pyc ADDED
Binary file (41 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/pool.cpython-310.pyc ADDED
Binary file (25.5 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/popen_fork.cpython-310.pyc ADDED
Binary file (2.78 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/popen_forkserver.cpython-310.pyc ADDED
Binary file (2.72 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/popen_spawn_posix.cpython-310.pyc ADDED
Binary file (2.6 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/popen_spawn_win32.cpython-310.pyc ADDED
Binary file (3.73 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/process.cpython-310.pyc ADDED
Binary file (11.3 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/queues.cpython-310.pyc ADDED
Binary file (10.5 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/reduction.cpython-310.pyc ADDED
Binary file (8.55 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/resource_sharer.cpython-310.pyc ADDED
Binary file (5.56 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/resource_tracker.cpython-310.pyc ADDED
Binary file (5.74 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/shared_memory.cpython-310.pyc ADDED
Binary file (14.5 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/sharedctypes.cpython-310.pyc ADDED
Binary file (7.35 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/spawn.cpython-310.pyc ADDED
Binary file (6.99 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/synchronize.cpython-310.pyc ADDED
Binary file (11.3 kB). View file
 
lib/python3.1/multiprocessing/__pycache__/util.cpython-310.pyc ADDED
Binary file (11.8 kB). View file
 
lib/python3.1/multiprocessing/connection.py ADDED
@@ -0,0 +1,973 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # A higher level module for using sockets (or Windows named pipes)
3
+ #
4
+ # multiprocessing/connection.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = [ 'Client', 'Listener', 'Pipe', 'wait' ]
11
+
12
+ import io
13
+ import os
14
+ import sys
15
+ import socket
16
+ import struct
17
+ import time
18
+ import tempfile
19
+ import itertools
20
+
21
+ import _multiprocessing
22
+
23
+ from . import util
24
+
25
+ from . import AuthenticationError, BufferTooShort
26
+ from .context import reduction
27
+ _ForkingPickler = reduction.ForkingPickler
28
+
29
+ try:
30
+ import _winapi
31
+ from _winapi import WAIT_OBJECT_0, WAIT_ABANDONED_0, WAIT_TIMEOUT, INFINITE
32
+ except ImportError:
33
+ if sys.platform == 'win32':
34
+ raise
35
+ _winapi = None
36
+
37
+ #
38
+ #
39
+ #
40
+
41
+ BUFSIZE = 8192
42
+ # A very generous timeout when it comes to local connections...
43
+ CONNECTION_TIMEOUT = 20.
44
+
45
+ _mmap_counter = itertools.count()
46
+
47
+ default_family = 'AF_INET'
48
+ families = ['AF_INET']
49
+
50
+ if hasattr(socket, 'AF_UNIX'):
51
+ default_family = 'AF_UNIX'
52
+ families += ['AF_UNIX']
53
+
54
+ if sys.platform == 'win32':
55
+ default_family = 'AF_PIPE'
56
+ families += ['AF_PIPE']
57
+
58
+
59
+ def _init_timeout(timeout=CONNECTION_TIMEOUT):
60
+ return time.monotonic() + timeout
61
+
62
+ def _check_timeout(t):
63
+ return time.monotonic() > t
64
+
65
+ #
66
+ #
67
+ #
68
+
69
+ def arbitrary_address(family):
70
+ '''
71
+ Return an arbitrary free address for the given family
72
+ '''
73
+ if family == 'AF_INET':
74
+ return ('localhost', 0)
75
+ elif family == 'AF_UNIX':
76
+ return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir())
77
+ elif family == 'AF_PIPE':
78
+ return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' %
79
+ (os.getpid(), next(_mmap_counter)), dir="")
80
+ else:
81
+ raise ValueError('unrecognized family')
82
+
83
+ def _validate_family(family):
84
+ '''
85
+ Checks if the family is valid for the current environment.
86
+ '''
87
+ if sys.platform != 'win32' and family == 'AF_PIPE':
88
+ raise ValueError('Family %s is not recognized.' % family)
89
+
90
+ if sys.platform == 'win32' and family == 'AF_UNIX':
91
+ # double check
92
+ if not hasattr(socket, family):
93
+ raise ValueError('Family %s is not recognized.' % family)
94
+
95
+ def address_type(address):
96
+ '''
97
+ Return the types of the address
98
+
99
+ This can be 'AF_INET', 'AF_UNIX', or 'AF_PIPE'
100
+ '''
101
+ if type(address) == tuple:
102
+ return 'AF_INET'
103
+ elif type(address) is str and address.startswith('\\\\'):
104
+ return 'AF_PIPE'
105
+ elif type(address) is str or util.is_abstract_socket_namespace(address):
106
+ return 'AF_UNIX'
107
+ else:
108
+ raise ValueError('address type of %r unrecognized' % address)
109
+
110
+ #
111
+ # Connection classes
112
+ #
113
+
114
+ class _ConnectionBase:
115
+ _handle = None
116
+
117
+ def __init__(self, handle, readable=True, writable=True):
118
+ handle = handle.__index__()
119
+ if handle < 0:
120
+ raise ValueError("invalid handle")
121
+ if not readable and not writable:
122
+ raise ValueError(
123
+ "at least one of `readable` and `writable` must be True")
124
+ self._handle = handle
125
+ self._readable = readable
126
+ self._writable = writable
127
+
128
+ # XXX should we use util.Finalize instead of a __del__?
129
+
130
+ def __del__(self):
131
+ if self._handle is not None:
132
+ self._close()
133
+
134
+ def _check_closed(self):
135
+ if self._handle is None:
136
+ raise OSError("handle is closed")
137
+
138
+ def _check_readable(self):
139
+ if not self._readable:
140
+ raise OSError("connection is write-only")
141
+
142
+ def _check_writable(self):
143
+ if not self._writable:
144
+ raise OSError("connection is read-only")
145
+
146
+ def _bad_message_length(self):
147
+ if self._writable:
148
+ self._readable = False
149
+ else:
150
+ self.close()
151
+ raise OSError("bad message length")
152
+
153
+ @property
154
+ def closed(self):
155
+ """True if the connection is closed"""
156
+ return self._handle is None
157
+
158
+ @property
159
+ def readable(self):
160
+ """True if the connection is readable"""
161
+ return self._readable
162
+
163
+ @property
164
+ def writable(self):
165
+ """True if the connection is writable"""
166
+ return self._writable
167
+
168
+ def fileno(self):
169
+ """File descriptor or handle of the connection"""
170
+ self._check_closed()
171
+ return self._handle
172
+
173
+ def close(self):
174
+ """Close the connection"""
175
+ if self._handle is not None:
176
+ try:
177
+ self._close()
178
+ finally:
179
+ self._handle = None
180
+
181
+ def send_bytes(self, buf, offset=0, size=None):
182
+ """Send the bytes data from a bytes-like object"""
183
+ self._check_closed()
184
+ self._check_writable()
185
+ m = memoryview(buf)
186
+ # HACK for byte-indexing of non-bytewise buffers (e.g. array.array)
187
+ if m.itemsize > 1:
188
+ m = memoryview(bytes(m))
189
+ n = len(m)
190
+ if offset < 0:
191
+ raise ValueError("offset is negative")
192
+ if n < offset:
193
+ raise ValueError("buffer length < offset")
194
+ if size is None:
195
+ size = n - offset
196
+ elif size < 0:
197
+ raise ValueError("size is negative")
198
+ elif offset + size > n:
199
+ raise ValueError("buffer length < offset + size")
200
+ self._send_bytes(m[offset:offset + size])
201
+
202
+ def send(self, obj):
203
+ """Send a (picklable) object"""
204
+ self._check_closed()
205
+ self._check_writable()
206
+ self._send_bytes(_ForkingPickler.dumps(obj))
207
+
208
+ def recv_bytes(self, maxlength=None):
209
+ """
210
+ Receive bytes data as a bytes object.
211
+ """
212
+ self._check_closed()
213
+ self._check_readable()
214
+ if maxlength is not None and maxlength < 0:
215
+ raise ValueError("negative maxlength")
216
+ buf = self._recv_bytes(maxlength)
217
+ if buf is None:
218
+ self._bad_message_length()
219
+ return buf.getvalue()
220
+
221
+ def recv_bytes_into(self, buf, offset=0):
222
+ """
223
+ Receive bytes data into a writeable bytes-like object.
224
+ Return the number of bytes read.
225
+ """
226
+ self._check_closed()
227
+ self._check_readable()
228
+ with memoryview(buf) as m:
229
+ # Get bytesize of arbitrary buffer
230
+ itemsize = m.itemsize
231
+ bytesize = itemsize * len(m)
232
+ if offset < 0:
233
+ raise ValueError("negative offset")
234
+ elif offset > bytesize:
235
+ raise ValueError("offset too large")
236
+ result = self._recv_bytes()
237
+ size = result.tell()
238
+ if bytesize < offset + size:
239
+ raise BufferTooShort(result.getvalue())
240
+ # Message can fit in dest
241
+ result.seek(0)
242
+ result.readinto(m[offset // itemsize :
243
+ (offset + size) // itemsize])
244
+ return size
245
+
246
+ def recv(self):
247
+ """Receive a (picklable) object"""
248
+ self._check_closed()
249
+ self._check_readable()
250
+ buf = self._recv_bytes()
251
+ return _ForkingPickler.loads(buf.getbuffer())
252
+
253
+ def poll(self, timeout=0.0):
254
+ """Whether there is any input available to be read"""
255
+ self._check_closed()
256
+ self._check_readable()
257
+ return self._poll(timeout)
258
+
259
+ def __enter__(self):
260
+ return self
261
+
262
+ def __exit__(self, exc_type, exc_value, exc_tb):
263
+ self.close()
264
+
265
+
266
+ if _winapi:
267
+
268
+ class PipeConnection(_ConnectionBase):
269
+ """
270
+ Connection class based on a Windows named pipe.
271
+ Overlapped I/O is used, so the handles must have been created
272
+ with FILE_FLAG_OVERLAPPED.
273
+ """
274
+ _got_empty_message = False
275
+
276
+ def _close(self, _CloseHandle=_winapi.CloseHandle):
277
+ _CloseHandle(self._handle)
278
+
279
+ def _send_bytes(self, buf):
280
+ ov, err = _winapi.WriteFile(self._handle, buf, overlapped=True)
281
+ try:
282
+ if err == _winapi.ERROR_IO_PENDING:
283
+ waitres = _winapi.WaitForMultipleObjects(
284
+ [ov.event], False, INFINITE)
285
+ assert waitres == WAIT_OBJECT_0
286
+ except:
287
+ ov.cancel()
288
+ raise
289
+ finally:
290
+ nwritten, err = ov.GetOverlappedResult(True)
291
+ assert err == 0
292
+ assert nwritten == len(buf)
293
+
294
+ def _recv_bytes(self, maxsize=None):
295
+ if self._got_empty_message:
296
+ self._got_empty_message = False
297
+ return io.BytesIO()
298
+ else:
299
+ bsize = 128 if maxsize is None else min(maxsize, 128)
300
+ try:
301
+ ov, err = _winapi.ReadFile(self._handle, bsize,
302
+ overlapped=True)
303
+ try:
304
+ if err == _winapi.ERROR_IO_PENDING:
305
+ waitres = _winapi.WaitForMultipleObjects(
306
+ [ov.event], False, INFINITE)
307
+ assert waitres == WAIT_OBJECT_0
308
+ except:
309
+ ov.cancel()
310
+ raise
311
+ finally:
312
+ nread, err = ov.GetOverlappedResult(True)
313
+ if err == 0:
314
+ f = io.BytesIO()
315
+ f.write(ov.getbuffer())
316
+ return f
317
+ elif err == _winapi.ERROR_MORE_DATA:
318
+ return self._get_more_data(ov, maxsize)
319
+ except OSError as e:
320
+ if e.winerror == _winapi.ERROR_BROKEN_PIPE:
321
+ raise EOFError
322
+ else:
323
+ raise
324
+ raise RuntimeError("shouldn't get here; expected KeyboardInterrupt")
325
+
326
+ def _poll(self, timeout):
327
+ if (self._got_empty_message or
328
+ _winapi.PeekNamedPipe(self._handle)[0] != 0):
329
+ return True
330
+ return bool(wait([self], timeout))
331
+
332
+ def _get_more_data(self, ov, maxsize):
333
+ buf = ov.getbuffer()
334
+ f = io.BytesIO()
335
+ f.write(buf)
336
+ left = _winapi.PeekNamedPipe(self._handle)[1]
337
+ assert left > 0
338
+ if maxsize is not None and len(buf) + left > maxsize:
339
+ self._bad_message_length()
340
+ ov, err = _winapi.ReadFile(self._handle, left, overlapped=True)
341
+ rbytes, err = ov.GetOverlappedResult(True)
342
+ assert err == 0
343
+ assert rbytes == left
344
+ f.write(ov.getbuffer())
345
+ return f
346
+
347
+
348
+ class Connection(_ConnectionBase):
349
+ """
350
+ Connection class based on an arbitrary file descriptor (Unix only), or
351
+ a socket handle (Windows).
352
+ """
353
+
354
+ if _winapi:
355
+ def _close(self, _close=_multiprocessing.closesocket):
356
+ _close(self._handle)
357
+ _write = _multiprocessing.send
358
+ _read = _multiprocessing.recv
359
+ else:
360
+ def _close(self, _close=os.close):
361
+ _close(self._handle)
362
+ _write = os.write
363
+ _read = os.read
364
+
365
+ def _send(self, buf, write=_write):
366
+ remaining = len(buf)
367
+ while True:
368
+ n = write(self._handle, buf)
369
+ remaining -= n
370
+ if remaining == 0:
371
+ break
372
+ buf = buf[n:]
373
+
374
+ def _recv(self, size, read=_read):
375
+ buf = io.BytesIO()
376
+ handle = self._handle
377
+ remaining = size
378
+ while remaining > 0:
379
+ chunk = read(handle, remaining)
380
+ n = len(chunk)
381
+ if n == 0:
382
+ if remaining == size:
383
+ raise EOFError
384
+ else:
385
+ raise OSError("got end of file during message")
386
+ buf.write(chunk)
387
+ remaining -= n
388
+ return buf
389
+
390
+ def _send_bytes(self, buf):
391
+ n = len(buf)
392
+ if n > 0x7fffffff:
393
+ pre_header = struct.pack("!i", -1)
394
+ header = struct.pack("!Q", n)
395
+ self._send(pre_header)
396
+ self._send(header)
397
+ self._send(buf)
398
+ else:
399
+ # For wire compatibility with 3.7 and lower
400
+ header = struct.pack("!i", n)
401
+ if n > 16384:
402
+ # The payload is large so Nagle's algorithm won't be triggered
403
+ # and we'd better avoid the cost of concatenation.
404
+ self._send(header)
405
+ self._send(buf)
406
+ else:
407
+ # Issue #20540: concatenate before sending, to avoid delays due
408
+ # to Nagle's algorithm on a TCP socket.
409
+ # Also note we want to avoid sending a 0-length buffer separately,
410
+ # to avoid "broken pipe" errors if the other end closed the pipe.
411
+ self._send(header + buf)
412
+
413
+ def _recv_bytes(self, maxsize=None):
414
+ buf = self._recv(4)
415
+ size, = struct.unpack("!i", buf.getvalue())
416
+ if size == -1:
417
+ buf = self._recv(8)
418
+ size, = struct.unpack("!Q", buf.getvalue())
419
+ if maxsize is not None and size > maxsize:
420
+ return None
421
+ return self._recv(size)
422
+
423
+ def _poll(self, timeout):
424
+ r = wait([self], timeout)
425
+ return bool(r)
426
+
427
+
428
+ #
429
+ # Public functions
430
+ #
431
+
432
+ class Listener(object):
433
+ '''
434
+ Returns a listener object.
435
+
436
+ This is a wrapper for a bound socket which is 'listening' for
437
+ connections, or for a Windows named pipe.
438
+ '''
439
+ def __init__(self, address=None, family=None, backlog=1, authkey=None):
440
+ family = family or (address and address_type(address)) \
441
+ or default_family
442
+ address = address or arbitrary_address(family)
443
+
444
+ _validate_family(family)
445
+ if family == 'AF_PIPE':
446
+ self._listener = PipeListener(address, backlog)
447
+ else:
448
+ self._listener = SocketListener(address, family, backlog)
449
+
450
+ if authkey is not None and not isinstance(authkey, bytes):
451
+ raise TypeError('authkey should be a byte string')
452
+
453
+ self._authkey = authkey
454
+
455
+ def accept(self):
456
+ '''
457
+ Accept a connection on the bound socket or named pipe of `self`.
458
+
459
+ Returns a `Connection` object.
460
+ '''
461
+ if self._listener is None:
462
+ raise OSError('listener is closed')
463
+ c = self._listener.accept()
464
+ if self._authkey:
465
+ deliver_challenge(c, self._authkey)
466
+ answer_challenge(c, self._authkey)
467
+ return c
468
+
469
+ def close(self):
470
+ '''
471
+ Close the bound socket or named pipe of `self`.
472
+ '''
473
+ listener = self._listener
474
+ if listener is not None:
475
+ self._listener = None
476
+ listener.close()
477
+
478
+ @property
479
+ def address(self):
480
+ return self._listener._address
481
+
482
+ @property
483
+ def last_accepted(self):
484
+ return self._listener._last_accepted
485
+
486
+ def __enter__(self):
487
+ return self
488
+
489
+ def __exit__(self, exc_type, exc_value, exc_tb):
490
+ self.close()
491
+
492
+
493
+ def Client(address, family=None, authkey=None):
494
+ '''
495
+ Returns a connection to the address of a `Listener`
496
+ '''
497
+ family = family or address_type(address)
498
+ _validate_family(family)
499
+ if family == 'AF_PIPE':
500
+ c = PipeClient(address)
501
+ else:
502
+ c = SocketClient(address)
503
+
504
+ if authkey is not None and not isinstance(authkey, bytes):
505
+ raise TypeError('authkey should be a byte string')
506
+
507
+ if authkey is not None:
508
+ answer_challenge(c, authkey)
509
+ deliver_challenge(c, authkey)
510
+
511
+ return c
512
+
513
+
514
+ if sys.platform != 'win32':
515
+
516
+ def Pipe(duplex=True):
517
+ '''
518
+ Returns pair of connection objects at either end of a pipe
519
+ '''
520
+ if duplex:
521
+ s1, s2 = socket.socketpair()
522
+ s1.setblocking(True)
523
+ s2.setblocking(True)
524
+ c1 = Connection(s1.detach())
525
+ c2 = Connection(s2.detach())
526
+ else:
527
+ fd1, fd2 = os.pipe()
528
+ c1 = Connection(fd1, writable=False)
529
+ c2 = Connection(fd2, readable=False)
530
+
531
+ return c1, c2
532
+
533
+ else:
534
+
535
+ def Pipe(duplex=True):
536
+ '''
537
+ Returns pair of connection objects at either end of a pipe
538
+ '''
539
+ address = arbitrary_address('AF_PIPE')
540
+ if duplex:
541
+ openmode = _winapi.PIPE_ACCESS_DUPLEX
542
+ access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE
543
+ obsize, ibsize = BUFSIZE, BUFSIZE
544
+ else:
545
+ openmode = _winapi.PIPE_ACCESS_INBOUND
546
+ access = _winapi.GENERIC_WRITE
547
+ obsize, ibsize = 0, BUFSIZE
548
+
549
+ h1 = _winapi.CreateNamedPipe(
550
+ address, openmode | _winapi.FILE_FLAG_OVERLAPPED |
551
+ _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE,
552
+ _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE |
553
+ _winapi.PIPE_WAIT,
554
+ 1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER,
555
+ # default security descriptor: the handle cannot be inherited
556
+ _winapi.NULL
557
+ )
558
+ h2 = _winapi.CreateFile(
559
+ address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,
560
+ _winapi.FILE_FLAG_OVERLAPPED, _winapi.NULL
561
+ )
562
+ _winapi.SetNamedPipeHandleState(
563
+ h2, _winapi.PIPE_READMODE_MESSAGE, None, None
564
+ )
565
+
566
+ overlapped = _winapi.ConnectNamedPipe(h1, overlapped=True)
567
+ _, err = overlapped.GetOverlappedResult(True)
568
+ assert err == 0
569
+
570
+ c1 = PipeConnection(h1, writable=duplex)
571
+ c2 = PipeConnection(h2, readable=duplex)
572
+
573
+ return c1, c2
574
+
575
+ #
576
+ # Definitions for connections based on sockets
577
+ #
578
+
579
+ class SocketListener(object):
580
+ '''
581
+ Representation of a socket which is bound to an address and listening
582
+ '''
583
+ def __init__(self, address, family, backlog=1):
584
+ self._socket = socket.socket(getattr(socket, family))
585
+ try:
586
+ # SO_REUSEADDR has different semantics on Windows (issue #2550).
587
+ if os.name == 'posix':
588
+ self._socket.setsockopt(socket.SOL_SOCKET,
589
+ socket.SO_REUSEADDR, 1)
590
+ self._socket.setblocking(True)
591
+ self._socket.bind(address)
592
+ self._socket.listen(backlog)
593
+ self._address = self._socket.getsockname()
594
+ except OSError:
595
+ self._socket.close()
596
+ raise
597
+ self._family = family
598
+ self._last_accepted = None
599
+
600
+ if family == 'AF_UNIX' and not util.is_abstract_socket_namespace(address):
601
+ # Linux abstract socket namespaces do not need to be explicitly unlinked
602
+ self._unlink = util.Finalize(
603
+ self, os.unlink, args=(address,), exitpriority=0
604
+ )
605
+ else:
606
+ self._unlink = None
607
+
608
+ def accept(self):
609
+ s, self._last_accepted = self._socket.accept()
610
+ s.setblocking(True)
611
+ return Connection(s.detach())
612
+
613
+ def close(self):
614
+ try:
615
+ self._socket.close()
616
+ finally:
617
+ unlink = self._unlink
618
+ if unlink is not None:
619
+ self._unlink = None
620
+ unlink()
621
+
622
+
623
+ def SocketClient(address):
624
+ '''
625
+ Return a connection object connected to the socket given by `address`
626
+ '''
627
+ family = address_type(address)
628
+ with socket.socket( getattr(socket, family) ) as s:
629
+ s.setblocking(True)
630
+ s.connect(address)
631
+ return Connection(s.detach())
632
+
633
+ #
634
+ # Definitions for connections based on named pipes
635
+ #
636
+
637
+ if sys.platform == 'win32':
638
+
639
+ class PipeListener(object):
640
+ '''
641
+ Representation of a named pipe
642
+ '''
643
+ def __init__(self, address, backlog=None):
644
+ self._address = address
645
+ self._handle_queue = [self._new_handle(first=True)]
646
+
647
+ self._last_accepted = None
648
+ util.sub_debug('listener created with address=%r', self._address)
649
+ self.close = util.Finalize(
650
+ self, PipeListener._finalize_pipe_listener,
651
+ args=(self._handle_queue, self._address), exitpriority=0
652
+ )
653
+
654
+ def _new_handle(self, first=False):
655
+ flags = _winapi.PIPE_ACCESS_DUPLEX | _winapi.FILE_FLAG_OVERLAPPED
656
+ if first:
657
+ flags |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
658
+ return _winapi.CreateNamedPipe(
659
+ self._address, flags,
660
+ _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE |
661
+ _winapi.PIPE_WAIT,
662
+ _winapi.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE,
663
+ _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL
664
+ )
665
+
666
+ def accept(self):
667
+ self._handle_queue.append(self._new_handle())
668
+ handle = self._handle_queue.pop(0)
669
+ try:
670
+ ov = _winapi.ConnectNamedPipe(handle, overlapped=True)
671
+ except OSError as e:
672
+ if e.winerror != _winapi.ERROR_NO_DATA:
673
+ raise
674
+ # ERROR_NO_DATA can occur if a client has already connected,
675
+ # written data and then disconnected -- see Issue 14725.
676
+ else:
677
+ try:
678
+ res = _winapi.WaitForMultipleObjects(
679
+ [ov.event], False, INFINITE)
680
+ except:
681
+ ov.cancel()
682
+ _winapi.CloseHandle(handle)
683
+ raise
684
+ finally:
685
+ _, err = ov.GetOverlappedResult(True)
686
+ assert err == 0
687
+ return PipeConnection(handle)
688
+
689
+ @staticmethod
690
+ def _finalize_pipe_listener(queue, address):
691
+ util.sub_debug('closing listener with address=%r', address)
692
+ for handle in queue:
693
+ _winapi.CloseHandle(handle)
694
+
695
+ def PipeClient(address):
696
+ '''
697
+ Return a connection object connected to the pipe given by `address`
698
+ '''
699
+ t = _init_timeout()
700
+ while 1:
701
+ try:
702
+ _winapi.WaitNamedPipe(address, 1000)
703
+ h = _winapi.CreateFile(
704
+ address, _winapi.GENERIC_READ | _winapi.GENERIC_WRITE,
705
+ 0, _winapi.NULL, _winapi.OPEN_EXISTING,
706
+ _winapi.FILE_FLAG_OVERLAPPED, _winapi.NULL
707
+ )
708
+ except OSError as e:
709
+ if e.winerror not in (_winapi.ERROR_SEM_TIMEOUT,
710
+ _winapi.ERROR_PIPE_BUSY) or _check_timeout(t):
711
+ raise
712
+ else:
713
+ break
714
+ else:
715
+ raise
716
+
717
+ _winapi.SetNamedPipeHandleState(
718
+ h, _winapi.PIPE_READMODE_MESSAGE, None, None
719
+ )
720
+ return PipeConnection(h)
721
+
722
+ #
723
+ # Authentication stuff
724
+ #
725
+
726
+ MESSAGE_LENGTH = 20
727
+
728
+ CHALLENGE = b'#CHALLENGE#'
729
+ WELCOME = b'#WELCOME#'
730
+ FAILURE = b'#FAILURE#'
731
+
732
+ def deliver_challenge(connection, authkey):
733
+ import hmac
734
+ if not isinstance(authkey, bytes):
735
+ raise ValueError(
736
+ "Authkey must be bytes, not {0!s}".format(type(authkey)))
737
+ message = os.urandom(MESSAGE_LENGTH)
738
+ connection.send_bytes(CHALLENGE + message)
739
+ digest = hmac.new(authkey, message, 'md5').digest()
740
+ response = connection.recv_bytes(256) # reject large message
741
+ if response == digest:
742
+ connection.send_bytes(WELCOME)
743
+ else:
744
+ connection.send_bytes(FAILURE)
745
+ raise AuthenticationError('digest received was wrong')
746
+
747
+ def answer_challenge(connection, authkey):
748
+ import hmac
749
+ if not isinstance(authkey, bytes):
750
+ raise ValueError(
751
+ "Authkey must be bytes, not {0!s}".format(type(authkey)))
752
+ message = connection.recv_bytes(256) # reject large message
753
+ assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message
754
+ message = message[len(CHALLENGE):]
755
+ digest = hmac.new(authkey, message, 'md5').digest()
756
+ connection.send_bytes(digest)
757
+ response = connection.recv_bytes(256) # reject large message
758
+ if response != WELCOME:
759
+ raise AuthenticationError('digest sent was rejected')
760
+
761
+ #
762
+ # Support for using xmlrpclib for serialization
763
+ #
764
+
765
+ class ConnectionWrapper(object):
766
+ def __init__(self, conn, dumps, loads):
767
+ self._conn = conn
768
+ self._dumps = dumps
769
+ self._loads = loads
770
+ for attr in ('fileno', 'close', 'poll', 'recv_bytes', 'send_bytes'):
771
+ obj = getattr(conn, attr)
772
+ setattr(self, attr, obj)
773
+ def send(self, obj):
774
+ s = self._dumps(obj)
775
+ self._conn.send_bytes(s)
776
+ def recv(self):
777
+ s = self._conn.recv_bytes()
778
+ return self._loads(s)
779
+
780
+ def _xml_dumps(obj):
781
+ return xmlrpclib.dumps((obj,), None, None, None, 1).encode('utf-8')
782
+
783
+ def _xml_loads(s):
784
+ (obj,), method = xmlrpclib.loads(s.decode('utf-8'))
785
+ return obj
786
+
787
+ class XmlListener(Listener):
788
+ def accept(self):
789
+ global xmlrpclib
790
+ import xmlrpc.client as xmlrpclib
791
+ obj = Listener.accept(self)
792
+ return ConnectionWrapper(obj, _xml_dumps, _xml_loads)
793
+
794
+ def XmlClient(*args, **kwds):
795
+ global xmlrpclib
796
+ import xmlrpc.client as xmlrpclib
797
+ return ConnectionWrapper(Client(*args, **kwds), _xml_dumps, _xml_loads)
798
+
799
+ #
800
+ # Wait
801
+ #
802
+
803
+ if sys.platform == 'win32':
804
+
805
+ def _exhaustive_wait(handles, timeout):
806
+ # Return ALL handles which are currently signalled. (Only
807
+ # returning the first signalled might create starvation issues.)
808
+ L = list(handles)
809
+ ready = []
810
+ while L:
811
+ res = _winapi.WaitForMultipleObjects(L, False, timeout)
812
+ if res == WAIT_TIMEOUT:
813
+ break
814
+ elif WAIT_OBJECT_0 <= res < WAIT_OBJECT_0 + len(L):
815
+ res -= WAIT_OBJECT_0
816
+ elif WAIT_ABANDONED_0 <= res < WAIT_ABANDONED_0 + len(L):
817
+ res -= WAIT_ABANDONED_0
818
+ else:
819
+ raise RuntimeError('Should not get here')
820
+ ready.append(L[res])
821
+ L = L[res+1:]
822
+ timeout = 0
823
+ return ready
824
+
825
+ _ready_errors = {_winapi.ERROR_BROKEN_PIPE, _winapi.ERROR_NETNAME_DELETED}
826
+
827
+ def wait(object_list, timeout=None):
828
+ '''
829
+ Wait till an object in object_list is ready/readable.
830
+
831
+ Returns list of those objects in object_list which are ready/readable.
832
+ '''
833
+ if timeout is None:
834
+ timeout = INFINITE
835
+ elif timeout < 0:
836
+ timeout = 0
837
+ else:
838
+ timeout = int(timeout * 1000 + 0.5)
839
+
840
+ object_list = list(object_list)
841
+ waithandle_to_obj = {}
842
+ ov_list = []
843
+ ready_objects = set()
844
+ ready_handles = set()
845
+
846
+ try:
847
+ for o in object_list:
848
+ try:
849
+ fileno = getattr(o, 'fileno')
850
+ except AttributeError:
851
+ waithandle_to_obj[o.__index__()] = o
852
+ else:
853
+ # start an overlapped read of length zero
854
+ try:
855
+ ov, err = _winapi.ReadFile(fileno(), 0, True)
856
+ except OSError as e:
857
+ ov, err = None, e.winerror
858
+ if err not in _ready_errors:
859
+ raise
860
+ if err == _winapi.ERROR_IO_PENDING:
861
+ ov_list.append(ov)
862
+ waithandle_to_obj[ov.event] = o
863
+ else:
864
+ # If o.fileno() is an overlapped pipe handle and
865
+ # err == 0 then there is a zero length message
866
+ # in the pipe, but it HAS NOT been consumed...
867
+ if ov and sys.getwindowsversion()[:2] >= (6, 2):
868
+ # ... except on Windows 8 and later, where
869
+ # the message HAS been consumed.
870
+ try:
871
+ _, err = ov.GetOverlappedResult(False)
872
+ except OSError as e:
873
+ err = e.winerror
874
+ if not err and hasattr(o, '_got_empty_message'):
875
+ o._got_empty_message = True
876
+ ready_objects.add(o)
877
+ timeout = 0
878
+
879
+ ready_handles = _exhaustive_wait(waithandle_to_obj.keys(), timeout)
880
+ finally:
881
+ # request that overlapped reads stop
882
+ for ov in ov_list:
883
+ ov.cancel()
884
+
885
+ # wait for all overlapped reads to stop
886
+ for ov in ov_list:
887
+ try:
888
+ _, err = ov.GetOverlappedResult(True)
889
+ except OSError as e:
890
+ err = e.winerror
891
+ if err not in _ready_errors:
892
+ raise
893
+ if err != _winapi.ERROR_OPERATION_ABORTED:
894
+ o = waithandle_to_obj[ov.event]
895
+ ready_objects.add(o)
896
+ if err == 0:
897
+ # If o.fileno() is an overlapped pipe handle then
898
+ # a zero length message HAS been consumed.
899
+ if hasattr(o, '_got_empty_message'):
900
+ o._got_empty_message = True
901
+
902
+ ready_objects.update(waithandle_to_obj[h] for h in ready_handles)
903
+ return [o for o in object_list if o in ready_objects]
904
+
905
+ else:
906
+
907
+ import selectors
908
+
909
+ # poll/select have the advantage of not requiring any extra file
910
+ # descriptor, contrarily to epoll/kqueue (also, they require a single
911
+ # syscall).
912
+ if hasattr(selectors, 'PollSelector'):
913
+ _WaitSelector = selectors.PollSelector
914
+ else:
915
+ _WaitSelector = selectors.SelectSelector
916
+
917
+ def wait(object_list, timeout=None):
918
+ '''
919
+ Wait till an object in object_list is ready/readable.
920
+
921
+ Returns list of those objects in object_list which are ready/readable.
922
+ '''
923
+ with _WaitSelector() as selector:
924
+ for obj in object_list:
925
+ selector.register(obj, selectors.EVENT_READ)
926
+
927
+ if timeout is not None:
928
+ deadline = time.monotonic() + timeout
929
+
930
+ while True:
931
+ ready = selector.select(timeout)
932
+ if ready:
933
+ return [key.fileobj for (key, events) in ready]
934
+ else:
935
+ if timeout is not None:
936
+ timeout = deadline - time.monotonic()
937
+ if timeout < 0:
938
+ return ready
939
+
940
+ #
941
+ # Make connection and socket objects sharable if possible
942
+ #
943
+
944
+ if sys.platform == 'win32':
945
+ def reduce_connection(conn):
946
+ handle = conn.fileno()
947
+ with socket.fromfd(handle, socket.AF_INET, socket.SOCK_STREAM) as s:
948
+ from . import resource_sharer
949
+ ds = resource_sharer.DupSocket(s)
950
+ return rebuild_connection, (ds, conn.readable, conn.writable)
951
+ def rebuild_connection(ds, readable, writable):
952
+ sock = ds.detach()
953
+ return Connection(sock.detach(), readable, writable)
954
+ reduction.register(Connection, reduce_connection)
955
+
956
+ def reduce_pipe_connection(conn):
957
+ access = ((_winapi.FILE_GENERIC_READ if conn.readable else 0) |
958
+ (_winapi.FILE_GENERIC_WRITE if conn.writable else 0))
959
+ dh = reduction.DupHandle(conn.fileno(), access)
960
+ return rebuild_pipe_connection, (dh, conn.readable, conn.writable)
961
+ def rebuild_pipe_connection(dh, readable, writable):
962
+ handle = dh.detach()
963
+ return PipeConnection(handle, readable, writable)
964
+ reduction.register(PipeConnection, reduce_pipe_connection)
965
+
966
+ else:
967
+ def reduce_connection(conn):
968
+ df = reduction.DupFd(conn.fileno())
969
+ return rebuild_connection, (df, conn.readable, conn.writable)
970
+ def rebuild_connection(df, readable, writable):
971
+ fd = df.detach()
972
+ return Connection(fd, readable, writable)
973
+ reduction.register(Connection, reduce_connection)
lib/python3.1/multiprocessing/context.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import threading
4
+
5
+ from . import process
6
+ from . import reduction
7
+
8
+ __all__ = ()
9
+
10
+ #
11
+ # Exceptions
12
+ #
13
+
14
+ class ProcessError(Exception):
15
+ pass
16
+
17
+ class BufferTooShort(ProcessError):
18
+ pass
19
+
20
+ class TimeoutError(ProcessError):
21
+ pass
22
+
23
+ class AuthenticationError(ProcessError):
24
+ pass
25
+
26
+ #
27
+ # Base type for contexts. Bound methods of an instance of this type are included in __all__ of __init__.py
28
+ #
29
+
30
+ class BaseContext(object):
31
+
32
+ ProcessError = ProcessError
33
+ BufferTooShort = BufferTooShort
34
+ TimeoutError = TimeoutError
35
+ AuthenticationError = AuthenticationError
36
+
37
+ current_process = staticmethod(process.current_process)
38
+ parent_process = staticmethod(process.parent_process)
39
+ active_children = staticmethod(process.active_children)
40
+
41
+ def cpu_count(self):
42
+ '''Returns the number of CPUs in the system'''
43
+ num = os.cpu_count()
44
+ if num is None:
45
+ raise NotImplementedError('cannot determine number of cpus')
46
+ else:
47
+ return num
48
+
49
+ def Manager(self):
50
+ '''Returns a manager associated with a running server process
51
+
52
+ The managers methods such as `Lock()`, `Condition()` and `Queue()`
53
+ can be used to create shared objects.
54
+ '''
55
+ from .managers import SyncManager
56
+ m = SyncManager(ctx=self.get_context())
57
+ m.start()
58
+ return m
59
+
60
+ def Pipe(self, duplex=True):
61
+ '''Returns two connection object connected by a pipe'''
62
+ from .connection import Pipe
63
+ return Pipe(duplex)
64
+
65
+ def Lock(self):
66
+ '''Returns a non-recursive lock object'''
67
+ from .synchronize import Lock
68
+ return Lock(ctx=self.get_context())
69
+
70
+ def RLock(self):
71
+ '''Returns a recursive lock object'''
72
+ from .synchronize import RLock
73
+ return RLock(ctx=self.get_context())
74
+
75
+ def Condition(self, lock=None):
76
+ '''Returns a condition object'''
77
+ from .synchronize import Condition
78
+ return Condition(lock, ctx=self.get_context())
79
+
80
+ def Semaphore(self, value=1):
81
+ '''Returns a semaphore object'''
82
+ from .synchronize import Semaphore
83
+ return Semaphore(value, ctx=self.get_context())
84
+
85
+ def BoundedSemaphore(self, value=1):
86
+ '''Returns a bounded semaphore object'''
87
+ from .synchronize import BoundedSemaphore
88
+ return BoundedSemaphore(value, ctx=self.get_context())
89
+
90
+ def Event(self):
91
+ '''Returns an event object'''
92
+ from .synchronize import Event
93
+ return Event(ctx=self.get_context())
94
+
95
+ def Barrier(self, parties, action=None, timeout=None):
96
+ '''Returns a barrier object'''
97
+ from .synchronize import Barrier
98
+ return Barrier(parties, action, timeout, ctx=self.get_context())
99
+
100
+ def Queue(self, maxsize=0):
101
+ '''Returns a queue object'''
102
+ from .queues import Queue
103
+ return Queue(maxsize, ctx=self.get_context())
104
+
105
+ def JoinableQueue(self, maxsize=0):
106
+ '''Returns a queue object'''
107
+ from .queues import JoinableQueue
108
+ return JoinableQueue(maxsize, ctx=self.get_context())
109
+
110
+ def SimpleQueue(self):
111
+ '''Returns a queue object'''
112
+ from .queues import SimpleQueue
113
+ return SimpleQueue(ctx=self.get_context())
114
+
115
+ def Pool(self, processes=None, initializer=None, initargs=(),
116
+ maxtasksperchild=None):
117
+ '''Returns a process pool object'''
118
+ from .pool import Pool
119
+ return Pool(processes, initializer, initargs, maxtasksperchild,
120
+ context=self.get_context())
121
+
122
+ def RawValue(self, typecode_or_type, *args):
123
+ '''Returns a shared object'''
124
+ from .sharedctypes import RawValue
125
+ return RawValue(typecode_or_type, *args)
126
+
127
+ def RawArray(self, typecode_or_type, size_or_initializer):
128
+ '''Returns a shared array'''
129
+ from .sharedctypes import RawArray
130
+ return RawArray(typecode_or_type, size_or_initializer)
131
+
132
+ def Value(self, typecode_or_type, *args, lock=True):
133
+ '''Returns a synchronized shared object'''
134
+ from .sharedctypes import Value
135
+ return Value(typecode_or_type, *args, lock=lock,
136
+ ctx=self.get_context())
137
+
138
+ def Array(self, typecode_or_type, size_or_initializer, *, lock=True):
139
+ '''Returns a synchronized shared array'''
140
+ from .sharedctypes import Array
141
+ return Array(typecode_or_type, size_or_initializer, lock=lock,
142
+ ctx=self.get_context())
143
+
144
+ def freeze_support(self):
145
+ '''Check whether this is a fake forked process in a frozen executable.
146
+ If so then run code specified by commandline and exit.
147
+ '''
148
+ if sys.platform == 'win32' and getattr(sys, 'frozen', False):
149
+ from .spawn import freeze_support
150
+ freeze_support()
151
+
152
+ def get_logger(self):
153
+ '''Return package logger -- if it does not already exist then
154
+ it is created.
155
+ '''
156
+ from .util import get_logger
157
+ return get_logger()
158
+
159
+ def log_to_stderr(self, level=None):
160
+ '''Turn on logging and add a handler which prints to stderr'''
161
+ from .util import log_to_stderr
162
+ return log_to_stderr(level)
163
+
164
+ def allow_connection_pickling(self):
165
+ '''Install support for sending connections and sockets
166
+ between processes
167
+ '''
168
+ # This is undocumented. In previous versions of multiprocessing
169
+ # its only effect was to make socket objects inheritable on Windows.
170
+ from . import connection
171
+
172
+ def set_executable(self, executable):
173
+ '''Sets the path to a python.exe or pythonw.exe binary used to run
174
+ child processes instead of sys.executable when using the 'spawn'
175
+ start method. Useful for people embedding Python.
176
+ '''
177
+ from .spawn import set_executable
178
+ set_executable(executable)
179
+
180
+ def set_forkserver_preload(self, module_names):
181
+ '''Set list of module names to try to load in forkserver process.
182
+ This is really just a hint.
183
+ '''
184
+ from .forkserver import set_forkserver_preload
185
+ set_forkserver_preload(module_names)
186
+
187
+ def get_context(self, method=None):
188
+ if method is None:
189
+ return self
190
+ try:
191
+ ctx = _concrete_contexts[method]
192
+ except KeyError:
193
+ raise ValueError('cannot find context for %r' % method) from None
194
+ ctx._check_available()
195
+ return ctx
196
+
197
+ def get_start_method(self, allow_none=False):
198
+ return self._name
199
+
200
+ def set_start_method(self, method, force=False):
201
+ raise ValueError('cannot set start method of concrete context')
202
+
203
+ @property
204
+ def reducer(self):
205
+ '''Controls how objects will be reduced to a form that can be
206
+ shared with other processes.'''
207
+ return globals().get('reduction')
208
+
209
+ @reducer.setter
210
+ def reducer(self, reduction):
211
+ globals()['reduction'] = reduction
212
+
213
+ def _check_available(self):
214
+ pass
215
+
216
+ #
217
+ # Type of default context -- underlying context can be set at most once
218
+ #
219
+
220
+ class Process(process.BaseProcess):
221
+ _start_method = None
222
+ @staticmethod
223
+ def _Popen(process_obj):
224
+ return _default_context.get_context().Process._Popen(process_obj)
225
+
226
+ @staticmethod
227
+ def _after_fork():
228
+ return _default_context.get_context().Process._after_fork()
229
+
230
+ class DefaultContext(BaseContext):
231
+ Process = Process
232
+
233
+ def __init__(self, context):
234
+ self._default_context = context
235
+ self._actual_context = None
236
+
237
+ def get_context(self, method=None):
238
+ if method is None:
239
+ if self._actual_context is None:
240
+ self._actual_context = self._default_context
241
+ return self._actual_context
242
+ else:
243
+ return super().get_context(method)
244
+
245
+ def set_start_method(self, method, force=False):
246
+ if self._actual_context is not None and not force:
247
+ raise RuntimeError('context has already been set')
248
+ if method is None and force:
249
+ self._actual_context = None
250
+ return
251
+ self._actual_context = self.get_context(method)
252
+
253
+ def get_start_method(self, allow_none=False):
254
+ if self._actual_context is None:
255
+ if allow_none:
256
+ return None
257
+ self._actual_context = self._default_context
258
+ return self._actual_context._name
259
+
260
+ def get_all_start_methods(self):
261
+ if sys.platform == 'win32':
262
+ return ['spawn']
263
+ else:
264
+ methods = ['spawn', 'fork'] if sys.platform == 'darwin' else ['fork', 'spawn']
265
+ if reduction.HAVE_SEND_HANDLE:
266
+ methods.append('forkserver')
267
+ return methods
268
+
269
+
270
+ #
271
+ # Context types for fixed start method
272
+ #
273
+
274
+ if sys.platform != 'win32':
275
+
276
+ class ForkProcess(process.BaseProcess):
277
+ _start_method = 'fork'
278
+ @staticmethod
279
+ def _Popen(process_obj):
280
+ from .popen_fork import Popen
281
+ return Popen(process_obj)
282
+
283
+ class SpawnProcess(process.BaseProcess):
284
+ _start_method = 'spawn'
285
+ @staticmethod
286
+ def _Popen(process_obj):
287
+ from .popen_spawn_posix import Popen
288
+ return Popen(process_obj)
289
+
290
+ @staticmethod
291
+ def _after_fork():
292
+ # process is spawned, nothing to do
293
+ pass
294
+
295
+ class ForkServerProcess(process.BaseProcess):
296
+ _start_method = 'forkserver'
297
+ @staticmethod
298
+ def _Popen(process_obj):
299
+ from .popen_forkserver import Popen
300
+ return Popen(process_obj)
301
+
302
+ class ForkContext(BaseContext):
303
+ _name = 'fork'
304
+ Process = ForkProcess
305
+
306
+ class SpawnContext(BaseContext):
307
+ _name = 'spawn'
308
+ Process = SpawnProcess
309
+
310
+ class ForkServerContext(BaseContext):
311
+ _name = 'forkserver'
312
+ Process = ForkServerProcess
313
+ def _check_available(self):
314
+ if not reduction.HAVE_SEND_HANDLE:
315
+ raise ValueError('forkserver start method not available')
316
+
317
+ _concrete_contexts = {
318
+ 'fork': ForkContext(),
319
+ 'spawn': SpawnContext(),
320
+ 'forkserver': ForkServerContext(),
321
+ }
322
+ if sys.platform == 'darwin':
323
+ # bpo-33725: running arbitrary code after fork() is no longer reliable
324
+ # on macOS since macOS 10.14 (Mojave). Use spawn by default instead.
325
+ _default_context = DefaultContext(_concrete_contexts['spawn'])
326
+ else:
327
+ _default_context = DefaultContext(_concrete_contexts['fork'])
328
+
329
+ else:
330
+
331
+ class SpawnProcess(process.BaseProcess):
332
+ _start_method = 'spawn'
333
+ @staticmethod
334
+ def _Popen(process_obj):
335
+ from .popen_spawn_win32 import Popen
336
+ return Popen(process_obj)
337
+
338
+ @staticmethod
339
+ def _after_fork():
340
+ # process is spawned, nothing to do
341
+ pass
342
+
343
+ class SpawnContext(BaseContext):
344
+ _name = 'spawn'
345
+ Process = SpawnProcess
346
+
347
+ _concrete_contexts = {
348
+ 'spawn': SpawnContext(),
349
+ }
350
+ _default_context = DefaultContext(_concrete_contexts['spawn'])
351
+
352
+ #
353
+ # Force the start method
354
+ #
355
+
356
+ def _force_start_method(method):
357
+ _default_context._actual_context = _concrete_contexts[method]
358
+
359
+ #
360
+ # Check that the current thread is spawning a child process
361
+ #
362
+
363
+ _tls = threading.local()
364
+
365
+ def get_spawning_popen():
366
+ return getattr(_tls, 'spawning_popen', None)
367
+
368
+ def set_spawning_popen(popen):
369
+ _tls.spawning_popen = popen
370
+
371
+ def assert_spawning(obj):
372
+ if get_spawning_popen() is None:
373
+ raise RuntimeError(
374
+ '%s objects should only be shared between processes'
375
+ ' through inheritance' % type(obj).__name__
376
+ )
lib/python3.1/multiprocessing/dummy/__init__.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Support for the API of the multiprocessing package using threads
3
+ #
4
+ # multiprocessing/dummy/__init__.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = [
11
+ 'Process', 'current_process', 'active_children', 'freeze_support',
12
+ 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition',
13
+ 'Event', 'Barrier', 'Queue', 'Manager', 'Pipe', 'Pool', 'JoinableQueue'
14
+ ]
15
+
16
+ #
17
+ # Imports
18
+ #
19
+
20
+ import threading
21
+ import sys
22
+ import weakref
23
+ import array
24
+
25
+ from .connection import Pipe
26
+ from threading import Lock, RLock, Semaphore, BoundedSemaphore
27
+ from threading import Event, Condition, Barrier
28
+ from queue import Queue
29
+
30
+ #
31
+ #
32
+ #
33
+
34
+ class DummyProcess(threading.Thread):
35
+
36
+ def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
37
+ threading.Thread.__init__(self, group, target, name, args, kwargs)
38
+ self._pid = None
39
+ self._children = weakref.WeakKeyDictionary()
40
+ self._start_called = False
41
+ self._parent = current_process()
42
+
43
+ def start(self):
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()))
48
+ self._start_called = True
49
+ if hasattr(self._parent, '_children'):
50
+ self._parent._children[self] = None
51
+ threading.Thread.start(self)
52
+
53
+ @property
54
+ def exitcode(self):
55
+ if self._start_called and not self.is_alive():
56
+ return 0
57
+ else:
58
+ return None
59
+
60
+ #
61
+ #
62
+ #
63
+
64
+ Process = DummyProcess
65
+ current_process = threading.current_thread
66
+ current_process()._children = weakref.WeakKeyDictionary()
67
+
68
+ def active_children():
69
+ children = current_process()._children
70
+ for p in list(children):
71
+ if not p.is_alive():
72
+ children.pop(p, None)
73
+ return list(children)
74
+
75
+ def freeze_support():
76
+ pass
77
+
78
+ #
79
+ #
80
+ #
81
+
82
+ class Namespace(object):
83
+ def __init__(self, /, **kwds):
84
+ self.__dict__.update(kwds)
85
+ def __repr__(self):
86
+ items = list(self.__dict__.items())
87
+ temp = []
88
+ for name, value in items:
89
+ if not name.startswith('_'):
90
+ temp.append('%s=%r' % (name, value))
91
+ temp.sort()
92
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(temp))
93
+
94
+ dict = dict
95
+ list = list
96
+
97
+ def Array(typecode, sequence, lock=True):
98
+ return array.array(typecode, sequence)
99
+
100
+ class Value(object):
101
+ def __init__(self, typecode, value, lock=True):
102
+ self._typecode = typecode
103
+ self._value = value
104
+
105
+ @property
106
+ def value(self):
107
+ return self._value
108
+
109
+ @value.setter
110
+ def value(self, value):
111
+ self._value = value
112
+
113
+ def __repr__(self):
114
+ return '<%s(%r, %r)>'%(type(self).__name__,self._typecode,self._value)
115
+
116
+ def Manager():
117
+ return sys.modules[__name__]
118
+
119
+ def shutdown():
120
+ pass
121
+
122
+ def Pool(processes=None, initializer=None, initargs=()):
123
+ from ..pool import ThreadPool
124
+ return ThreadPool(processes, initializer, initargs)
125
+
126
+ JoinableQueue = Queue
lib/python3.1/multiprocessing/dummy/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (4.12 kB). View file
 
lib/python3.1/multiprocessing/dummy/__pycache__/connection.cpython-310.pyc ADDED
Binary file (2.82 kB). View file
 
lib/python3.1/multiprocessing/dummy/connection.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Analogue of `multiprocessing.connection` which uses queues instead of sockets
3
+ #
4
+ # multiprocessing/dummy/connection.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = [ 'Client', 'Listener', 'Pipe' ]
11
+
12
+ from queue import Queue
13
+
14
+
15
+ families = [None]
16
+
17
+
18
+ class Listener(object):
19
+
20
+ def __init__(self, address=None, family=None, backlog=1):
21
+ self._backlog_queue = Queue(backlog)
22
+
23
+ def accept(self):
24
+ return Connection(*self._backlog_queue.get())
25
+
26
+ def close(self):
27
+ self._backlog_queue = None
28
+
29
+ @property
30
+ def address(self):
31
+ return self._backlog_queue
32
+
33
+ def __enter__(self):
34
+ return self
35
+
36
+ def __exit__(self, exc_type, exc_value, exc_tb):
37
+ self.close()
38
+
39
+
40
+ def Client(address):
41
+ _in, _out = Queue(), Queue()
42
+ address.put((_out, _in))
43
+ return Connection(_in, _out)
44
+
45
+
46
+ def Pipe(duplex=True):
47
+ a, b = Queue(), Queue()
48
+ return Connection(a, b), Connection(b, a)
49
+
50
+
51
+ class Connection(object):
52
+
53
+ def __init__(self, _in, _out):
54
+ self._out = _out
55
+ self._in = _in
56
+ self.send = self.send_bytes = _out.put
57
+ self.recv = self.recv_bytes = _in.get
58
+
59
+ def poll(self, timeout=0.0):
60
+ if self._in.qsize() > 0:
61
+ return True
62
+ if timeout <= 0.0:
63
+ return False
64
+ with self._in.not_empty:
65
+ self._in.not_empty.wait(timeout)
66
+ return self._in.qsize() > 0
67
+
68
+ def close(self):
69
+ pass
70
+
71
+ def __enter__(self):
72
+ return self
73
+
74
+ def __exit__(self, exc_type, exc_value, exc_tb):
75
+ self.close()
lib/python3.1/multiprocessing/forkserver.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import errno
2
+ import os
3
+ import selectors
4
+ import signal
5
+ import socket
6
+ import struct
7
+ import sys
8
+ import threading
9
+ import warnings
10
+
11
+ from . import connection
12
+ from . import process
13
+ from .context import reduction
14
+ from . import resource_tracker
15
+ from . import spawn
16
+ from . import util
17
+
18
+ __all__ = ['ensure_running', 'get_inherited_fds', 'connect_to_new_process',
19
+ 'set_forkserver_preload']
20
+
21
+ #
22
+ #
23
+ #
24
+
25
+ MAXFDS_TO_SEND = 256
26
+ SIGNED_STRUCT = struct.Struct('q') # large enough for pid_t
27
+
28
+ #
29
+ # Forkserver class
30
+ #
31
+
32
+ class ForkServer(object):
33
+
34
+ def __init__(self):
35
+ self._forkserver_address = None
36
+ self._forkserver_alive_fd = None
37
+ self._forkserver_pid = None
38
+ self._inherited_fds = None
39
+ self._lock = threading.Lock()
40
+ self._preload_modules = ['__main__']
41
+
42
+ def _stop(self):
43
+ # Method used by unit tests to stop the server
44
+ with self._lock:
45
+ self._stop_unlocked()
46
+
47
+ def _stop_unlocked(self):
48
+ if self._forkserver_pid is None:
49
+ return
50
+
51
+ # close the "alive" file descriptor asks the server to stop
52
+ os.close(self._forkserver_alive_fd)
53
+ self._forkserver_alive_fd = None
54
+
55
+ os.waitpid(self._forkserver_pid, 0)
56
+ self._forkserver_pid = None
57
+
58
+ if not util.is_abstract_socket_namespace(self._forkserver_address):
59
+ os.unlink(self._forkserver_address)
60
+ self._forkserver_address = None
61
+
62
+ def set_forkserver_preload(self, modules_names):
63
+ '''Set list of module names to try to load in forkserver process.'''
64
+ if not all(type(mod) is str for mod in self._preload_modules):
65
+ raise TypeError('module_names must be a list of strings')
66
+ self._preload_modules = modules_names
67
+
68
+ def get_inherited_fds(self):
69
+ '''Return list of fds inherited from parent process.
70
+
71
+ This returns None if the current process was not started by fork
72
+ server.
73
+ '''
74
+ return self._inherited_fds
75
+
76
+ def connect_to_new_process(self, fds):
77
+ '''Request forkserver to create a child process.
78
+
79
+ Returns a pair of fds (status_r, data_w). The calling process can read
80
+ the child process's pid and (eventually) its returncode from status_r.
81
+ The calling process should write to data_w the pickled preparation and
82
+ process data.
83
+ '''
84
+ self.ensure_running()
85
+ if len(fds) + 4 >= MAXFDS_TO_SEND:
86
+ raise ValueError('too many fds')
87
+ with socket.socket(socket.AF_UNIX) as client:
88
+ client.connect(self._forkserver_address)
89
+ parent_r, child_w = os.pipe()
90
+ child_r, parent_w = os.pipe()
91
+ allfds = [child_r, child_w, self._forkserver_alive_fd,
92
+ resource_tracker.getfd()]
93
+ allfds += fds
94
+ try:
95
+ reduction.sendfds(client, allfds)
96
+ return parent_r, parent_w
97
+ except:
98
+ os.close(parent_r)
99
+ os.close(parent_w)
100
+ raise
101
+ finally:
102
+ os.close(child_r)
103
+ os.close(child_w)
104
+
105
+ def ensure_running(self):
106
+ '''Make sure that a fork server is running.
107
+
108
+ This can be called from any process. Note that usually a child
109
+ process will just reuse the forkserver started by its parent, so
110
+ ensure_running() will do nothing.
111
+ '''
112
+ with self._lock:
113
+ resource_tracker.ensure_running()
114
+ if self._forkserver_pid is not None:
115
+ # forkserver was launched before, is it still running?
116
+ pid, status = os.waitpid(self._forkserver_pid, os.WNOHANG)
117
+ if not pid:
118
+ # still alive
119
+ return
120
+ # dead, launch it again
121
+ os.close(self._forkserver_alive_fd)
122
+ self._forkserver_address = None
123
+ self._forkserver_alive_fd = None
124
+ self._forkserver_pid = None
125
+
126
+ cmd = ('from multiprocessing.forkserver import main; ' +
127
+ 'main(%d, %d, %r, **%r)')
128
+
129
+ if self._preload_modules:
130
+ desired_keys = {'main_path', 'sys_path'}
131
+ data = spawn.get_preparation_data('ignore')
132
+ data = {x: y for x, y in data.items() if x in desired_keys}
133
+ else:
134
+ data = {}
135
+
136
+ with socket.socket(socket.AF_UNIX) as listener:
137
+ address = connection.arbitrary_address('AF_UNIX')
138
+ listener.bind(address)
139
+ if not util.is_abstract_socket_namespace(address):
140
+ os.chmod(address, 0o600)
141
+ listener.listen()
142
+
143
+ # all client processes own the write end of the "alive" pipe;
144
+ # when they all terminate the read end becomes ready.
145
+ alive_r, alive_w = os.pipe()
146
+ try:
147
+ fds_to_pass = [listener.fileno(), alive_r]
148
+ cmd %= (listener.fileno(), alive_r, self._preload_modules,
149
+ data)
150
+ exe = spawn.get_executable()
151
+ args = [exe] + util._args_from_interpreter_flags()
152
+ args += ['-c', cmd]
153
+ pid = util.spawnv_passfds(exe, args, fds_to_pass)
154
+ except:
155
+ os.close(alive_w)
156
+ raise
157
+ finally:
158
+ os.close(alive_r)
159
+ self._forkserver_address = address
160
+ self._forkserver_alive_fd = alive_w
161
+ self._forkserver_pid = pid
162
+
163
+ #
164
+ #
165
+ #
166
+
167
+ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
168
+ '''Run forkserver.'''
169
+ if preload:
170
+ if '__main__' in preload and main_path is not None:
171
+ process.current_process()._inheriting = True
172
+ try:
173
+ spawn.import_main_path(main_path)
174
+ finally:
175
+ del process.current_process()._inheriting
176
+ for modname in preload:
177
+ try:
178
+ __import__(modname)
179
+ except ImportError:
180
+ pass
181
+
182
+ util._close_stdin()
183
+
184
+ sig_r, sig_w = os.pipe()
185
+ os.set_blocking(sig_r, False)
186
+ os.set_blocking(sig_w, False)
187
+
188
+ def sigchld_handler(*_unused):
189
+ # Dummy signal handler, doesn't do anything
190
+ pass
191
+
192
+ handlers = {
193
+ # unblocking SIGCHLD allows the wakeup fd to notify our event loop
194
+ signal.SIGCHLD: sigchld_handler,
195
+ # protect the process from ^C
196
+ signal.SIGINT: signal.SIG_IGN,
197
+ }
198
+ old_handlers = {sig: signal.signal(sig, val)
199
+ for (sig, val) in handlers.items()}
200
+
201
+ # calling os.write() in the Python signal handler is racy
202
+ signal.set_wakeup_fd(sig_w)
203
+
204
+ # map child pids to client fds
205
+ pid_to_fd = {}
206
+
207
+ with socket.socket(socket.AF_UNIX, fileno=listener_fd) as listener, \
208
+ selectors.DefaultSelector() as selector:
209
+ _forkserver._forkserver_address = listener.getsockname()
210
+
211
+ selector.register(listener, selectors.EVENT_READ)
212
+ selector.register(alive_r, selectors.EVENT_READ)
213
+ selector.register(sig_r, selectors.EVENT_READ)
214
+
215
+ while True:
216
+ try:
217
+ while True:
218
+ rfds = [key.fileobj for (key, events) in selector.select()]
219
+ if rfds:
220
+ break
221
+
222
+ if alive_r in rfds:
223
+ # EOF because no more client processes left
224
+ assert os.read(alive_r, 1) == b'', "Not at EOF?"
225
+ raise SystemExit
226
+
227
+ if sig_r in rfds:
228
+ # Got SIGCHLD
229
+ os.read(sig_r, 65536) # exhaust
230
+ while True:
231
+ # Scan for child processes
232
+ try:
233
+ pid, sts = os.waitpid(-1, os.WNOHANG)
234
+ except ChildProcessError:
235
+ break
236
+ if pid == 0:
237
+ break
238
+ child_w = pid_to_fd.pop(pid, None)
239
+ if child_w is not None:
240
+ returncode = os.waitstatus_to_exitcode(sts)
241
+
242
+ # Send exit code to client process
243
+ try:
244
+ write_signed(child_w, returncode)
245
+ except BrokenPipeError:
246
+ # client vanished
247
+ pass
248
+ os.close(child_w)
249
+ else:
250
+ # This shouldn't happen really
251
+ warnings.warn('forkserver: waitpid returned '
252
+ 'unexpected pid %d' % pid)
253
+
254
+ if listener in rfds:
255
+ # Incoming fork request
256
+ with listener.accept()[0] as s:
257
+ # Receive fds from client
258
+ fds = reduction.recvfds(s, MAXFDS_TO_SEND + 1)
259
+ if len(fds) > MAXFDS_TO_SEND:
260
+ raise RuntimeError(
261
+ "Too many ({0:n}) fds to send".format(
262
+ len(fds)))
263
+ child_r, child_w, *fds = fds
264
+ s.close()
265
+ pid = os.fork()
266
+ if pid == 0:
267
+ # Child
268
+ code = 1
269
+ try:
270
+ listener.close()
271
+ selector.close()
272
+ unused_fds = [alive_r, child_w, sig_r, sig_w]
273
+ unused_fds.extend(pid_to_fd.values())
274
+ code = _serve_one(child_r, fds,
275
+ unused_fds,
276
+ old_handlers)
277
+ except Exception:
278
+ sys.excepthook(*sys.exc_info())
279
+ sys.stderr.flush()
280
+ finally:
281
+ os._exit(code)
282
+ else:
283
+ # Send pid to client process
284
+ try:
285
+ write_signed(child_w, pid)
286
+ except BrokenPipeError:
287
+ # client vanished
288
+ pass
289
+ pid_to_fd[pid] = child_w
290
+ os.close(child_r)
291
+ for fd in fds:
292
+ os.close(fd)
293
+
294
+ except OSError as e:
295
+ if e.errno != errno.ECONNABORTED:
296
+ raise
297
+
298
+
299
+ def _serve_one(child_r, fds, unused_fds, handlers):
300
+ # close unnecessary stuff and reset signal handlers
301
+ signal.set_wakeup_fd(-1)
302
+ for sig, val in handlers.items():
303
+ signal.signal(sig, val)
304
+ for fd in unused_fds:
305
+ os.close(fd)
306
+
307
+ (_forkserver._forkserver_alive_fd,
308
+ resource_tracker._resource_tracker._fd,
309
+ *_forkserver._inherited_fds) = fds
310
+
311
+ # Run process object received over pipe
312
+ parent_sentinel = os.dup(child_r)
313
+ code = spawn._main(child_r, parent_sentinel)
314
+
315
+ return code
316
+
317
+
318
+ #
319
+ # Read and write signed numbers
320
+ #
321
+
322
+ def read_signed(fd):
323
+ data = b''
324
+ length = SIGNED_STRUCT.size
325
+ while len(data) < length:
326
+ s = os.read(fd, length - len(data))
327
+ if not s:
328
+ raise EOFError('unexpected EOF')
329
+ data += s
330
+ return SIGNED_STRUCT.unpack(data)[0]
331
+
332
+ def write_signed(fd, n):
333
+ msg = SIGNED_STRUCT.pack(n)
334
+ while msg:
335
+ nbytes = os.write(fd, msg)
336
+ if nbytes == 0:
337
+ raise RuntimeError('should not get here')
338
+ msg = msg[nbytes:]
339
+
340
+ #
341
+ #
342
+ #
343
+
344
+ _forkserver = ForkServer()
345
+ ensure_running = _forkserver.ensure_running
346
+ get_inherited_fds = _forkserver.get_inherited_fds
347
+ connect_to_new_process = _forkserver.connect_to_new_process
348
+ set_forkserver_preload = _forkserver.set_forkserver_preload
lib/python3.1/multiprocessing/heap.py ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module which supports allocation of memory from an mmap
3
+ #
4
+ # multiprocessing/heap.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ import bisect
11
+ from collections import defaultdict
12
+ import mmap
13
+ import os
14
+ import sys
15
+ import tempfile
16
+ import threading
17
+
18
+ from .context import reduction, assert_spawning
19
+ from . import util
20
+
21
+ __all__ = ['BufferWrapper']
22
+
23
+ #
24
+ # Inheritable class which wraps an mmap, and from which blocks can be allocated
25
+ #
26
+
27
+ if sys.platform == 'win32':
28
+
29
+ import _winapi
30
+
31
+ class Arena(object):
32
+ """
33
+ A shared memory area backed by anonymous memory (Windows).
34
+ """
35
+
36
+ _rand = tempfile._RandomNameSequence()
37
+
38
+ def __init__(self, size):
39
+ self.size = size
40
+ for i in range(100):
41
+ name = 'pym-%d-%s' % (os.getpid(), next(self._rand))
42
+ buf = mmap.mmap(-1, size, tagname=name)
43
+ if _winapi.GetLastError() == 0:
44
+ break
45
+ # We have reopened a preexisting mmap.
46
+ buf.close()
47
+ else:
48
+ raise FileExistsError('Cannot find name for new mmap')
49
+ self.name = name
50
+ self.buffer = buf
51
+ self._state = (self.size, self.name)
52
+
53
+ def __getstate__(self):
54
+ assert_spawning(self)
55
+ return self._state
56
+
57
+ def __setstate__(self, state):
58
+ self.size, self.name = self._state = state
59
+ # Reopen existing mmap
60
+ self.buffer = mmap.mmap(-1, self.size, tagname=self.name)
61
+ # XXX Temporarily preventing buildbot failures while determining
62
+ # XXX the correct long-term fix. See issue 23060
63
+ #assert _winapi.GetLastError() == _winapi.ERROR_ALREADY_EXISTS
64
+
65
+ else:
66
+
67
+ class Arena(object):
68
+ """
69
+ A shared memory area backed by a temporary file (POSIX).
70
+ """
71
+
72
+ if sys.platform == 'linux':
73
+ _dir_candidates = ['/dev/shm']
74
+ else:
75
+ _dir_candidates = []
76
+
77
+ def __init__(self, size, fd=-1):
78
+ self.size = size
79
+ self.fd = fd
80
+ if fd == -1:
81
+ # Arena is created anew (if fd != -1, it means we're coming
82
+ # from rebuild_arena() below)
83
+ self.fd, name = tempfile.mkstemp(
84
+ prefix='pym-%d-'%os.getpid(),
85
+ dir=self._choose_dir(size))
86
+ os.unlink(name)
87
+ util.Finalize(self, os.close, (self.fd,))
88
+ os.ftruncate(self.fd, size)
89
+ self.buffer = mmap.mmap(self.fd, self.size)
90
+
91
+ def _choose_dir(self, size):
92
+ # Choose a non-storage backed directory if possible,
93
+ # to improve performance
94
+ for d in self._dir_candidates:
95
+ st = os.statvfs(d)
96
+ if st.f_bavail * st.f_frsize >= size: # enough free space?
97
+ return d
98
+ return util.get_temp_dir()
99
+
100
+ def reduce_arena(a):
101
+ if a.fd == -1:
102
+ raise ValueError('Arena is unpicklable because '
103
+ 'forking was enabled when it was created')
104
+ return rebuild_arena, (a.size, reduction.DupFd(a.fd))
105
+
106
+ def rebuild_arena(size, dupfd):
107
+ return Arena(size, dupfd.detach())
108
+
109
+ reduction.register(Arena, reduce_arena)
110
+
111
+ #
112
+ # Class allowing allocation of chunks of memory from arenas
113
+ #
114
+
115
+ class Heap(object):
116
+
117
+ # Minimum malloc() alignment
118
+ _alignment = 8
119
+
120
+ _DISCARD_FREE_SPACE_LARGER_THAN = 4 * 1024 ** 2 # 4 MB
121
+ _DOUBLE_ARENA_SIZE_UNTIL = 4 * 1024 ** 2
122
+
123
+ def __init__(self, size=mmap.PAGESIZE):
124
+ self._lastpid = os.getpid()
125
+ self._lock = threading.Lock()
126
+ # Current arena allocation size
127
+ self._size = size
128
+ # A sorted list of available block sizes in arenas
129
+ self._lengths = []
130
+
131
+ # Free block management:
132
+ # - map each block size to a list of `(Arena, start, stop)` blocks
133
+ self._len_to_seq = {}
134
+ # - map `(Arena, start)` tuple to the `(Arena, start, stop)` block
135
+ # starting at that offset
136
+ self._start_to_block = {}
137
+ # - map `(Arena, stop)` tuple to the `(Arena, start, stop)` block
138
+ # ending at that offset
139
+ self._stop_to_block = {}
140
+
141
+ # Map arenas to their `(Arena, start, stop)` blocks in use
142
+ self._allocated_blocks = defaultdict(set)
143
+ self._arenas = []
144
+
145
+ # List of pending blocks to free - see comment in free() below
146
+ self._pending_free_blocks = []
147
+
148
+ # Statistics
149
+ self._n_mallocs = 0
150
+ self._n_frees = 0
151
+
152
+ @staticmethod
153
+ def _roundup(n, alignment):
154
+ # alignment must be a power of 2
155
+ mask = alignment - 1
156
+ return (n + mask) & ~mask
157
+
158
+ def _new_arena(self, size):
159
+ # Create a new arena with at least the given *size*
160
+ length = self._roundup(max(self._size, size), mmap.PAGESIZE)
161
+ # We carve larger and larger arenas, for efficiency, until we
162
+ # reach a large-ish size (roughly L3 cache-sized)
163
+ if self._size < self._DOUBLE_ARENA_SIZE_UNTIL:
164
+ self._size *= 2
165
+ util.info('allocating a new mmap of length %d', length)
166
+ arena = Arena(length)
167
+ self._arenas.append(arena)
168
+ return (arena, 0, length)
169
+
170
+ def _discard_arena(self, arena):
171
+ # Possibly delete the given (unused) arena
172
+ length = arena.size
173
+ # Reusing an existing arena is faster than creating a new one, so
174
+ # we only reclaim space if it's large enough.
175
+ if length < self._DISCARD_FREE_SPACE_LARGER_THAN:
176
+ return
177
+ blocks = self._allocated_blocks.pop(arena)
178
+ assert not blocks
179
+ del self._start_to_block[(arena, 0)]
180
+ del self._stop_to_block[(arena, length)]
181
+ self._arenas.remove(arena)
182
+ seq = self._len_to_seq[length]
183
+ seq.remove((arena, 0, length))
184
+ if not seq:
185
+ del self._len_to_seq[length]
186
+ self._lengths.remove(length)
187
+
188
+ def _malloc(self, size):
189
+ # returns a large enough block -- it might be much larger
190
+ i = bisect.bisect_left(self._lengths, size)
191
+ if i == len(self._lengths):
192
+ return self._new_arena(size)
193
+ else:
194
+ length = self._lengths[i]
195
+ seq = self._len_to_seq[length]
196
+ block = seq.pop()
197
+ if not seq:
198
+ del self._len_to_seq[length], self._lengths[i]
199
+
200
+ (arena, start, stop) = block
201
+ del self._start_to_block[(arena, start)]
202
+ del self._stop_to_block[(arena, stop)]
203
+ return block
204
+
205
+ def _add_free_block(self, block):
206
+ # make block available and try to merge with its neighbours in the arena
207
+ (arena, start, stop) = block
208
+
209
+ try:
210
+ prev_block = self._stop_to_block[(arena, start)]
211
+ except KeyError:
212
+ pass
213
+ else:
214
+ start, _ = self._absorb(prev_block)
215
+
216
+ try:
217
+ next_block = self._start_to_block[(arena, stop)]
218
+ except KeyError:
219
+ pass
220
+ else:
221
+ _, stop = self._absorb(next_block)
222
+
223
+ block = (arena, start, stop)
224
+ length = stop - start
225
+
226
+ try:
227
+ self._len_to_seq[length].append(block)
228
+ except KeyError:
229
+ self._len_to_seq[length] = [block]
230
+ bisect.insort(self._lengths, length)
231
+
232
+ self._start_to_block[(arena, start)] = block
233
+ self._stop_to_block[(arena, stop)] = block
234
+
235
+ def _absorb(self, block):
236
+ # deregister this block so it can be merged with a neighbour
237
+ (arena, start, stop) = block
238
+ del self._start_to_block[(arena, start)]
239
+ del self._stop_to_block[(arena, stop)]
240
+
241
+ length = stop - start
242
+ seq = self._len_to_seq[length]
243
+ seq.remove(block)
244
+ if not seq:
245
+ del self._len_to_seq[length]
246
+ self._lengths.remove(length)
247
+
248
+ return start, stop
249
+
250
+ def _remove_allocated_block(self, block):
251
+ arena, start, stop = block
252
+ blocks = self._allocated_blocks[arena]
253
+ blocks.remove((start, stop))
254
+ if not blocks:
255
+ # Arena is entirely free, discard it from this process
256
+ self._discard_arena(arena)
257
+
258
+ def _free_pending_blocks(self):
259
+ # Free all the blocks in the pending list - called with the lock held.
260
+ while True:
261
+ try:
262
+ block = self._pending_free_blocks.pop()
263
+ except IndexError:
264
+ break
265
+ self._add_free_block(block)
266
+ self._remove_allocated_block(block)
267
+
268
+ def free(self, block):
269
+ # free a block returned by malloc()
270
+ # Since free() can be called asynchronously by the GC, it could happen
271
+ # that it's called while self._lock is held: in that case,
272
+ # self._lock.acquire() would deadlock (issue #12352). To avoid that, a
273
+ # trylock is used instead, and if the lock can't be acquired
274
+ # immediately, the block is added to a list of blocks to be freed
275
+ # synchronously sometimes later from malloc() or free(), by calling
276
+ # _free_pending_blocks() (appending and retrieving from a list is not
277
+ # strictly thread-safe but under CPython it's atomic thanks to the GIL).
278
+ if os.getpid() != self._lastpid:
279
+ raise ValueError(
280
+ "My pid ({0:n}) is not last pid {1:n}".format(
281
+ os.getpid(),self._lastpid))
282
+ if not self._lock.acquire(False):
283
+ # can't acquire the lock right now, add the block to the list of
284
+ # pending blocks to free
285
+ self._pending_free_blocks.append(block)
286
+ else:
287
+ # we hold the lock
288
+ try:
289
+ self._n_frees += 1
290
+ self._free_pending_blocks()
291
+ self._add_free_block(block)
292
+ self._remove_allocated_block(block)
293
+ finally:
294
+ self._lock.release()
295
+
296
+ def malloc(self, size):
297
+ # return a block of right size (possibly rounded up)
298
+ if size < 0:
299
+ raise ValueError("Size {0:n} out of range".format(size))
300
+ if sys.maxsize <= size:
301
+ raise OverflowError("Size {0:n} too large".format(size))
302
+ if os.getpid() != self._lastpid:
303
+ self.__init__() # reinitialize after fork
304
+ with self._lock:
305
+ self._n_mallocs += 1
306
+ # allow pending blocks to be marked available
307
+ self._free_pending_blocks()
308
+ size = self._roundup(max(size, 1), self._alignment)
309
+ (arena, start, stop) = self._malloc(size)
310
+ real_stop = start + size
311
+ if real_stop < stop:
312
+ # if the returned block is larger than necessary, mark
313
+ # the remainder available
314
+ self._add_free_block((arena, real_stop, stop))
315
+ self._allocated_blocks[arena].add((start, real_stop))
316
+ return (arena, start, real_stop)
317
+
318
+ #
319
+ # Class wrapping a block allocated out of a Heap -- can be inherited by child process
320
+ #
321
+
322
+ class BufferWrapper(object):
323
+
324
+ _heap = Heap()
325
+
326
+ def __init__(self, size):
327
+ if size < 0:
328
+ raise ValueError("Size {0:n} out of range".format(size))
329
+ if sys.maxsize <= size:
330
+ raise OverflowError("Size {0:n} too large".format(size))
331
+ block = BufferWrapper._heap.malloc(size)
332
+ self._state = (block, size)
333
+ util.Finalize(self, BufferWrapper._heap.free, args=(block,))
334
+
335
+ def create_memoryview(self):
336
+ (arena, start, stop), size = self._state
337
+ return memoryview(arena.buffer)[start:start+size]
lib/python3.1/multiprocessing/managers.py ADDED
@@ -0,0 +1,1378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module providing manager classes for dealing
3
+ # with shared objects
4
+ #
5
+ # multiprocessing/managers.py
6
+ #
7
+ # Copyright (c) 2006-2008, R Oudkerk
8
+ # Licensed to PSF under a Contributor Agreement.
9
+ #
10
+
11
+ __all__ = [ 'BaseManager', 'SyncManager', 'BaseProxy', 'Token' ]
12
+
13
+ #
14
+ # Imports
15
+ #
16
+
17
+ import sys
18
+ import threading
19
+ import signal
20
+ import array
21
+ import queue
22
+ import time
23
+ import types
24
+ import os
25
+ from os import getpid
26
+
27
+ from traceback import format_exc
28
+
29
+ from . import connection
30
+ from .context import reduction, get_spawning_popen, ProcessError
31
+ from . import pool
32
+ from . import process
33
+ from . import util
34
+ from . import get_context
35
+ try:
36
+ from . import shared_memory
37
+ except ImportError:
38
+ HAS_SHMEM = False
39
+ else:
40
+ HAS_SHMEM = True
41
+ __all__.append('SharedMemoryManager')
42
+
43
+ #
44
+ # Register some things for pickling
45
+ #
46
+
47
+ def reduce_array(a):
48
+ return array.array, (a.typecode, a.tobytes())
49
+ reduction.register(array.array, reduce_array)
50
+
51
+ view_types = [type(getattr({}, name)()) for name in ('items','keys','values')]
52
+ if view_types[0] is not list: # only needed in Py3.0
53
+ def rebuild_as_list(obj):
54
+ return list, (list(obj),)
55
+ for view_type in view_types:
56
+ reduction.register(view_type, rebuild_as_list)
57
+
58
+ #
59
+ # Type for identifying shared objects
60
+ #
61
+
62
+ class Token(object):
63
+ '''
64
+ Type to uniquely identify a shared object
65
+ '''
66
+ __slots__ = ('typeid', 'address', 'id')
67
+
68
+ def __init__(self, typeid, address, id):
69
+ (self.typeid, self.address, self.id) = (typeid, address, id)
70
+
71
+ def __getstate__(self):
72
+ return (self.typeid, self.address, self.id)
73
+
74
+ def __setstate__(self, state):
75
+ (self.typeid, self.address, self.id) = state
76
+
77
+ def __repr__(self):
78
+ return '%s(typeid=%r, address=%r, id=%r)' % \
79
+ (self.__class__.__name__, self.typeid, self.address, self.id)
80
+
81
+ #
82
+ # Function for communication with a manager's server process
83
+ #
84
+
85
+ def dispatch(c, id, methodname, args=(), kwds={}):
86
+ '''
87
+ Send a message to manager using connection `c` and return response
88
+ '''
89
+ c.send((id, methodname, args, kwds))
90
+ kind, result = c.recv()
91
+ if kind == '#RETURN':
92
+ return result
93
+ raise convert_to_error(kind, result)
94
+
95
+ def convert_to_error(kind, result):
96
+ if kind == '#ERROR':
97
+ return result
98
+ elif kind in ('#TRACEBACK', '#UNSERIALIZABLE'):
99
+ if not isinstance(result, str):
100
+ raise TypeError(
101
+ "Result {0!r} (kind '{1}') type is {2}, not str".format(
102
+ result, kind, type(result)))
103
+ if kind == '#UNSERIALIZABLE':
104
+ return RemoteError('Unserializable message: %s\n' % result)
105
+ else:
106
+ return RemoteError(result)
107
+ else:
108
+ return ValueError('Unrecognized message type {!r}'.format(kind))
109
+
110
+ class RemoteError(Exception):
111
+ def __str__(self):
112
+ return ('\n' + '-'*75 + '\n' + str(self.args[0]) + '-'*75)
113
+
114
+ #
115
+ # Functions for finding the method names of an object
116
+ #
117
+
118
+ def all_methods(obj):
119
+ '''
120
+ Return a list of names of methods of `obj`
121
+ '''
122
+ temp = []
123
+ for name in dir(obj):
124
+ func = getattr(obj, name)
125
+ if callable(func):
126
+ temp.append(name)
127
+ return temp
128
+
129
+ def public_methods(obj):
130
+ '''
131
+ Return a list of names of methods of `obj` which do not start with '_'
132
+ '''
133
+ return [name for name in all_methods(obj) if name[0] != '_']
134
+
135
+ #
136
+ # Server which is run in a process controlled by a manager
137
+ #
138
+
139
+ class Server(object):
140
+ '''
141
+ Server class which runs in a process controlled by a manager object
142
+ '''
143
+ public = ['shutdown', 'create', 'accept_connection', 'get_methods',
144
+ 'debug_info', 'number_of_objects', 'dummy', 'incref', 'decref']
145
+
146
+ def __init__(self, registry, address, authkey, serializer):
147
+ if not isinstance(authkey, bytes):
148
+ raise TypeError(
149
+ "Authkey {0!r} is type {1!s}, not bytes".format(
150
+ authkey, type(authkey)))
151
+ self.registry = registry
152
+ self.authkey = process.AuthenticationString(authkey)
153
+ Listener, Client = listener_client[serializer]
154
+
155
+ # do authentication later
156
+ self.listener = Listener(address=address, backlog=16)
157
+ self.address = self.listener.address
158
+
159
+ self.id_to_obj = {'0': (None, ())}
160
+ self.id_to_refcount = {}
161
+ self.id_to_local_proxy_obj = {}
162
+ self.mutex = threading.Lock()
163
+
164
+ def serve_forever(self):
165
+ '''
166
+ Run the server forever
167
+ '''
168
+ self.stop_event = threading.Event()
169
+ process.current_process()._manager_server = self
170
+ try:
171
+ accepter = threading.Thread(target=self.accepter)
172
+ accepter.daemon = True
173
+ accepter.start()
174
+ try:
175
+ while not self.stop_event.is_set():
176
+ self.stop_event.wait(1)
177
+ except (KeyboardInterrupt, SystemExit):
178
+ pass
179
+ finally:
180
+ if sys.stdout != sys.__stdout__: # what about stderr?
181
+ util.debug('resetting stdout, stderr')
182
+ sys.stdout = sys.__stdout__
183
+ sys.stderr = sys.__stderr__
184
+ sys.exit(0)
185
+
186
+ def accepter(self):
187
+ while True:
188
+ try:
189
+ c = self.listener.accept()
190
+ except OSError:
191
+ continue
192
+ t = threading.Thread(target=self.handle_request, args=(c,))
193
+ t.daemon = True
194
+ t.start()
195
+
196
+ def _handle_request(self, c):
197
+ request = None
198
+ try:
199
+ connection.deliver_challenge(c, self.authkey)
200
+ connection.answer_challenge(c, self.authkey)
201
+ request = c.recv()
202
+ ignore, funcname, args, kwds = request
203
+ assert funcname in self.public, '%r unrecognized' % funcname
204
+ func = getattr(self, funcname)
205
+ except Exception:
206
+ msg = ('#TRACEBACK', format_exc())
207
+ else:
208
+ try:
209
+ result = func(c, *args, **kwds)
210
+ except Exception:
211
+ msg = ('#TRACEBACK', format_exc())
212
+ else:
213
+ msg = ('#RETURN', result)
214
+
215
+ try:
216
+ c.send(msg)
217
+ except Exception as e:
218
+ try:
219
+ c.send(('#TRACEBACK', format_exc()))
220
+ except Exception:
221
+ pass
222
+ util.info('Failure to send message: %r', msg)
223
+ util.info(' ... request was %r', request)
224
+ util.info(' ... exception was %r', e)
225
+
226
+ def handle_request(self, conn):
227
+ '''
228
+ Handle a new connection
229
+ '''
230
+ try:
231
+ self._handle_request(conn)
232
+ except SystemExit:
233
+ # Server.serve_client() calls sys.exit(0) on EOF
234
+ pass
235
+ finally:
236
+ conn.close()
237
+
238
+ def serve_client(self, conn):
239
+ '''
240
+ Handle requests from the proxies in a particular process/thread
241
+ '''
242
+ util.debug('starting server thread to service %r',
243
+ threading.current_thread().name)
244
+
245
+ recv = conn.recv
246
+ send = conn.send
247
+ id_to_obj = self.id_to_obj
248
+
249
+ while not self.stop_event.is_set():
250
+
251
+ try:
252
+ methodname = obj = None
253
+ request = recv()
254
+ ident, methodname, args, kwds = request
255
+ try:
256
+ obj, exposed, gettypeid = id_to_obj[ident]
257
+ except KeyError as ke:
258
+ try:
259
+ obj, exposed, gettypeid = \
260
+ self.id_to_local_proxy_obj[ident]
261
+ except KeyError:
262
+ raise ke
263
+
264
+ if methodname not in exposed:
265
+ raise AttributeError(
266
+ 'method %r of %r object is not in exposed=%r' %
267
+ (methodname, type(obj), exposed)
268
+ )
269
+
270
+ function = getattr(obj, methodname)
271
+
272
+ try:
273
+ res = function(*args, **kwds)
274
+ except Exception as e:
275
+ msg = ('#ERROR', e)
276
+ else:
277
+ typeid = gettypeid and gettypeid.get(methodname, None)
278
+ if typeid:
279
+ rident, rexposed = self.create(conn, typeid, res)
280
+ token = Token(typeid, self.address, rident)
281
+ msg = ('#PROXY', (rexposed, token))
282
+ else:
283
+ msg = ('#RETURN', res)
284
+
285
+ except AttributeError:
286
+ if methodname is None:
287
+ msg = ('#TRACEBACK', format_exc())
288
+ else:
289
+ try:
290
+ fallback_func = self.fallback_mapping[methodname]
291
+ result = fallback_func(
292
+ self, conn, ident, obj, *args, **kwds
293
+ )
294
+ msg = ('#RETURN', result)
295
+ except Exception:
296
+ msg = ('#TRACEBACK', format_exc())
297
+
298
+ except EOFError:
299
+ util.debug('got EOF -- exiting thread serving %r',
300
+ threading.current_thread().name)
301
+ sys.exit(0)
302
+
303
+ except Exception:
304
+ msg = ('#TRACEBACK', format_exc())
305
+
306
+ try:
307
+ try:
308
+ send(msg)
309
+ except Exception:
310
+ send(('#UNSERIALIZABLE', format_exc()))
311
+ except Exception as e:
312
+ util.info('exception in thread serving %r',
313
+ threading.current_thread().name)
314
+ util.info(' ... message was %r', msg)
315
+ util.info(' ... exception was %r', e)
316
+ conn.close()
317
+ sys.exit(1)
318
+
319
+ def fallback_getvalue(self, conn, ident, obj):
320
+ return obj
321
+
322
+ def fallback_str(self, conn, ident, obj):
323
+ return str(obj)
324
+
325
+ def fallback_repr(self, conn, ident, obj):
326
+ return repr(obj)
327
+
328
+ fallback_mapping = {
329
+ '__str__':fallback_str,
330
+ '__repr__':fallback_repr,
331
+ '#GETVALUE':fallback_getvalue
332
+ }
333
+
334
+ def dummy(self, c):
335
+ pass
336
+
337
+ def debug_info(self, c):
338
+ '''
339
+ Return some info --- useful to spot problems with refcounting
340
+ '''
341
+ # Perhaps include debug info about 'c'?
342
+ with self.mutex:
343
+ result = []
344
+ keys = list(self.id_to_refcount.keys())
345
+ keys.sort()
346
+ for ident in keys:
347
+ if ident != '0':
348
+ result.append(' %s: refcount=%s\n %s' %
349
+ (ident, self.id_to_refcount[ident],
350
+ str(self.id_to_obj[ident][0])[:75]))
351
+ return '\n'.join(result)
352
+
353
+ def number_of_objects(self, c):
354
+ '''
355
+ Number of shared objects
356
+ '''
357
+ # Doesn't use (len(self.id_to_obj) - 1) as we shouldn't count ident='0'
358
+ return len(self.id_to_refcount)
359
+
360
+ def shutdown(self, c):
361
+ '''
362
+ Shutdown this process
363
+ '''
364
+ try:
365
+ util.debug('manager received shutdown message')
366
+ c.send(('#RETURN', None))
367
+ except:
368
+ import traceback
369
+ traceback.print_exc()
370
+ finally:
371
+ self.stop_event.set()
372
+
373
+ def create(self, c, typeid, /, *args, **kwds):
374
+ '''
375
+ Create a new shared object and return its id
376
+ '''
377
+ with self.mutex:
378
+ callable, exposed, method_to_typeid, proxytype = \
379
+ self.registry[typeid]
380
+
381
+ if callable is None:
382
+ if kwds or (len(args) != 1):
383
+ raise ValueError(
384
+ "Without callable, must have one non-keyword argument")
385
+ obj = args[0]
386
+ else:
387
+ obj = callable(*args, **kwds)
388
+
389
+ if exposed is None:
390
+ exposed = public_methods(obj)
391
+ if method_to_typeid is not None:
392
+ if not isinstance(method_to_typeid, dict):
393
+ raise TypeError(
394
+ "Method_to_typeid {0!r}: type {1!s}, not dict".format(
395
+ method_to_typeid, type(method_to_typeid)))
396
+ exposed = list(exposed) + list(method_to_typeid)
397
+
398
+ ident = '%x' % id(obj) # convert to string because xmlrpclib
399
+ # only has 32 bit signed integers
400
+ util.debug('%r callable returned object with id %r', typeid, ident)
401
+
402
+ self.id_to_obj[ident] = (obj, set(exposed), method_to_typeid)
403
+ if ident not in self.id_to_refcount:
404
+ self.id_to_refcount[ident] = 0
405
+
406
+ self.incref(c, ident)
407
+ return ident, tuple(exposed)
408
+
409
+ def get_methods(self, c, token):
410
+ '''
411
+ Return the methods of the shared object indicated by token
412
+ '''
413
+ return tuple(self.id_to_obj[token.id][1])
414
+
415
+ def accept_connection(self, c, name):
416
+ '''
417
+ Spawn a new thread to serve this connection
418
+ '''
419
+ threading.current_thread().name = name
420
+ c.send(('#RETURN', None))
421
+ self.serve_client(c)
422
+
423
+ def incref(self, c, ident):
424
+ with self.mutex:
425
+ try:
426
+ self.id_to_refcount[ident] += 1
427
+ except KeyError as ke:
428
+ # If no external references exist but an internal (to the
429
+ # manager) still does and a new external reference is created
430
+ # from it, restore the manager's tracking of it from the
431
+ # previously stashed internal ref.
432
+ if ident in self.id_to_local_proxy_obj:
433
+ self.id_to_refcount[ident] = 1
434
+ self.id_to_obj[ident] = \
435
+ self.id_to_local_proxy_obj[ident]
436
+ obj, exposed, gettypeid = self.id_to_obj[ident]
437
+ util.debug('Server re-enabled tracking & INCREF %r', ident)
438
+ else:
439
+ raise ke
440
+
441
+ def decref(self, c, ident):
442
+ if ident not in self.id_to_refcount and \
443
+ ident in self.id_to_local_proxy_obj:
444
+ util.debug('Server DECREF skipping %r', ident)
445
+ return
446
+
447
+ with self.mutex:
448
+ if self.id_to_refcount[ident] <= 0:
449
+ raise AssertionError(
450
+ "Id {0!s} ({1!r}) has refcount {2:n}, not 1+".format(
451
+ ident, self.id_to_obj[ident],
452
+ self.id_to_refcount[ident]))
453
+ self.id_to_refcount[ident] -= 1
454
+ if self.id_to_refcount[ident] == 0:
455
+ del self.id_to_refcount[ident]
456
+
457
+ if ident not in self.id_to_refcount:
458
+ # Two-step process in case the object turns out to contain other
459
+ # proxy objects (e.g. a managed list of managed lists).
460
+ # Otherwise, deleting self.id_to_obj[ident] would trigger the
461
+ # deleting of the stored value (another managed object) which would
462
+ # in turn attempt to acquire the mutex that is already held here.
463
+ self.id_to_obj[ident] = (None, (), None) # thread-safe
464
+ util.debug('disposing of obj with id %r', ident)
465
+ with self.mutex:
466
+ del self.id_to_obj[ident]
467
+
468
+
469
+ #
470
+ # Class to represent state of a manager
471
+ #
472
+
473
+ class State(object):
474
+ __slots__ = ['value']
475
+ INITIAL = 0
476
+ STARTED = 1
477
+ SHUTDOWN = 2
478
+
479
+ #
480
+ # Mapping from serializer name to Listener and Client types
481
+ #
482
+
483
+ listener_client = {
484
+ 'pickle' : (connection.Listener, connection.Client),
485
+ 'xmlrpclib' : (connection.XmlListener, connection.XmlClient)
486
+ }
487
+
488
+ #
489
+ # Definition of BaseManager
490
+ #
491
+
492
+ class BaseManager(object):
493
+ '''
494
+ Base class for managers
495
+ '''
496
+ _registry = {}
497
+ _Server = Server
498
+
499
+ def __init__(self, address=None, authkey=None, serializer='pickle',
500
+ ctx=None):
501
+ if authkey is None:
502
+ authkey = process.current_process().authkey
503
+ self._address = address # XXX not final address if eg ('', 0)
504
+ self._authkey = process.AuthenticationString(authkey)
505
+ self._state = State()
506
+ self._state.value = State.INITIAL
507
+ self._serializer = serializer
508
+ self._Listener, self._Client = listener_client[serializer]
509
+ self._ctx = ctx or get_context()
510
+
511
+ def get_server(self):
512
+ '''
513
+ Return server object with serve_forever() method and address attribute
514
+ '''
515
+ if self._state.value != State.INITIAL:
516
+ if self._state.value == State.STARTED:
517
+ raise ProcessError("Already started server")
518
+ elif self._state.value == State.SHUTDOWN:
519
+ raise ProcessError("Manager has shut down")
520
+ else:
521
+ raise ProcessError(
522
+ "Unknown state {!r}".format(self._state.value))
523
+ return Server(self._registry, self._address,
524
+ self._authkey, self._serializer)
525
+
526
+ def connect(self):
527
+ '''
528
+ Connect manager object to the server process
529
+ '''
530
+ Listener, Client = listener_client[self._serializer]
531
+ conn = Client(self._address, authkey=self._authkey)
532
+ dispatch(conn, None, 'dummy')
533
+ self._state.value = State.STARTED
534
+
535
+ def start(self, initializer=None, initargs=()):
536
+ '''
537
+ Spawn a server process for this manager object
538
+ '''
539
+ if self._state.value != State.INITIAL:
540
+ if self._state.value == State.STARTED:
541
+ raise ProcessError("Already started server")
542
+ elif self._state.value == State.SHUTDOWN:
543
+ raise ProcessError("Manager has shut down")
544
+ else:
545
+ raise ProcessError(
546
+ "Unknown state {!r}".format(self._state.value))
547
+
548
+ if initializer is not None and not callable(initializer):
549
+ raise TypeError('initializer must be a callable')
550
+
551
+ # pipe over which we will retrieve address of server
552
+ reader, writer = connection.Pipe(duplex=False)
553
+
554
+ # spawn process which runs a server
555
+ self._process = self._ctx.Process(
556
+ target=type(self)._run_server,
557
+ args=(self._registry, self._address, self._authkey,
558
+ self._serializer, writer, initializer, initargs),
559
+ )
560
+ ident = ':'.join(str(i) for i in self._process._identity)
561
+ self._process.name = type(self).__name__ + '-' + ident
562
+ self._process.start()
563
+
564
+ # get address of server
565
+ writer.close()
566
+ self._address = reader.recv()
567
+ reader.close()
568
+
569
+ # register a finalizer
570
+ self._state.value = State.STARTED
571
+ self.shutdown = util.Finalize(
572
+ self, type(self)._finalize_manager,
573
+ args=(self._process, self._address, self._authkey,
574
+ self._state, self._Client),
575
+ exitpriority=0
576
+ )
577
+
578
+ @classmethod
579
+ def _run_server(cls, registry, address, authkey, serializer, writer,
580
+ initializer=None, initargs=()):
581
+ '''
582
+ Create a server, report its address and run it
583
+ '''
584
+ # bpo-36368: protect server process from KeyboardInterrupt signals
585
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
586
+
587
+ if initializer is not None:
588
+ initializer(*initargs)
589
+
590
+ # create server
591
+ server = cls._Server(registry, address, authkey, serializer)
592
+
593
+ # inform parent process of the server's address
594
+ writer.send(server.address)
595
+ writer.close()
596
+
597
+ # run the manager
598
+ util.info('manager serving at %r', server.address)
599
+ server.serve_forever()
600
+
601
+ def _create(self, typeid, /, *args, **kwds):
602
+ '''
603
+ Create a new shared object; return the token and exposed tuple
604
+ '''
605
+ assert self._state.value == State.STARTED, 'server not yet started'
606
+ conn = self._Client(self._address, authkey=self._authkey)
607
+ try:
608
+ id, exposed = dispatch(conn, None, 'create', (typeid,)+args, kwds)
609
+ finally:
610
+ conn.close()
611
+ return Token(typeid, self._address, id), exposed
612
+
613
+ def join(self, timeout=None):
614
+ '''
615
+ Join the manager process (if it has been spawned)
616
+ '''
617
+ if self._process is not None:
618
+ self._process.join(timeout)
619
+ if not self._process.is_alive():
620
+ self._process = None
621
+
622
+ def _debug_info(self):
623
+ '''
624
+ Return some info about the servers shared objects and connections
625
+ '''
626
+ conn = self._Client(self._address, authkey=self._authkey)
627
+ try:
628
+ return dispatch(conn, None, 'debug_info')
629
+ finally:
630
+ conn.close()
631
+
632
+ def _number_of_objects(self):
633
+ '''
634
+ Return the number of shared objects
635
+ '''
636
+ conn = self._Client(self._address, authkey=self._authkey)
637
+ try:
638
+ return dispatch(conn, None, 'number_of_objects')
639
+ finally:
640
+ conn.close()
641
+
642
+ def __enter__(self):
643
+ if self._state.value == State.INITIAL:
644
+ self.start()
645
+ if self._state.value != State.STARTED:
646
+ if self._state.value == State.INITIAL:
647
+ raise ProcessError("Unable to start server")
648
+ elif self._state.value == State.SHUTDOWN:
649
+ raise ProcessError("Manager has shut down")
650
+ else:
651
+ raise ProcessError(
652
+ "Unknown state {!r}".format(self._state.value))
653
+ return self
654
+
655
+ def __exit__(self, exc_type, exc_val, exc_tb):
656
+ self.shutdown()
657
+
658
+ @staticmethod
659
+ def _finalize_manager(process, address, authkey, state, _Client):
660
+ '''
661
+ Shutdown the manager process; will be registered as a finalizer
662
+ '''
663
+ if process.is_alive():
664
+ util.info('sending shutdown message to manager')
665
+ try:
666
+ conn = _Client(address, authkey=authkey)
667
+ try:
668
+ dispatch(conn, None, 'shutdown')
669
+ finally:
670
+ conn.close()
671
+ except Exception:
672
+ pass
673
+
674
+ process.join(timeout=1.0)
675
+ if process.is_alive():
676
+ util.info('manager still alive')
677
+ if hasattr(process, 'terminate'):
678
+ util.info('trying to `terminate()` manager process')
679
+ process.terminate()
680
+ process.join(timeout=1.0)
681
+ if process.is_alive():
682
+ util.info('manager still alive after terminate')
683
+
684
+ state.value = State.SHUTDOWN
685
+ try:
686
+ del BaseProxy._address_to_local[address]
687
+ except KeyError:
688
+ pass
689
+
690
+ @property
691
+ def address(self):
692
+ return self._address
693
+
694
+ @classmethod
695
+ def register(cls, typeid, callable=None, proxytype=None, exposed=None,
696
+ method_to_typeid=None, create_method=True):
697
+ '''
698
+ Register a typeid with the manager type
699
+ '''
700
+ if '_registry' not in cls.__dict__:
701
+ cls._registry = cls._registry.copy()
702
+
703
+ if proxytype is None:
704
+ proxytype = AutoProxy
705
+
706
+ exposed = exposed or getattr(proxytype, '_exposed_', None)
707
+
708
+ method_to_typeid = method_to_typeid or \
709
+ getattr(proxytype, '_method_to_typeid_', None)
710
+
711
+ if method_to_typeid:
712
+ for key, value in list(method_to_typeid.items()): # isinstance?
713
+ assert type(key) is str, '%r is not a string' % key
714
+ assert type(value) is str, '%r is not a string' % value
715
+
716
+ cls._registry[typeid] = (
717
+ callable, exposed, method_to_typeid, proxytype
718
+ )
719
+
720
+ if create_method:
721
+ def temp(self, /, *args, **kwds):
722
+ util.debug('requesting creation of a shared %r object', typeid)
723
+ token, exp = self._create(typeid, *args, **kwds)
724
+ proxy = proxytype(
725
+ token, self._serializer, manager=self,
726
+ authkey=self._authkey, exposed=exp
727
+ )
728
+ conn = self._Client(token.address, authkey=self._authkey)
729
+ dispatch(conn, None, 'decref', (token.id,))
730
+ return proxy
731
+ temp.__name__ = typeid
732
+ setattr(cls, typeid, temp)
733
+
734
+ #
735
+ # Subclass of set which get cleared after a fork
736
+ #
737
+
738
+ class ProcessLocalSet(set):
739
+ def __init__(self):
740
+ util.register_after_fork(self, lambda obj: obj.clear())
741
+ def __reduce__(self):
742
+ return type(self), ()
743
+
744
+ #
745
+ # Definition of BaseProxy
746
+ #
747
+
748
+ class BaseProxy(object):
749
+ '''
750
+ A base for proxies of shared objects
751
+ '''
752
+ _address_to_local = {}
753
+ _mutex = util.ForkAwareThreadLock()
754
+
755
+ def __init__(self, token, serializer, manager=None,
756
+ authkey=None, exposed=None, incref=True, manager_owned=False):
757
+ with BaseProxy._mutex:
758
+ tls_idset = BaseProxy._address_to_local.get(token.address, None)
759
+ if tls_idset is None:
760
+ tls_idset = util.ForkAwareLocal(), ProcessLocalSet()
761
+ BaseProxy._address_to_local[token.address] = tls_idset
762
+
763
+ # self._tls is used to record the connection used by this
764
+ # thread to communicate with the manager at token.address
765
+ self._tls = tls_idset[0]
766
+
767
+ # self._idset is used to record the identities of all shared
768
+ # objects for which the current process owns references and
769
+ # which are in the manager at token.address
770
+ self._idset = tls_idset[1]
771
+
772
+ self._token = token
773
+ self._id = self._token.id
774
+ self._manager = manager
775
+ self._serializer = serializer
776
+ self._Client = listener_client[serializer][1]
777
+
778
+ # Should be set to True only when a proxy object is being created
779
+ # on the manager server; primary use case: nested proxy objects.
780
+ # RebuildProxy detects when a proxy is being created on the manager
781
+ # and sets this value appropriately.
782
+ self._owned_by_manager = manager_owned
783
+
784
+ if authkey is not None:
785
+ self._authkey = process.AuthenticationString(authkey)
786
+ elif self._manager is not None:
787
+ self._authkey = self._manager._authkey
788
+ else:
789
+ self._authkey = process.current_process().authkey
790
+
791
+ if incref:
792
+ self._incref()
793
+
794
+ util.register_after_fork(self, BaseProxy._after_fork)
795
+
796
+ def _connect(self):
797
+ util.debug('making connection to manager')
798
+ name = process.current_process().name
799
+ if threading.current_thread().name != 'MainThread':
800
+ name += '|' + threading.current_thread().name
801
+ conn = self._Client(self._token.address, authkey=self._authkey)
802
+ dispatch(conn, None, 'accept_connection', (name,))
803
+ self._tls.connection = conn
804
+
805
+ def _callmethod(self, methodname, args=(), kwds={}):
806
+ '''
807
+ Try to call a method of the referent and return a copy of the result
808
+ '''
809
+ try:
810
+ conn = self._tls.connection
811
+ except AttributeError:
812
+ util.debug('thread %r does not own a connection',
813
+ threading.current_thread().name)
814
+ self._connect()
815
+ conn = self._tls.connection
816
+
817
+ conn.send((self._id, methodname, args, kwds))
818
+ kind, result = conn.recv()
819
+
820
+ if kind == '#RETURN':
821
+ return result
822
+ elif kind == '#PROXY':
823
+ exposed, token = result
824
+ proxytype = self._manager._registry[token.typeid][-1]
825
+ token.address = self._token.address
826
+ proxy = proxytype(
827
+ token, self._serializer, manager=self._manager,
828
+ authkey=self._authkey, exposed=exposed
829
+ )
830
+ conn = self._Client(token.address, authkey=self._authkey)
831
+ dispatch(conn, None, 'decref', (token.id,))
832
+ return proxy
833
+ raise convert_to_error(kind, result)
834
+
835
+ def _getvalue(self):
836
+ '''
837
+ Get a copy of the value of the referent
838
+ '''
839
+ return self._callmethod('#GETVALUE')
840
+
841
+ def _incref(self):
842
+ if self._owned_by_manager:
843
+ util.debug('owned_by_manager skipped INCREF of %r', self._token.id)
844
+ return
845
+
846
+ conn = self._Client(self._token.address, authkey=self._authkey)
847
+ dispatch(conn, None, 'incref', (self._id,))
848
+ util.debug('INCREF %r', self._token.id)
849
+
850
+ self._idset.add(self._id)
851
+
852
+ state = self._manager and self._manager._state
853
+
854
+ self._close = util.Finalize(
855
+ self, BaseProxy._decref,
856
+ args=(self._token, self._authkey, state,
857
+ self._tls, self._idset, self._Client),
858
+ exitpriority=10
859
+ )
860
+
861
+ @staticmethod
862
+ def _decref(token, authkey, state, tls, idset, _Client):
863
+ idset.discard(token.id)
864
+
865
+ # check whether manager is still alive
866
+ if state is None or state.value == State.STARTED:
867
+ # tell manager this process no longer cares about referent
868
+ try:
869
+ util.debug('DECREF %r', token.id)
870
+ conn = _Client(token.address, authkey=authkey)
871
+ dispatch(conn, None, 'decref', (token.id,))
872
+ except Exception as e:
873
+ util.debug('... decref failed %s', e)
874
+
875
+ else:
876
+ util.debug('DECREF %r -- manager already shutdown', token.id)
877
+
878
+ # check whether we can close this thread's connection because
879
+ # the process owns no more references to objects for this manager
880
+ if not idset and hasattr(tls, 'connection'):
881
+ util.debug('thread %r has no more proxies so closing conn',
882
+ threading.current_thread().name)
883
+ tls.connection.close()
884
+ del tls.connection
885
+
886
+ def _after_fork(self):
887
+ self._manager = None
888
+ try:
889
+ self._incref()
890
+ except Exception as e:
891
+ # the proxy may just be for a manager which has shutdown
892
+ util.info('incref failed: %s' % e)
893
+
894
+ def __reduce__(self):
895
+ kwds = {}
896
+ if get_spawning_popen() is not None:
897
+ kwds['authkey'] = self._authkey
898
+
899
+ if getattr(self, '_isauto', False):
900
+ kwds['exposed'] = self._exposed_
901
+ return (RebuildProxy,
902
+ (AutoProxy, self._token, self._serializer, kwds))
903
+ else:
904
+ return (RebuildProxy,
905
+ (type(self), self._token, self._serializer, kwds))
906
+
907
+ def __deepcopy__(self, memo):
908
+ return self._getvalue()
909
+
910
+ def __repr__(self):
911
+ return '<%s object, typeid %r at %#x>' % \
912
+ (type(self).__name__, self._token.typeid, id(self))
913
+
914
+ def __str__(self):
915
+ '''
916
+ Return representation of the referent (or a fall-back if that fails)
917
+ '''
918
+ try:
919
+ return self._callmethod('__repr__')
920
+ except Exception:
921
+ return repr(self)[:-1] + "; '__str__()' failed>"
922
+
923
+ #
924
+ # Function used for unpickling
925
+ #
926
+
927
+ def RebuildProxy(func, token, serializer, kwds):
928
+ '''
929
+ Function used for unpickling proxy objects.
930
+ '''
931
+ server = getattr(process.current_process(), '_manager_server', None)
932
+ if server and server.address == token.address:
933
+ util.debug('Rebuild a proxy owned by manager, token=%r', token)
934
+ kwds['manager_owned'] = True
935
+ if token.id not in server.id_to_local_proxy_obj:
936
+ server.id_to_local_proxy_obj[token.id] = \
937
+ server.id_to_obj[token.id]
938
+ incref = (
939
+ kwds.pop('incref', True) and
940
+ not getattr(process.current_process(), '_inheriting', False)
941
+ )
942
+ return func(token, serializer, incref=incref, **kwds)
943
+
944
+ #
945
+ # Functions to create proxies and proxy types
946
+ #
947
+
948
+ def MakeProxyType(name, exposed, _cache={}):
949
+ '''
950
+ Return a proxy type whose methods are given by `exposed`
951
+ '''
952
+ exposed = tuple(exposed)
953
+ try:
954
+ return _cache[(name, exposed)]
955
+ except KeyError:
956
+ pass
957
+
958
+ dic = {}
959
+
960
+ for meth in exposed:
961
+ exec('''def %s(self, /, *args, **kwds):
962
+ return self._callmethod(%r, args, kwds)''' % (meth, meth), dic)
963
+
964
+ ProxyType = type(name, (BaseProxy,), dic)
965
+ ProxyType._exposed_ = exposed
966
+ _cache[(name, exposed)] = ProxyType
967
+ return ProxyType
968
+
969
+
970
+ def AutoProxy(token, serializer, manager=None, authkey=None,
971
+ exposed=None, incref=True, manager_owned=False):
972
+ '''
973
+ Return an auto-proxy for `token`
974
+ '''
975
+ _Client = listener_client[serializer][1]
976
+
977
+ if exposed is None:
978
+ conn = _Client(token.address, authkey=authkey)
979
+ try:
980
+ exposed = dispatch(conn, None, 'get_methods', (token,))
981
+ finally:
982
+ conn.close()
983
+
984
+ if authkey is None and manager is not None:
985
+ authkey = manager._authkey
986
+ if authkey is None:
987
+ authkey = process.current_process().authkey
988
+
989
+ ProxyType = MakeProxyType('AutoProxy[%s]' % token.typeid, exposed)
990
+ proxy = ProxyType(token, serializer, manager=manager, authkey=authkey,
991
+ incref=incref, manager_owned=manager_owned)
992
+ proxy._isauto = True
993
+ return proxy
994
+
995
+ #
996
+ # Types/callables which we will register with SyncManager
997
+ #
998
+
999
+ class Namespace(object):
1000
+ def __init__(self, /, **kwds):
1001
+ self.__dict__.update(kwds)
1002
+ def __repr__(self):
1003
+ items = list(self.__dict__.items())
1004
+ temp = []
1005
+ for name, value in items:
1006
+ if not name.startswith('_'):
1007
+ temp.append('%s=%r' % (name, value))
1008
+ temp.sort()
1009
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(temp))
1010
+
1011
+ class Value(object):
1012
+ def __init__(self, typecode, value, lock=True):
1013
+ self._typecode = typecode
1014
+ self._value = value
1015
+ def get(self):
1016
+ return self._value
1017
+ def set(self, value):
1018
+ self._value = value
1019
+ def __repr__(self):
1020
+ return '%s(%r, %r)'%(type(self).__name__, self._typecode, self._value)
1021
+ value = property(get, set)
1022
+
1023
+ def Array(typecode, sequence, lock=True):
1024
+ return array.array(typecode, sequence)
1025
+
1026
+ #
1027
+ # Proxy types used by SyncManager
1028
+ #
1029
+
1030
+ class IteratorProxy(BaseProxy):
1031
+ _exposed_ = ('__next__', 'send', 'throw', 'close')
1032
+ def __iter__(self):
1033
+ return self
1034
+ def __next__(self, *args):
1035
+ return self._callmethod('__next__', args)
1036
+ def send(self, *args):
1037
+ return self._callmethod('send', args)
1038
+ def throw(self, *args):
1039
+ return self._callmethod('throw', args)
1040
+ def close(self, *args):
1041
+ return self._callmethod('close', args)
1042
+
1043
+
1044
+ class AcquirerProxy(BaseProxy):
1045
+ _exposed_ = ('acquire', 'release')
1046
+ def acquire(self, blocking=True, timeout=None):
1047
+ args = (blocking,) if timeout is None else (blocking, timeout)
1048
+ return self._callmethod('acquire', args)
1049
+ def release(self):
1050
+ return self._callmethod('release')
1051
+ def __enter__(self):
1052
+ return self._callmethod('acquire')
1053
+ def __exit__(self, exc_type, exc_val, exc_tb):
1054
+ return self._callmethod('release')
1055
+
1056
+
1057
+ class ConditionProxy(AcquirerProxy):
1058
+ _exposed_ = ('acquire', 'release', 'wait', 'notify', 'notify_all')
1059
+ def wait(self, timeout=None):
1060
+ return self._callmethod('wait', (timeout,))
1061
+ def notify(self, n=1):
1062
+ return self._callmethod('notify', (n,))
1063
+ def notify_all(self):
1064
+ return self._callmethod('notify_all')
1065
+ def wait_for(self, predicate, timeout=None):
1066
+ result = predicate()
1067
+ if result:
1068
+ return result
1069
+ if timeout is not None:
1070
+ endtime = time.monotonic() + timeout
1071
+ else:
1072
+ endtime = None
1073
+ waittime = None
1074
+ while not result:
1075
+ if endtime is not None:
1076
+ waittime = endtime - time.monotonic()
1077
+ if waittime <= 0:
1078
+ break
1079
+ self.wait(waittime)
1080
+ result = predicate()
1081
+ return result
1082
+
1083
+
1084
+ class EventProxy(BaseProxy):
1085
+ _exposed_ = ('is_set', 'set', 'clear', 'wait')
1086
+ def is_set(self):
1087
+ return self._callmethod('is_set')
1088
+ def set(self):
1089
+ return self._callmethod('set')
1090
+ def clear(self):
1091
+ return self._callmethod('clear')
1092
+ def wait(self, timeout=None):
1093
+ return self._callmethod('wait', (timeout,))
1094
+
1095
+
1096
+ class BarrierProxy(BaseProxy):
1097
+ _exposed_ = ('__getattribute__', 'wait', 'abort', 'reset')
1098
+ def wait(self, timeout=None):
1099
+ return self._callmethod('wait', (timeout,))
1100
+ def abort(self):
1101
+ return self._callmethod('abort')
1102
+ def reset(self):
1103
+ return self._callmethod('reset')
1104
+ @property
1105
+ def parties(self):
1106
+ return self._callmethod('__getattribute__', ('parties',))
1107
+ @property
1108
+ def n_waiting(self):
1109
+ return self._callmethod('__getattribute__', ('n_waiting',))
1110
+ @property
1111
+ def broken(self):
1112
+ return self._callmethod('__getattribute__', ('broken',))
1113
+
1114
+
1115
+ class NamespaceProxy(BaseProxy):
1116
+ _exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
1117
+ def __getattr__(self, key):
1118
+ if key[0] == '_':
1119
+ return object.__getattribute__(self, key)
1120
+ callmethod = object.__getattribute__(self, '_callmethod')
1121
+ return callmethod('__getattribute__', (key,))
1122
+ def __setattr__(self, key, value):
1123
+ if key[0] == '_':
1124
+ return object.__setattr__(self, key, value)
1125
+ callmethod = object.__getattribute__(self, '_callmethod')
1126
+ return callmethod('__setattr__', (key, value))
1127
+ def __delattr__(self, key):
1128
+ if key[0] == '_':
1129
+ return object.__delattr__(self, key)
1130
+ callmethod = object.__getattribute__(self, '_callmethod')
1131
+ return callmethod('__delattr__', (key,))
1132
+
1133
+
1134
+ class ValueProxy(BaseProxy):
1135
+ _exposed_ = ('get', 'set')
1136
+ def get(self):
1137
+ return self._callmethod('get')
1138
+ def set(self, value):
1139
+ return self._callmethod('set', (value,))
1140
+ value = property(get, set)
1141
+
1142
+ __class_getitem__ = classmethod(types.GenericAlias)
1143
+
1144
+
1145
+ BaseListProxy = MakeProxyType('BaseListProxy', (
1146
+ '__add__', '__contains__', '__delitem__', '__getitem__', '__len__',
1147
+ '__mul__', '__reversed__', '__rmul__', '__setitem__',
1148
+ 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove',
1149
+ 'reverse', 'sort', '__imul__'
1150
+ ))
1151
+ class ListProxy(BaseListProxy):
1152
+ def __iadd__(self, value):
1153
+ self._callmethod('extend', (value,))
1154
+ return self
1155
+ def __imul__(self, value):
1156
+ self._callmethod('__imul__', (value,))
1157
+ return self
1158
+
1159
+
1160
+ DictProxy = MakeProxyType('DictProxy', (
1161
+ '__contains__', '__delitem__', '__getitem__', '__iter__', '__len__',
1162
+ '__setitem__', 'clear', 'copy', 'get', 'items',
1163
+ 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
1164
+ ))
1165
+ DictProxy._method_to_typeid_ = {
1166
+ '__iter__': 'Iterator',
1167
+ }
1168
+
1169
+
1170
+ ArrayProxy = MakeProxyType('ArrayProxy', (
1171
+ '__len__', '__getitem__', '__setitem__'
1172
+ ))
1173
+
1174
+
1175
+ BasePoolProxy = MakeProxyType('PoolProxy', (
1176
+ 'apply', 'apply_async', 'close', 'imap', 'imap_unordered', 'join',
1177
+ 'map', 'map_async', 'starmap', 'starmap_async', 'terminate',
1178
+ ))
1179
+ BasePoolProxy._method_to_typeid_ = {
1180
+ 'apply_async': 'AsyncResult',
1181
+ 'map_async': 'AsyncResult',
1182
+ 'starmap_async': 'AsyncResult',
1183
+ 'imap': 'Iterator',
1184
+ 'imap_unordered': 'Iterator'
1185
+ }
1186
+ class PoolProxy(BasePoolProxy):
1187
+ def __enter__(self):
1188
+ return self
1189
+ def __exit__(self, exc_type, exc_val, exc_tb):
1190
+ self.terminate()
1191
+
1192
+ #
1193
+ # Definition of SyncManager
1194
+ #
1195
+
1196
+ class SyncManager(BaseManager):
1197
+ '''
1198
+ Subclass of `BaseManager` which supports a number of shared object types.
1199
+
1200
+ The types registered are those intended for the synchronization
1201
+ of threads, plus `dict`, `list` and `Namespace`.
1202
+
1203
+ The `multiprocessing.Manager()` function creates started instances of
1204
+ this class.
1205
+ '''
1206
+
1207
+ SyncManager.register('Queue', queue.Queue)
1208
+ SyncManager.register('JoinableQueue', queue.Queue)
1209
+ SyncManager.register('Event', threading.Event, EventProxy)
1210
+ SyncManager.register('Lock', threading.Lock, AcquirerProxy)
1211
+ SyncManager.register('RLock', threading.RLock, AcquirerProxy)
1212
+ SyncManager.register('Semaphore', threading.Semaphore, AcquirerProxy)
1213
+ SyncManager.register('BoundedSemaphore', threading.BoundedSemaphore,
1214
+ AcquirerProxy)
1215
+ SyncManager.register('Condition', threading.Condition, ConditionProxy)
1216
+ SyncManager.register('Barrier', threading.Barrier, BarrierProxy)
1217
+ SyncManager.register('Pool', pool.Pool, PoolProxy)
1218
+ SyncManager.register('list', list, ListProxy)
1219
+ SyncManager.register('dict', dict, DictProxy)
1220
+ SyncManager.register('Value', Value, ValueProxy)
1221
+ SyncManager.register('Array', Array, ArrayProxy)
1222
+ SyncManager.register('Namespace', Namespace, NamespaceProxy)
1223
+
1224
+ # types returned by methods of PoolProxy
1225
+ SyncManager.register('Iterator', proxytype=IteratorProxy, create_method=False)
1226
+ SyncManager.register('AsyncResult', create_method=False)
1227
+
1228
+ #
1229
+ # Definition of SharedMemoryManager and SharedMemoryServer
1230
+ #
1231
+
1232
+ if HAS_SHMEM:
1233
+ class _SharedMemoryTracker:
1234
+ "Manages one or more shared memory segments."
1235
+
1236
+ def __init__(self, name, segment_names=[]):
1237
+ self.shared_memory_context_name = name
1238
+ self.segment_names = segment_names
1239
+
1240
+ def register_segment(self, segment_name):
1241
+ "Adds the supplied shared memory block name to tracker."
1242
+ util.debug(f"Register segment {segment_name!r} in pid {getpid()}")
1243
+ self.segment_names.append(segment_name)
1244
+
1245
+ def destroy_segment(self, segment_name):
1246
+ """Calls unlink() on the shared memory block with the supplied name
1247
+ and removes it from the list of blocks being tracked."""
1248
+ util.debug(f"Destroy segment {segment_name!r} in pid {getpid()}")
1249
+ self.segment_names.remove(segment_name)
1250
+ segment = shared_memory.SharedMemory(segment_name)
1251
+ segment.close()
1252
+ segment.unlink()
1253
+
1254
+ def unlink(self):
1255
+ "Calls destroy_segment() on all tracked shared memory blocks."
1256
+ for segment_name in self.segment_names[:]:
1257
+ self.destroy_segment(segment_name)
1258
+
1259
+ def __del__(self):
1260
+ util.debug(f"Call {self.__class__.__name__}.__del__ in {getpid()}")
1261
+ self.unlink()
1262
+
1263
+ def __getstate__(self):
1264
+ return (self.shared_memory_context_name, self.segment_names)
1265
+
1266
+ def __setstate__(self, state):
1267
+ self.__init__(*state)
1268
+
1269
+
1270
+ class SharedMemoryServer(Server):
1271
+
1272
+ public = Server.public + \
1273
+ ['track_segment', 'release_segment', 'list_segments']
1274
+
1275
+ def __init__(self, *args, **kwargs):
1276
+ Server.__init__(self, *args, **kwargs)
1277
+ address = self.address
1278
+ # The address of Linux abstract namespaces can be bytes
1279
+ if isinstance(address, bytes):
1280
+ address = os.fsdecode(address)
1281
+ self.shared_memory_context = \
1282
+ _SharedMemoryTracker(f"shm_{address}_{getpid()}")
1283
+ util.debug(f"SharedMemoryServer started by pid {getpid()}")
1284
+
1285
+ def create(self, c, typeid, /, *args, **kwargs):
1286
+ """Create a new distributed-shared object (not backed by a shared
1287
+ memory block) and return its id to be used in a Proxy Object."""
1288
+ # Unless set up as a shared proxy, don't make shared_memory_context
1289
+ # a standard part of kwargs. This makes things easier for supplying
1290
+ # simple functions.
1291
+ if hasattr(self.registry[typeid][-1], "_shared_memory_proxy"):
1292
+ kwargs['shared_memory_context'] = self.shared_memory_context
1293
+ return Server.create(self, c, typeid, *args, **kwargs)
1294
+
1295
+ def shutdown(self, c):
1296
+ "Call unlink() on all tracked shared memory, terminate the Server."
1297
+ self.shared_memory_context.unlink()
1298
+ return Server.shutdown(self, c)
1299
+
1300
+ def track_segment(self, c, segment_name):
1301
+ "Adds the supplied shared memory block name to Server's tracker."
1302
+ self.shared_memory_context.register_segment(segment_name)
1303
+
1304
+ def release_segment(self, c, segment_name):
1305
+ """Calls unlink() on the shared memory block with the supplied name
1306
+ and removes it from the tracker instance inside the Server."""
1307
+ self.shared_memory_context.destroy_segment(segment_name)
1308
+
1309
+ def list_segments(self, c):
1310
+ """Returns a list of names of shared memory blocks that the Server
1311
+ is currently tracking."""
1312
+ return self.shared_memory_context.segment_names
1313
+
1314
+
1315
+ class SharedMemoryManager(BaseManager):
1316
+ """Like SyncManager but uses SharedMemoryServer instead of Server.
1317
+
1318
+ It provides methods for creating and returning SharedMemory instances
1319
+ and for creating a list-like object (ShareableList) backed by shared
1320
+ memory. It also provides methods that create and return Proxy Objects
1321
+ that support synchronization across processes (i.e. multi-process-safe
1322
+ locks and semaphores).
1323
+ """
1324
+
1325
+ _Server = SharedMemoryServer
1326
+
1327
+ def __init__(self, *args, **kwargs):
1328
+ if os.name == "posix":
1329
+ # bpo-36867: Ensure the resource_tracker is running before
1330
+ # launching the manager process, so that concurrent
1331
+ # shared_memory manipulation both in the manager and in the
1332
+ # current process does not create two resource_tracker
1333
+ # processes.
1334
+ from . import resource_tracker
1335
+ resource_tracker.ensure_running()
1336
+ BaseManager.__init__(self, *args, **kwargs)
1337
+ util.debug(f"{self.__class__.__name__} created by pid {getpid()}")
1338
+
1339
+ def __del__(self):
1340
+ util.debug(f"{self.__class__.__name__}.__del__ by pid {getpid()}")
1341
+ pass
1342
+
1343
+ def get_server(self):
1344
+ 'Better than monkeypatching for now; merge into Server ultimately'
1345
+ if self._state.value != State.INITIAL:
1346
+ if self._state.value == State.STARTED:
1347
+ raise ProcessError("Already started SharedMemoryServer")
1348
+ elif self._state.value == State.SHUTDOWN:
1349
+ raise ProcessError("SharedMemoryManager has shut down")
1350
+ else:
1351
+ raise ProcessError(
1352
+ "Unknown state {!r}".format(self._state.value))
1353
+ return self._Server(self._registry, self._address,
1354
+ self._authkey, self._serializer)
1355
+
1356
+ def SharedMemory(self, size):
1357
+ """Returns a new SharedMemory instance with the specified size in
1358
+ bytes, to be tracked by the manager."""
1359
+ with self._Client(self._address, authkey=self._authkey) as conn:
1360
+ sms = shared_memory.SharedMemory(None, create=True, size=size)
1361
+ try:
1362
+ dispatch(conn, None, 'track_segment', (sms.name,))
1363
+ except BaseException as e:
1364
+ sms.unlink()
1365
+ raise e
1366
+ return sms
1367
+
1368
+ def ShareableList(self, sequence):
1369
+ """Returns a new ShareableList instance populated with the values
1370
+ from the input sequence, to be tracked by the manager."""
1371
+ with self._Client(self._address, authkey=self._authkey) as conn:
1372
+ sl = shared_memory.ShareableList(sequence)
1373
+ try:
1374
+ dispatch(conn, None, 'track_segment', (sl.shm.name,))
1375
+ except BaseException as e:
1376
+ sl.shm.unlink()
1377
+ raise e
1378
+ return sl
lib/python3.1/multiprocessing/pool.py ADDED
@@ -0,0 +1,957 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module providing the `Pool` class for managing a process pool
3
+ #
4
+ # multiprocessing/pool.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = ['Pool', 'ThreadPool']
11
+
12
+ #
13
+ # Imports
14
+ #
15
+
16
+ import collections
17
+ import itertools
18
+ import os
19
+ import queue
20
+ import threading
21
+ import time
22
+ import traceback
23
+ import types
24
+ import warnings
25
+
26
+ # If threading is available then ThreadPool should be provided. Therefore
27
+ # we avoid top-level imports which are liable to fail on some systems.
28
+ from . import util
29
+ from . import get_context, TimeoutError
30
+ from .connection import wait
31
+
32
+ #
33
+ # Constants representing the state of a pool
34
+ #
35
+
36
+ INIT = "INIT"
37
+ RUN = "RUN"
38
+ CLOSE = "CLOSE"
39
+ TERMINATE = "TERMINATE"
40
+
41
+ #
42
+ # Miscellaneous
43
+ #
44
+
45
+ job_counter = itertools.count()
46
+
47
+ def mapstar(args):
48
+ return list(map(*args))
49
+
50
+ def starmapstar(args):
51
+ return list(itertools.starmap(args[0], args[1]))
52
+
53
+ #
54
+ # Hack to embed stringification of remote traceback in local traceback
55
+ #
56
+
57
+ class RemoteTraceback(Exception):
58
+ def __init__(self, tb):
59
+ self.tb = tb
60
+ def __str__(self):
61
+ return self.tb
62
+
63
+ class ExceptionWithTraceback:
64
+ def __init__(self, exc, tb):
65
+ tb = traceback.format_exception(type(exc), exc, tb)
66
+ tb = ''.join(tb)
67
+ self.exc = exc
68
+ self.tb = '\n"""\n%s"""' % tb
69
+ def __reduce__(self):
70
+ return rebuild_exc, (self.exc, self.tb)
71
+
72
+ def rebuild_exc(exc, tb):
73
+ exc.__cause__ = RemoteTraceback(tb)
74
+ return exc
75
+
76
+ #
77
+ # Code run by worker processes
78
+ #
79
+
80
+ class MaybeEncodingError(Exception):
81
+ """Wraps possible unpickleable errors, so they can be
82
+ safely sent through the socket."""
83
+
84
+ def __init__(self, exc, value):
85
+ self.exc = repr(exc)
86
+ self.value = repr(value)
87
+ super(MaybeEncodingError, self).__init__(self.exc, self.value)
88
+
89
+ def __str__(self):
90
+ return "Error sending result: '%s'. Reason: '%s'" % (self.value,
91
+ self.exc)
92
+
93
+ def __repr__(self):
94
+ return "<%s: %s>" % (self.__class__.__name__, self)
95
+
96
+
97
+ def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None,
98
+ wrap_exception=False):
99
+ if (maxtasks is not None) and not (isinstance(maxtasks, int)
100
+ and maxtasks >= 1):
101
+ raise AssertionError("Maxtasks {!r} is not valid".format(maxtasks))
102
+ put = outqueue.put
103
+ get = inqueue.get
104
+ if hasattr(inqueue, '_writer'):
105
+ inqueue._writer.close()
106
+ outqueue._reader.close()
107
+
108
+ if initializer is not None:
109
+ initializer(*initargs)
110
+
111
+ completed = 0
112
+ while maxtasks is None or (maxtasks and completed < maxtasks):
113
+ try:
114
+ task = get()
115
+ except (EOFError, OSError):
116
+ util.debug('worker got EOFError or OSError -- exiting')
117
+ break
118
+
119
+ if task is None:
120
+ util.debug('worker got sentinel -- exiting')
121
+ break
122
+
123
+ job, i, func, args, kwds = task
124
+ try:
125
+ result = (True, func(*args, **kwds))
126
+ except Exception as e:
127
+ if wrap_exception and func is not _helper_reraises_exception:
128
+ e = ExceptionWithTraceback(e, e.__traceback__)
129
+ result = (False, e)
130
+ try:
131
+ put((job, i, result))
132
+ except Exception as e:
133
+ wrapped = MaybeEncodingError(e, result[1])
134
+ util.debug("Possible encoding error while sending result: %s" % (
135
+ wrapped))
136
+ put((job, i, (False, wrapped)))
137
+
138
+ task = job = result = func = args = kwds = None
139
+ completed += 1
140
+ util.debug('worker exiting after %d tasks' % completed)
141
+
142
+ def _helper_reraises_exception(ex):
143
+ 'Pickle-able helper function for use by _guarded_task_generation.'
144
+ raise ex
145
+
146
+ #
147
+ # Class representing a process pool
148
+ #
149
+
150
+ class _PoolCache(dict):
151
+ """
152
+ Class that implements a cache for the Pool class that will notify
153
+ the pool management threads every time the cache is emptied. The
154
+ notification is done by the use of a queue that is provided when
155
+ instantiating the cache.
156
+ """
157
+ def __init__(self, /, *args, notifier=None, **kwds):
158
+ self.notifier = notifier
159
+ super().__init__(*args, **kwds)
160
+
161
+ def __delitem__(self, item):
162
+ super().__delitem__(item)
163
+
164
+ # Notify that the cache is empty. This is important because the
165
+ # pool keeps maintaining workers until the cache gets drained. This
166
+ # eliminates a race condition in which a task is finished after the
167
+ # the pool's _handle_workers method has enter another iteration of the
168
+ # loop. In this situation, the only event that can wake up the pool
169
+ # is the cache to be emptied (no more tasks available).
170
+ if not self:
171
+ self.notifier.put(None)
172
+
173
+ class Pool(object):
174
+ '''
175
+ Class which supports an async version of applying functions to arguments.
176
+ '''
177
+ _wrap_exception = True
178
+
179
+ @staticmethod
180
+ def Process(ctx, *args, **kwds):
181
+ return ctx.Process(*args, **kwds)
182
+
183
+ def __init__(self, processes=None, initializer=None, initargs=(),
184
+ maxtasksperchild=None, context=None):
185
+ # Attributes initialized early to make sure that they exist in
186
+ # __del__() if __init__() raises an exception
187
+ self._pool = []
188
+ self._state = INIT
189
+
190
+ self._ctx = context or get_context()
191
+ self._setup_queues()
192
+ self._taskqueue = queue.SimpleQueue()
193
+ # The _change_notifier queue exist to wake up self._handle_workers()
194
+ # when the cache (self._cache) is empty or when there is a change in
195
+ # the _state variable of the thread that runs _handle_workers.
196
+ self._change_notifier = self._ctx.SimpleQueue()
197
+ self._cache = _PoolCache(notifier=self._change_notifier)
198
+ self._maxtasksperchild = maxtasksperchild
199
+ self._initializer = initializer
200
+ self._initargs = initargs
201
+
202
+ if processes is None:
203
+ processes = os.cpu_count() or 1
204
+ if processes < 1:
205
+ raise ValueError("Number of processes must be at least 1")
206
+ if maxtasksperchild is not None:
207
+ if not isinstance(maxtasksperchild, int) or maxtasksperchild <= 0:
208
+ raise ValueError("maxtasksperchild must be a positive int or None")
209
+
210
+ if initializer is not None and not callable(initializer):
211
+ raise TypeError('initializer must be a callable')
212
+
213
+ self._processes = processes
214
+ try:
215
+ self._repopulate_pool()
216
+ except Exception:
217
+ for p in self._pool:
218
+ if p.exitcode is None:
219
+ p.terminate()
220
+ for p in self._pool:
221
+ p.join()
222
+ raise
223
+
224
+ sentinels = self._get_sentinels()
225
+
226
+ self._worker_handler = threading.Thread(
227
+ target=Pool._handle_workers,
228
+ args=(self._cache, self._taskqueue, self._ctx, self.Process,
229
+ self._processes, self._pool, self._inqueue, self._outqueue,
230
+ self._initializer, self._initargs, self._maxtasksperchild,
231
+ self._wrap_exception, sentinels, self._change_notifier)
232
+ )
233
+ self._worker_handler.daemon = True
234
+ self._worker_handler._state = RUN
235
+ self._worker_handler.start()
236
+
237
+
238
+ self._task_handler = threading.Thread(
239
+ target=Pool._handle_tasks,
240
+ args=(self._taskqueue, self._quick_put, self._outqueue,
241
+ self._pool, self._cache)
242
+ )
243
+ self._task_handler.daemon = True
244
+ self._task_handler._state = RUN
245
+ self._task_handler.start()
246
+
247
+ self._result_handler = threading.Thread(
248
+ target=Pool._handle_results,
249
+ args=(self._outqueue, self._quick_get, self._cache)
250
+ )
251
+ self._result_handler.daemon = True
252
+ self._result_handler._state = RUN
253
+ self._result_handler.start()
254
+
255
+ self._terminate = util.Finalize(
256
+ self, self._terminate_pool,
257
+ args=(self._taskqueue, self._inqueue, self._outqueue, self._pool,
258
+ self._change_notifier, self._worker_handler, self._task_handler,
259
+ self._result_handler, self._cache),
260
+ exitpriority=15
261
+ )
262
+ self._state = RUN
263
+
264
+ # Copy globals as function locals to make sure that they are available
265
+ # during Python shutdown when the Pool is destroyed.
266
+ def __del__(self, _warn=warnings.warn, RUN=RUN):
267
+ if self._state == RUN:
268
+ _warn(f"unclosed running multiprocessing pool {self!r}",
269
+ ResourceWarning, source=self)
270
+ if getattr(self, '_change_notifier', None) is not None:
271
+ self._change_notifier.put(None)
272
+
273
+ def __repr__(self):
274
+ cls = self.__class__
275
+ return (f'<{cls.__module__}.{cls.__qualname__} '
276
+ f'state={self._state} '
277
+ f'pool_size={len(self._pool)}>')
278
+
279
+ def _get_sentinels(self):
280
+ task_queue_sentinels = [self._outqueue._reader]
281
+ self_notifier_sentinels = [self._change_notifier._reader]
282
+ return [*task_queue_sentinels, *self_notifier_sentinels]
283
+
284
+ @staticmethod
285
+ def _get_worker_sentinels(workers):
286
+ return [worker.sentinel for worker in
287
+ workers if hasattr(worker, "sentinel")]
288
+
289
+ @staticmethod
290
+ def _join_exited_workers(pool):
291
+ """Cleanup after any worker processes which have exited due to reaching
292
+ their specified lifetime. Returns True if any workers were cleaned up.
293
+ """
294
+ cleaned = False
295
+ for i in reversed(range(len(pool))):
296
+ worker = pool[i]
297
+ if worker.exitcode is not None:
298
+ # worker exited
299
+ util.debug('cleaning up worker %d' % i)
300
+ worker.join()
301
+ cleaned = True
302
+ del pool[i]
303
+ return cleaned
304
+
305
+ def _repopulate_pool(self):
306
+ return self._repopulate_pool_static(self._ctx, self.Process,
307
+ self._processes,
308
+ self._pool, self._inqueue,
309
+ self._outqueue, self._initializer,
310
+ self._initargs,
311
+ self._maxtasksperchild,
312
+ self._wrap_exception)
313
+
314
+ @staticmethod
315
+ def _repopulate_pool_static(ctx, Process, processes, pool, inqueue,
316
+ outqueue, initializer, initargs,
317
+ maxtasksperchild, wrap_exception):
318
+ """Bring the number of pool processes up to the specified number,
319
+ for use after reaping workers which have exited.
320
+ """
321
+ for i in range(processes - len(pool)):
322
+ w = Process(ctx, target=worker,
323
+ args=(inqueue, outqueue,
324
+ initializer,
325
+ initargs, maxtasksperchild,
326
+ wrap_exception))
327
+ w.name = w.name.replace('Process', 'PoolWorker')
328
+ w.daemon = True
329
+ w.start()
330
+ pool.append(w)
331
+ util.debug('added worker')
332
+
333
+ @staticmethod
334
+ def _maintain_pool(ctx, Process, processes, pool, inqueue, outqueue,
335
+ initializer, initargs, maxtasksperchild,
336
+ wrap_exception):
337
+ """Clean up any exited workers and start replacements for them.
338
+ """
339
+ if Pool._join_exited_workers(pool):
340
+ Pool._repopulate_pool_static(ctx, Process, processes, pool,
341
+ inqueue, outqueue, initializer,
342
+ initargs, maxtasksperchild,
343
+ wrap_exception)
344
+
345
+ def _setup_queues(self):
346
+ self._inqueue = self._ctx.SimpleQueue()
347
+ self._outqueue = self._ctx.SimpleQueue()
348
+ self._quick_put = self._inqueue._writer.send
349
+ self._quick_get = self._outqueue._reader.recv
350
+
351
+ def _check_running(self):
352
+ if self._state != RUN:
353
+ raise ValueError("Pool not running")
354
+
355
+ def apply(self, func, args=(), kwds={}):
356
+ '''
357
+ Equivalent of `func(*args, **kwds)`.
358
+ Pool must be running.
359
+ '''
360
+ return self.apply_async(func, args, kwds).get()
361
+
362
+ def map(self, func, iterable, chunksize=None):
363
+ '''
364
+ Apply `func` to each element in `iterable`, collecting the results
365
+ in a list that is returned.
366
+ '''
367
+ return self._map_async(func, iterable, mapstar, chunksize).get()
368
+
369
+ def starmap(self, func, iterable, chunksize=None):
370
+ '''
371
+ Like `map()` method but the elements of the `iterable` are expected to
372
+ be iterables as well and will be unpacked as arguments. Hence
373
+ `func` and (a, b) becomes func(a, b).
374
+ '''
375
+ return self._map_async(func, iterable, starmapstar, chunksize).get()
376
+
377
+ def starmap_async(self, func, iterable, chunksize=None, callback=None,
378
+ error_callback=None):
379
+ '''
380
+ Asynchronous version of `starmap()` method.
381
+ '''
382
+ return self._map_async(func, iterable, starmapstar, chunksize,
383
+ callback, error_callback)
384
+
385
+ def _guarded_task_generation(self, result_job, func, iterable):
386
+ '''Provides a generator of tasks for imap and imap_unordered with
387
+ appropriate handling for iterables which throw exceptions during
388
+ iteration.'''
389
+ try:
390
+ i = -1
391
+ for i, x in enumerate(iterable):
392
+ yield (result_job, i, func, (x,), {})
393
+ except Exception as e:
394
+ yield (result_job, i+1, _helper_reraises_exception, (e,), {})
395
+
396
+ def imap(self, func, iterable, chunksize=1):
397
+ '''
398
+ Equivalent of `map()` -- can be MUCH slower than `Pool.map()`.
399
+ '''
400
+ self._check_running()
401
+ if chunksize == 1:
402
+ result = IMapIterator(self)
403
+ self._taskqueue.put(
404
+ (
405
+ self._guarded_task_generation(result._job, func, iterable),
406
+ result._set_length
407
+ ))
408
+ return result
409
+ else:
410
+ if chunksize < 1:
411
+ raise ValueError(
412
+ "Chunksize must be 1+, not {0:n}".format(
413
+ chunksize))
414
+ task_batches = Pool._get_tasks(func, iterable, chunksize)
415
+ result = IMapIterator(self)
416
+ self._taskqueue.put(
417
+ (
418
+ self._guarded_task_generation(result._job,
419
+ mapstar,
420
+ task_batches),
421
+ result._set_length
422
+ ))
423
+ return (item for chunk in result for item in chunk)
424
+
425
+ def imap_unordered(self, func, iterable, chunksize=1):
426
+ '''
427
+ Like `imap()` method but ordering of results is arbitrary.
428
+ '''
429
+ self._check_running()
430
+ if chunksize == 1:
431
+ result = IMapUnorderedIterator(self)
432
+ self._taskqueue.put(
433
+ (
434
+ self._guarded_task_generation(result._job, func, iterable),
435
+ result._set_length
436
+ ))
437
+ return result
438
+ else:
439
+ if chunksize < 1:
440
+ raise ValueError(
441
+ "Chunksize must be 1+, not {0!r}".format(chunksize))
442
+ task_batches = Pool._get_tasks(func, iterable, chunksize)
443
+ result = IMapUnorderedIterator(self)
444
+ self._taskqueue.put(
445
+ (
446
+ self._guarded_task_generation(result._job,
447
+ mapstar,
448
+ task_batches),
449
+ result._set_length
450
+ ))
451
+ return (item for chunk in result for item in chunk)
452
+
453
+ def apply_async(self, func, args=(), kwds={}, callback=None,
454
+ error_callback=None):
455
+ '''
456
+ Asynchronous version of `apply()` method.
457
+ '''
458
+ self._check_running()
459
+ result = ApplyResult(self, callback, error_callback)
460
+ self._taskqueue.put(([(result._job, 0, func, args, kwds)], None))
461
+ return result
462
+
463
+ def map_async(self, func, iterable, chunksize=None, callback=None,
464
+ error_callback=None):
465
+ '''
466
+ Asynchronous version of `map()` method.
467
+ '''
468
+ return self._map_async(func, iterable, mapstar, chunksize, callback,
469
+ error_callback)
470
+
471
+ def _map_async(self, func, iterable, mapper, chunksize=None, callback=None,
472
+ error_callback=None):
473
+ '''
474
+ Helper function to implement map, starmap and their async counterparts.
475
+ '''
476
+ self._check_running()
477
+ if not hasattr(iterable, '__len__'):
478
+ iterable = list(iterable)
479
+
480
+ if chunksize is None:
481
+ chunksize, extra = divmod(len(iterable), len(self._pool) * 4)
482
+ if extra:
483
+ chunksize += 1
484
+ if len(iterable) == 0:
485
+ chunksize = 0
486
+
487
+ task_batches = Pool._get_tasks(func, iterable, chunksize)
488
+ result = MapResult(self, chunksize, len(iterable), callback,
489
+ error_callback=error_callback)
490
+ self._taskqueue.put(
491
+ (
492
+ self._guarded_task_generation(result._job,
493
+ mapper,
494
+ task_batches),
495
+ None
496
+ )
497
+ )
498
+ return result
499
+
500
+ @staticmethod
501
+ def _wait_for_updates(sentinels, change_notifier, timeout=None):
502
+ wait(sentinels, timeout=timeout)
503
+ while not change_notifier.empty():
504
+ change_notifier.get()
505
+
506
+ @classmethod
507
+ def _handle_workers(cls, cache, taskqueue, ctx, Process, processes,
508
+ pool, inqueue, outqueue, initializer, initargs,
509
+ maxtasksperchild, wrap_exception, sentinels,
510
+ change_notifier):
511
+ thread = threading.current_thread()
512
+
513
+ # Keep maintaining workers until the cache gets drained, unless the pool
514
+ # is terminated.
515
+ while thread._state == RUN or (cache and thread._state != TERMINATE):
516
+ cls._maintain_pool(ctx, Process, processes, pool, inqueue,
517
+ outqueue, initializer, initargs,
518
+ maxtasksperchild, wrap_exception)
519
+
520
+ current_sentinels = [*cls._get_worker_sentinels(pool), *sentinels]
521
+
522
+ cls._wait_for_updates(current_sentinels, change_notifier)
523
+ # send sentinel to stop workers
524
+ taskqueue.put(None)
525
+ util.debug('worker handler exiting')
526
+
527
+ @staticmethod
528
+ def _handle_tasks(taskqueue, put, outqueue, pool, cache):
529
+ thread = threading.current_thread()
530
+
531
+ for taskseq, set_length in iter(taskqueue.get, None):
532
+ task = None
533
+ try:
534
+ # iterating taskseq cannot fail
535
+ for task in taskseq:
536
+ if thread._state != RUN:
537
+ util.debug('task handler found thread._state != RUN')
538
+ break
539
+ try:
540
+ put(task)
541
+ except Exception as e:
542
+ job, idx = task[:2]
543
+ try:
544
+ cache[job]._set(idx, (False, e))
545
+ except KeyError:
546
+ pass
547
+ else:
548
+ if set_length:
549
+ util.debug('doing set_length()')
550
+ idx = task[1] if task else -1
551
+ set_length(idx + 1)
552
+ continue
553
+ break
554
+ finally:
555
+ task = taskseq = job = None
556
+ else:
557
+ util.debug('task handler got sentinel')
558
+
559
+ try:
560
+ # tell result handler to finish when cache is empty
561
+ util.debug('task handler sending sentinel to result handler')
562
+ outqueue.put(None)
563
+
564
+ # tell workers there is no more work
565
+ util.debug('task handler sending sentinel to workers')
566
+ for p in pool:
567
+ put(None)
568
+ except OSError:
569
+ util.debug('task handler got OSError when sending sentinels')
570
+
571
+ util.debug('task handler exiting')
572
+
573
+ @staticmethod
574
+ def _handle_results(outqueue, get, cache):
575
+ thread = threading.current_thread()
576
+
577
+ while 1:
578
+ try:
579
+ task = get()
580
+ except (OSError, EOFError):
581
+ util.debug('result handler got EOFError/OSError -- exiting')
582
+ return
583
+
584
+ if thread._state != RUN:
585
+ assert thread._state == TERMINATE, "Thread not in TERMINATE"
586
+ util.debug('result handler found thread._state=TERMINATE')
587
+ break
588
+
589
+ if task is None:
590
+ util.debug('result handler got sentinel')
591
+ break
592
+
593
+ job, i, obj = task
594
+ try:
595
+ cache[job]._set(i, obj)
596
+ except KeyError:
597
+ pass
598
+ task = job = obj = None
599
+
600
+ while cache and thread._state != TERMINATE:
601
+ try:
602
+ task = get()
603
+ except (OSError, EOFError):
604
+ util.debug('result handler got EOFError/OSError -- exiting')
605
+ return
606
+
607
+ if task is None:
608
+ util.debug('result handler ignoring extra sentinel')
609
+ continue
610
+ job, i, obj = task
611
+ try:
612
+ cache[job]._set(i, obj)
613
+ except KeyError:
614
+ pass
615
+ task = job = obj = None
616
+
617
+ if hasattr(outqueue, '_reader'):
618
+ util.debug('ensuring that outqueue is not full')
619
+ # If we don't make room available in outqueue then
620
+ # attempts to add the sentinel (None) to outqueue may
621
+ # block. There is guaranteed to be no more than 2 sentinels.
622
+ try:
623
+ for i in range(10):
624
+ if not outqueue._reader.poll():
625
+ break
626
+ get()
627
+ except (OSError, EOFError):
628
+ pass
629
+
630
+ util.debug('result handler exiting: len(cache)=%s, thread._state=%s',
631
+ len(cache), thread._state)
632
+
633
+ @staticmethod
634
+ def _get_tasks(func, it, size):
635
+ it = iter(it)
636
+ while 1:
637
+ x = tuple(itertools.islice(it, size))
638
+ if not x:
639
+ return
640
+ yield (func, x)
641
+
642
+ def __reduce__(self):
643
+ raise NotImplementedError(
644
+ 'pool objects cannot be passed between processes or pickled'
645
+ )
646
+
647
+ def close(self):
648
+ util.debug('closing pool')
649
+ if self._state == RUN:
650
+ self._state = CLOSE
651
+ self._worker_handler._state = CLOSE
652
+ self._change_notifier.put(None)
653
+
654
+ def terminate(self):
655
+ util.debug('terminating pool')
656
+ self._state = TERMINATE
657
+ self._terminate()
658
+
659
+ def join(self):
660
+ util.debug('joining pool')
661
+ if self._state == RUN:
662
+ raise ValueError("Pool is still running")
663
+ elif self._state not in (CLOSE, TERMINATE):
664
+ raise ValueError("In unknown state")
665
+ self._worker_handler.join()
666
+ self._task_handler.join()
667
+ self._result_handler.join()
668
+ for p in self._pool:
669
+ p.join()
670
+
671
+ @staticmethod
672
+ def _help_stuff_finish(inqueue, task_handler, size):
673
+ # task_handler may be blocked trying to put items on inqueue
674
+ util.debug('removing tasks from inqueue until task handler finished')
675
+ inqueue._rlock.acquire()
676
+ while task_handler.is_alive() and inqueue._reader.poll():
677
+ inqueue._reader.recv()
678
+ time.sleep(0)
679
+
680
+ @classmethod
681
+ def _terminate_pool(cls, taskqueue, inqueue, outqueue, pool, change_notifier,
682
+ worker_handler, task_handler, result_handler, cache):
683
+ # this is guaranteed to only be called once
684
+ util.debug('finalizing pool')
685
+
686
+ # Notify that the worker_handler state has been changed so the
687
+ # _handle_workers loop can be unblocked (and exited) in order to
688
+ # send the finalization sentinel all the workers.
689
+ worker_handler._state = TERMINATE
690
+ change_notifier.put(None)
691
+
692
+ task_handler._state = TERMINATE
693
+
694
+ util.debug('helping task handler/workers to finish')
695
+ cls._help_stuff_finish(inqueue, task_handler, len(pool))
696
+
697
+ if (not result_handler.is_alive()) and (len(cache) != 0):
698
+ raise AssertionError(
699
+ "Cannot have cache with result_hander not alive")
700
+
701
+ result_handler._state = TERMINATE
702
+ change_notifier.put(None)
703
+ outqueue.put(None) # sentinel
704
+
705
+ # We must wait for the worker handler to exit before terminating
706
+ # workers because we don't want workers to be restarted behind our back.
707
+ util.debug('joining worker handler')
708
+ if threading.current_thread() is not worker_handler:
709
+ worker_handler.join()
710
+
711
+ # Terminate workers which haven't already finished.
712
+ if pool and hasattr(pool[0], 'terminate'):
713
+ util.debug('terminating workers')
714
+ for p in pool:
715
+ if p.exitcode is None:
716
+ p.terminate()
717
+
718
+ util.debug('joining task handler')
719
+ if threading.current_thread() is not task_handler:
720
+ task_handler.join()
721
+
722
+ util.debug('joining result handler')
723
+ if threading.current_thread() is not result_handler:
724
+ result_handler.join()
725
+
726
+ if pool and hasattr(pool[0], 'terminate'):
727
+ util.debug('joining pool workers')
728
+ for p in pool:
729
+ if p.is_alive():
730
+ # worker has not yet exited
731
+ util.debug('cleaning up worker %d' % p.pid)
732
+ p.join()
733
+
734
+ def __enter__(self):
735
+ self._check_running()
736
+ return self
737
+
738
+ def __exit__(self, exc_type, exc_val, exc_tb):
739
+ self.terminate()
740
+
741
+ #
742
+ # Class whose instances are returned by `Pool.apply_async()`
743
+ #
744
+
745
+ class ApplyResult(object):
746
+
747
+ def __init__(self, pool, callback, error_callback):
748
+ self._pool = pool
749
+ self._event = threading.Event()
750
+ self._job = next(job_counter)
751
+ self._cache = pool._cache
752
+ self._callback = callback
753
+ self._error_callback = error_callback
754
+ self._cache[self._job] = self
755
+
756
+ def ready(self):
757
+ return self._event.is_set()
758
+
759
+ def successful(self):
760
+ if not self.ready():
761
+ raise ValueError("{0!r} not ready".format(self))
762
+ return self._success
763
+
764
+ def wait(self, timeout=None):
765
+ self._event.wait(timeout)
766
+
767
+ def get(self, timeout=None):
768
+ self.wait(timeout)
769
+ if not self.ready():
770
+ raise TimeoutError
771
+ if self._success:
772
+ return self._value
773
+ else:
774
+ raise self._value
775
+
776
+ def _set(self, i, obj):
777
+ self._success, self._value = obj
778
+ if self._callback and self._success:
779
+ self._callback(self._value)
780
+ if self._error_callback and not self._success:
781
+ self._error_callback(self._value)
782
+ self._event.set()
783
+ del self._cache[self._job]
784
+ self._pool = None
785
+
786
+ __class_getitem__ = classmethod(types.GenericAlias)
787
+
788
+ AsyncResult = ApplyResult # create alias -- see #17805
789
+
790
+ #
791
+ # Class whose instances are returned by `Pool.map_async()`
792
+ #
793
+
794
+ class MapResult(ApplyResult):
795
+
796
+ def __init__(self, pool, chunksize, length, callback, error_callback):
797
+ ApplyResult.__init__(self, pool, callback,
798
+ error_callback=error_callback)
799
+ self._success = True
800
+ self._value = [None] * length
801
+ self._chunksize = chunksize
802
+ if chunksize <= 0:
803
+ self._number_left = 0
804
+ self._event.set()
805
+ del self._cache[self._job]
806
+ else:
807
+ self._number_left = length//chunksize + bool(length % chunksize)
808
+
809
+ def _set(self, i, success_result):
810
+ self._number_left -= 1
811
+ success, result = success_result
812
+ if success and self._success:
813
+ self._value[i*self._chunksize:(i+1)*self._chunksize] = result
814
+ if self._number_left == 0:
815
+ if self._callback:
816
+ self._callback(self._value)
817
+ del self._cache[self._job]
818
+ self._event.set()
819
+ self._pool = None
820
+ else:
821
+ if not success and self._success:
822
+ # only store first exception
823
+ self._success = False
824
+ self._value = result
825
+ if self._number_left == 0:
826
+ # only consider the result ready once all jobs are done
827
+ if self._error_callback:
828
+ self._error_callback(self._value)
829
+ del self._cache[self._job]
830
+ self._event.set()
831
+ self._pool = None
832
+
833
+ #
834
+ # Class whose instances are returned by `Pool.imap()`
835
+ #
836
+
837
+ class IMapIterator(object):
838
+
839
+ def __init__(self, pool):
840
+ self._pool = pool
841
+ self._cond = threading.Condition(threading.Lock())
842
+ self._job = next(job_counter)
843
+ self._cache = pool._cache
844
+ self._items = collections.deque()
845
+ self._index = 0
846
+ self._length = None
847
+ self._unsorted = {}
848
+ self._cache[self._job] = self
849
+
850
+ def __iter__(self):
851
+ return self
852
+
853
+ def next(self, timeout=None):
854
+ with self._cond:
855
+ try:
856
+ item = self._items.popleft()
857
+ except IndexError:
858
+ if self._index == self._length:
859
+ self._pool = None
860
+ raise StopIteration from None
861
+ self._cond.wait(timeout)
862
+ try:
863
+ item = self._items.popleft()
864
+ except IndexError:
865
+ if self._index == self._length:
866
+ self._pool = None
867
+ raise StopIteration from None
868
+ raise TimeoutError from None
869
+
870
+ success, value = item
871
+ if success:
872
+ return value
873
+ raise value
874
+
875
+ __next__ = next # XXX
876
+
877
+ def _set(self, i, obj):
878
+ with self._cond:
879
+ if self._index == i:
880
+ self._items.append(obj)
881
+ self._index += 1
882
+ while self._index in self._unsorted:
883
+ obj = self._unsorted.pop(self._index)
884
+ self._items.append(obj)
885
+ self._index += 1
886
+ self._cond.notify()
887
+ else:
888
+ self._unsorted[i] = obj
889
+
890
+ if self._index == self._length:
891
+ del self._cache[self._job]
892
+ self._pool = None
893
+
894
+ def _set_length(self, length):
895
+ with self._cond:
896
+ self._length = length
897
+ if self._index == self._length:
898
+ self._cond.notify()
899
+ del self._cache[self._job]
900
+ self._pool = None
901
+
902
+ #
903
+ # Class whose instances are returned by `Pool.imap_unordered()`
904
+ #
905
+
906
+ class IMapUnorderedIterator(IMapIterator):
907
+
908
+ def _set(self, i, obj):
909
+ with self._cond:
910
+ self._items.append(obj)
911
+ self._index += 1
912
+ self._cond.notify()
913
+ if self._index == self._length:
914
+ del self._cache[self._job]
915
+ self._pool = None
916
+
917
+ #
918
+ #
919
+ #
920
+
921
+ class ThreadPool(Pool):
922
+ _wrap_exception = False
923
+
924
+ @staticmethod
925
+ def Process(ctx, *args, **kwds):
926
+ from .dummy import Process
927
+ return Process(*args, **kwds)
928
+
929
+ def __init__(self, processes=None, initializer=None, initargs=()):
930
+ Pool.__init__(self, processes, initializer, initargs)
931
+
932
+ def _setup_queues(self):
933
+ self._inqueue = queue.SimpleQueue()
934
+ self._outqueue = queue.SimpleQueue()
935
+ self._quick_put = self._inqueue.put
936
+ self._quick_get = self._outqueue.get
937
+
938
+ def _get_sentinels(self):
939
+ return [self._change_notifier._reader]
940
+
941
+ @staticmethod
942
+ def _get_worker_sentinels(workers):
943
+ return []
944
+
945
+ @staticmethod
946
+ def _help_stuff_finish(inqueue, task_handler, size):
947
+ # drain inqueue, and put sentinels at its head to make workers finish
948
+ try:
949
+ while True:
950
+ inqueue.get(block=False)
951
+ except queue.Empty:
952
+ pass
953
+ for i in range(size):
954
+ inqueue.put(None)
955
+
956
+ def _wait_for_updates(self, sentinels, change_notifier, timeout):
957
+ time.sleep(timeout)
lib/python3.1/multiprocessing/popen_fork.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import signal
3
+
4
+ from . import util
5
+
6
+ __all__ = ['Popen']
7
+
8
+ #
9
+ # Start child process using fork
10
+ #
11
+
12
+ class Popen(object):
13
+ method = 'fork'
14
+
15
+ def __init__(self, process_obj):
16
+ util._flush_std_streams()
17
+ self.returncode = None
18
+ self.finalizer = None
19
+ self._launch(process_obj)
20
+
21
+ def duplicate_for_child(self, fd):
22
+ return fd
23
+
24
+ def poll(self, flag=os.WNOHANG):
25
+ if self.returncode is None:
26
+ try:
27
+ pid, sts = os.waitpid(self.pid, flag)
28
+ except OSError:
29
+ # Child process not yet created. See #1731717
30
+ # e.errno == errno.ECHILD == 10
31
+ return None
32
+ if pid == self.pid:
33
+ self.returncode = os.waitstatus_to_exitcode(sts)
34
+ return self.returncode
35
+
36
+ def wait(self, timeout=None):
37
+ if self.returncode is None:
38
+ if timeout is not None:
39
+ from multiprocessing.connection import wait
40
+ if not wait([self.sentinel], timeout):
41
+ return None
42
+ # This shouldn't block if wait() returned successfully.
43
+ return self.poll(os.WNOHANG if timeout == 0.0 else 0)
44
+ return self.returncode
45
+
46
+ def _send_signal(self, sig):
47
+ if self.returncode is None:
48
+ try:
49
+ os.kill(self.pid, sig)
50
+ except ProcessLookupError:
51
+ pass
52
+ except OSError:
53
+ if self.wait(timeout=0.1) is None:
54
+ raise
55
+
56
+ def terminate(self):
57
+ self._send_signal(signal.SIGTERM)
58
+
59
+ def kill(self):
60
+ self._send_signal(signal.SIGKILL)
61
+
62
+ def _launch(self, process_obj):
63
+ code = 1
64
+ parent_r, child_w = os.pipe()
65
+ child_r, parent_w = os.pipe()
66
+ self.pid = os.fork()
67
+ if self.pid == 0:
68
+ try:
69
+ os.close(parent_r)
70
+ os.close(parent_w)
71
+ code = process_obj._bootstrap(parent_sentinel=child_r)
72
+ finally:
73
+ os._exit(code)
74
+ else:
75
+ os.close(child_w)
76
+ os.close(child_r)
77
+ self.finalizer = util.Finalize(self, util.close_fds,
78
+ (parent_r, parent_w,))
79
+ self.sentinel = parent_r
80
+
81
+ def close(self):
82
+ if self.finalizer is not None:
83
+ self.finalizer()
lib/python3.1/multiprocessing/popen_forkserver.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import os
3
+
4
+ from .context import reduction, set_spawning_popen
5
+ if not reduction.HAVE_SEND_HANDLE:
6
+ raise ImportError('No support for sending fds between processes')
7
+ from . import forkserver
8
+ from . import popen_fork
9
+ from . import spawn
10
+ from . import util
11
+
12
+
13
+ __all__ = ['Popen']
14
+
15
+ #
16
+ # Wrapper for an fd used while launching a process
17
+ #
18
+
19
+ class _DupFd(object):
20
+ def __init__(self, ind):
21
+ self.ind = ind
22
+ def detach(self):
23
+ return forkserver.get_inherited_fds()[self.ind]
24
+
25
+ #
26
+ # Start child process using a server process
27
+ #
28
+
29
+ class Popen(popen_fork.Popen):
30
+ method = 'forkserver'
31
+ DupFd = _DupFd
32
+
33
+ def __init__(self, process_obj):
34
+ self._fds = []
35
+ super().__init__(process_obj)
36
+
37
+ def duplicate_for_child(self, fd):
38
+ self._fds.append(fd)
39
+ return len(self._fds) - 1
40
+
41
+ def _launch(self, process_obj):
42
+ prep_data = spawn.get_preparation_data(process_obj._name)
43
+ buf = io.BytesIO()
44
+ set_spawning_popen(self)
45
+ try:
46
+ reduction.dump(prep_data, buf)
47
+ reduction.dump(process_obj, buf)
48
+ finally:
49
+ set_spawning_popen(None)
50
+
51
+ self.sentinel, w = forkserver.connect_to_new_process(self._fds)
52
+ # Keep a duplicate of the data pipe's write end as a sentinel of the
53
+ # parent process used by the child process.
54
+ _parent_w = os.dup(w)
55
+ self.finalizer = util.Finalize(self, util.close_fds,
56
+ (_parent_w, self.sentinel))
57
+ with open(w, 'wb', closefd=True) as f:
58
+ f.write(buf.getbuffer())
59
+ self.pid = forkserver.read_signed(self.sentinel)
60
+
61
+ def poll(self, flag=os.WNOHANG):
62
+ if self.returncode is None:
63
+ from multiprocessing.connection import wait
64
+ timeout = 0 if flag == os.WNOHANG else None
65
+ if not wait([self.sentinel], timeout):
66
+ return None
67
+ try:
68
+ self.returncode = forkserver.read_signed(self.sentinel)
69
+ except (OSError, EOFError):
70
+ # This should not happen usually, but perhaps the forkserver
71
+ # process itself got killed
72
+ self.returncode = 255
73
+
74
+ return self.returncode
lib/python3.1/multiprocessing/popen_spawn_posix.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import os
3
+
4
+ from .context import reduction, set_spawning_popen
5
+ from . import popen_fork
6
+ from . import spawn
7
+ from . import util
8
+
9
+ __all__ = ['Popen']
10
+
11
+
12
+ #
13
+ # Wrapper for an fd used while launching a process
14
+ #
15
+
16
+ class _DupFd(object):
17
+ def __init__(self, fd):
18
+ self.fd = fd
19
+ def detach(self):
20
+ return self.fd
21
+
22
+ #
23
+ # Start child process using a fresh interpreter
24
+ #
25
+
26
+ class Popen(popen_fork.Popen):
27
+ method = 'spawn'
28
+ DupFd = _DupFd
29
+
30
+ def __init__(self, process_obj):
31
+ self._fds = []
32
+ super().__init__(process_obj)
33
+
34
+ def duplicate_for_child(self, fd):
35
+ self._fds.append(fd)
36
+ return fd
37
+
38
+ def _launch(self, process_obj):
39
+ from . import resource_tracker
40
+ tracker_fd = resource_tracker.getfd()
41
+ self._fds.append(tracker_fd)
42
+ prep_data = spawn.get_preparation_data(process_obj._name)
43
+ fp = io.BytesIO()
44
+ set_spawning_popen(self)
45
+ try:
46
+ reduction.dump(prep_data, fp)
47
+ reduction.dump(process_obj, fp)
48
+ finally:
49
+ set_spawning_popen(None)
50
+
51
+ parent_r = child_w = child_r = parent_w = None
52
+ try:
53
+ parent_r, child_w = os.pipe()
54
+ child_r, parent_w = os.pipe()
55
+ cmd = spawn.get_command_line(tracker_fd=tracker_fd,
56
+ pipe_handle=child_r)
57
+ self._fds.extend([child_r, child_w])
58
+ self.pid = util.spawnv_passfds(spawn.get_executable(),
59
+ cmd, self._fds)
60
+ self.sentinel = parent_r
61
+ with open(parent_w, 'wb', closefd=False) as f:
62
+ f.write(fp.getbuffer())
63
+ finally:
64
+ fds_to_close = []
65
+ for fd in (parent_r, parent_w):
66
+ if fd is not None:
67
+ fds_to_close.append(fd)
68
+ self.finalizer = util.Finalize(self, util.close_fds, fds_to_close)
69
+
70
+ for fd in (child_r, child_w):
71
+ if fd is not None:
72
+ os.close(fd)
lib/python3.1/multiprocessing/popen_spawn_win32.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import msvcrt
3
+ import signal
4
+ import sys
5
+ import _winapi
6
+
7
+ from .context import reduction, get_spawning_popen, set_spawning_popen
8
+ from . import spawn
9
+ from . import util
10
+
11
+ __all__ = ['Popen']
12
+
13
+ #
14
+ #
15
+ #
16
+
17
+ TERMINATE = 0x10000
18
+ WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
19
+ WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
20
+
21
+
22
+ def _path_eq(p1, p2):
23
+ return p1 == p2 or os.path.normcase(p1) == os.path.normcase(p2)
24
+
25
+ WINENV = not _path_eq(sys.executable, sys._base_executable)
26
+
27
+
28
+ def _close_handles(*handles):
29
+ for handle in handles:
30
+ _winapi.CloseHandle(handle)
31
+
32
+
33
+ #
34
+ # We define a Popen class similar to the one from subprocess, but
35
+ # whose constructor takes a process object as its argument.
36
+ #
37
+
38
+ class Popen(object):
39
+ '''
40
+ Start a subprocess to run the code of a process object
41
+ '''
42
+ method = 'spawn'
43
+
44
+ def __init__(self, process_obj):
45
+ prep_data = spawn.get_preparation_data(process_obj._name)
46
+
47
+ # read end of pipe will be duplicated by the child process
48
+ # -- see spawn_main() in spawn.py.
49
+ #
50
+ # bpo-33929: Previously, the read end of pipe was "stolen" by the child
51
+ # process, but it leaked a handle if the child process had been
52
+ # terminated before it could steal the handle from the parent process.
53
+ rhandle, whandle = _winapi.CreatePipe(None, 0)
54
+ wfd = msvcrt.open_osfhandle(whandle, 0)
55
+ cmd = spawn.get_command_line(parent_pid=os.getpid(),
56
+ pipe_handle=rhandle)
57
+ cmd = ' '.join('"%s"' % x for x in cmd)
58
+
59
+ python_exe = spawn.get_executable()
60
+
61
+ # bpo-35797: When running in a venv, we bypass the redirect
62
+ # executor and launch our base Python.
63
+ if WINENV and _path_eq(python_exe, sys.executable):
64
+ python_exe = sys._base_executable
65
+ env = os.environ.copy()
66
+ env["__PYVENV_LAUNCHER__"] = sys.executable
67
+ else:
68
+ env = None
69
+
70
+ with open(wfd, 'wb', closefd=True) as to_child:
71
+ # start process
72
+ try:
73
+ hp, ht, pid, tid = _winapi.CreateProcess(
74
+ python_exe, cmd,
75
+ None, None, False, 0, env, None, None)
76
+ _winapi.CloseHandle(ht)
77
+ except:
78
+ _winapi.CloseHandle(rhandle)
79
+ raise
80
+
81
+ # set attributes of self
82
+ self.pid = pid
83
+ self.returncode = None
84
+ self._handle = hp
85
+ self.sentinel = int(hp)
86
+ self.finalizer = util.Finalize(self, _close_handles,
87
+ (self.sentinel, int(rhandle)))
88
+
89
+ # send information to child
90
+ set_spawning_popen(self)
91
+ try:
92
+ reduction.dump(prep_data, to_child)
93
+ reduction.dump(process_obj, to_child)
94
+ finally:
95
+ set_spawning_popen(None)
96
+
97
+ def duplicate_for_child(self, handle):
98
+ assert self is get_spawning_popen()
99
+ return reduction.duplicate(handle, self.sentinel)
100
+
101
+ def wait(self, timeout=None):
102
+ if self.returncode is None:
103
+ if timeout is None:
104
+ msecs = _winapi.INFINITE
105
+ else:
106
+ msecs = max(0, int(timeout * 1000 + 0.5))
107
+
108
+ res = _winapi.WaitForSingleObject(int(self._handle), msecs)
109
+ if res == _winapi.WAIT_OBJECT_0:
110
+ code = _winapi.GetExitCodeProcess(self._handle)
111
+ if code == TERMINATE:
112
+ code = -signal.SIGTERM
113
+ self.returncode = code
114
+
115
+ return self.returncode
116
+
117
+ def poll(self):
118
+ return self.wait(timeout=0)
119
+
120
+ def terminate(self):
121
+ if self.returncode is None:
122
+ try:
123
+ _winapi.TerminateProcess(int(self._handle), TERMINATE)
124
+ except OSError:
125
+ if self.wait(timeout=1.0) is None:
126
+ raise
127
+
128
+ kill = terminate
129
+
130
+ def close(self):
131
+ self.finalizer()
lib/python3.1/multiprocessing/process.py ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module providing the `Process` class which emulates `threading.Thread`
3
+ #
4
+ # multiprocessing/process.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = ['BaseProcess', 'current_process', 'active_children',
11
+ 'parent_process']
12
+
13
+ #
14
+ # Imports
15
+ #
16
+
17
+ import os
18
+ import sys
19
+ import signal
20
+ import itertools
21
+ import threading
22
+ from _weakrefset import WeakSet
23
+
24
+ #
25
+ #
26
+ #
27
+
28
+ try:
29
+ ORIGINAL_DIR = os.path.abspath(os.getcwd())
30
+ except OSError:
31
+ ORIGINAL_DIR = None
32
+
33
+ #
34
+ # Public functions
35
+ #
36
+
37
+ def current_process():
38
+ '''
39
+ Return process object representing the current process
40
+ '''
41
+ return _current_process
42
+
43
+ def active_children():
44
+ '''
45
+ Return list of process objects corresponding to live child processes
46
+ '''
47
+ _cleanup()
48
+ return list(_children)
49
+
50
+
51
+ def parent_process():
52
+ '''
53
+ Return process object representing the parent process
54
+ '''
55
+ return _parent_process
56
+
57
+ #
58
+ #
59
+ #
60
+
61
+ def _cleanup():
62
+ # check for processes which have finished
63
+ for p in list(_children):
64
+ if p._popen.poll() is not None:
65
+ _children.discard(p)
66
+
67
+ #
68
+ # The `Process` class
69
+ #
70
+
71
+ class BaseProcess(object):
72
+ '''
73
+ Process objects represent activity that is run in a separate process
74
+
75
+ The class is analogous to `threading.Thread`
76
+ '''
77
+ def _Popen(self):
78
+ raise NotImplementedError
79
+
80
+ def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
81
+ *, daemon=None):
82
+ assert group is None, 'group argument must be None for now'
83
+ count = next(_process_counter)
84
+ self._identity = _current_process._identity + (count,)
85
+ self._config = _current_process._config.copy()
86
+ self._parent_pid = os.getpid()
87
+ self._parent_name = _current_process.name
88
+ self._popen = None
89
+ self._closed = False
90
+ self._target = target
91
+ self._args = tuple(args)
92
+ self._kwargs = dict(kwargs)
93
+ self._name = name or type(self).__name__ + '-' + \
94
+ ':'.join(str(i) for i in self._identity)
95
+ if daemon is not None:
96
+ self.daemon = daemon
97
+ _dangling.add(self)
98
+
99
+ def _check_closed(self):
100
+ if self._closed:
101
+ raise ValueError("process object is closed")
102
+
103
+ def run(self):
104
+ '''
105
+ Method to be run in sub-process; can be overridden in sub-class
106
+ '''
107
+ if self._target:
108
+ self._target(*self._args, **self._kwargs)
109
+
110
+ def start(self):
111
+ '''
112
+ Start child process
113
+ '''
114
+ self._check_closed()
115
+ assert self._popen is None, 'cannot start a process twice'
116
+ assert self._parent_pid == os.getpid(), \
117
+ 'can only start a process object created by current process'
118
+ assert not _current_process._config.get('daemon'), \
119
+ 'daemonic processes are not allowed to have children'
120
+ _cleanup()
121
+ self._popen = self._Popen(self)
122
+ self._sentinel = self._popen.sentinel
123
+ # Avoid a refcycle if the target function holds an indirect
124
+ # reference to the process object (see bpo-30775)
125
+ del self._target, self._args, self._kwargs
126
+ _children.add(self)
127
+
128
+ def terminate(self):
129
+ '''
130
+ Terminate process; sends SIGTERM signal or uses TerminateProcess()
131
+ '''
132
+ self._check_closed()
133
+ self._popen.terminate()
134
+
135
+ def kill(self):
136
+ '''
137
+ Terminate process; sends SIGKILL signal or uses TerminateProcess()
138
+ '''
139
+ self._check_closed()
140
+ self._popen.kill()
141
+
142
+ def join(self, timeout=None):
143
+ '''
144
+ Wait until child process terminates
145
+ '''
146
+ self._check_closed()
147
+ assert self._parent_pid == os.getpid(), 'can only join a child process'
148
+ assert self._popen is not None, 'can only join a started process'
149
+ res = self._popen.wait(timeout)
150
+ if res is not None:
151
+ _children.discard(self)
152
+
153
+ def is_alive(self):
154
+ '''
155
+ Return whether process is alive
156
+ '''
157
+ self._check_closed()
158
+ if self is _current_process:
159
+ return True
160
+ assert self._parent_pid == os.getpid(), 'can only test a child process'
161
+
162
+ if self._popen is None:
163
+ return False
164
+
165
+ returncode = self._popen.poll()
166
+ if returncode is None:
167
+ return True
168
+ else:
169
+ _children.discard(self)
170
+ return False
171
+
172
+ def close(self):
173
+ '''
174
+ Close the Process object.
175
+
176
+ This method releases resources held by the Process object. It is
177
+ an error to call this method if the child process is still running.
178
+ '''
179
+ if self._popen is not None:
180
+ if self._popen.poll() is None:
181
+ raise ValueError("Cannot close a process while it is still running. "
182
+ "You should first call join() or terminate().")
183
+ self._popen.close()
184
+ self._popen = None
185
+ del self._sentinel
186
+ _children.discard(self)
187
+ self._closed = True
188
+
189
+ @property
190
+ def name(self):
191
+ return self._name
192
+
193
+ @name.setter
194
+ def name(self, name):
195
+ assert isinstance(name, str), 'name must be a string'
196
+ self._name = name
197
+
198
+ @property
199
+ def daemon(self):
200
+ '''
201
+ Return whether process is a daemon
202
+ '''
203
+ return self._config.get('daemon', False)
204
+
205
+ @daemon.setter
206
+ def daemon(self, daemonic):
207
+ '''
208
+ Set whether process is a daemon
209
+ '''
210
+ assert self._popen is None, 'process has already started'
211
+ self._config['daemon'] = daemonic
212
+
213
+ @property
214
+ def authkey(self):
215
+ return self._config['authkey']
216
+
217
+ @authkey.setter
218
+ def authkey(self, authkey):
219
+ '''
220
+ Set authorization key of process
221
+ '''
222
+ self._config['authkey'] = AuthenticationString(authkey)
223
+
224
+ @property
225
+ def exitcode(self):
226
+ '''
227
+ Return exit code of process or `None` if it has yet to stop
228
+ '''
229
+ self._check_closed()
230
+ if self._popen is None:
231
+ return self._popen
232
+ return self._popen.poll()
233
+
234
+ @property
235
+ def ident(self):
236
+ '''
237
+ Return identifier (PID) of process or `None` if it has yet to start
238
+ '''
239
+ self._check_closed()
240
+ if self is _current_process:
241
+ return os.getpid()
242
+ else:
243
+ return self._popen and self._popen.pid
244
+
245
+ pid = ident
246
+
247
+ @property
248
+ def sentinel(self):
249
+ '''
250
+ Return a file descriptor (Unix) or handle (Windows) suitable for
251
+ waiting for process termination.
252
+ '''
253
+ self._check_closed()
254
+ try:
255
+ return self._sentinel
256
+ except AttributeError:
257
+ raise ValueError("process not started") from None
258
+
259
+ def __repr__(self):
260
+ exitcode = None
261
+ if self is _current_process:
262
+ status = 'started'
263
+ elif self._closed:
264
+ status = 'closed'
265
+ elif self._parent_pid != os.getpid():
266
+ status = 'unknown'
267
+ elif self._popen is None:
268
+ status = 'initial'
269
+ else:
270
+ exitcode = self._popen.poll()
271
+ if exitcode is not None:
272
+ status = 'stopped'
273
+ else:
274
+ status = 'started'
275
+
276
+ info = [type(self).__name__, 'name=%r' % self._name]
277
+ if self._popen is not None:
278
+ info.append('pid=%s' % self._popen.pid)
279
+ info.append('parent=%s' % self._parent_pid)
280
+ info.append(status)
281
+ if exitcode is not None:
282
+ exitcode = _exitcode_to_name.get(exitcode, exitcode)
283
+ info.append('exitcode=%s' % exitcode)
284
+ if self.daemon:
285
+ info.append('daemon')
286
+ return '<%s>' % ' '.join(info)
287
+
288
+ ##
289
+
290
+ def _bootstrap(self, parent_sentinel=None):
291
+ from . import util, context
292
+ global _current_process, _parent_process, _process_counter, _children
293
+
294
+ try:
295
+ if self._start_method is not None:
296
+ context._force_start_method(self._start_method)
297
+ _process_counter = itertools.count(1)
298
+ _children = set()
299
+ util._close_stdin()
300
+ old_process = _current_process
301
+ _current_process = self
302
+ _parent_process = _ParentProcess(
303
+ self._parent_name, self._parent_pid, parent_sentinel)
304
+ if threading._HAVE_THREAD_NATIVE_ID:
305
+ threading.main_thread()._set_native_id()
306
+ try:
307
+ self._after_fork()
308
+ finally:
309
+ # delay finalization of the old process object until after
310
+ # _run_after_forkers() is executed
311
+ del old_process
312
+ util.info('child process calling self.run()')
313
+ try:
314
+ self.run()
315
+ exitcode = 0
316
+ finally:
317
+ util._exit_function()
318
+ except SystemExit as e:
319
+ if e.code is None:
320
+ exitcode = 0
321
+ elif isinstance(e.code, int):
322
+ exitcode = e.code
323
+ else:
324
+ sys.stderr.write(str(e.code) + '\n')
325
+ exitcode = 1
326
+ except:
327
+ exitcode = 1
328
+ import traceback
329
+ sys.stderr.write('Process %s:\n' % self.name)
330
+ traceback.print_exc()
331
+ finally:
332
+ threading._shutdown()
333
+ util.info('process exiting with exitcode %d' % exitcode)
334
+ util._flush_std_streams()
335
+
336
+ return exitcode
337
+
338
+ @staticmethod
339
+ def _after_fork():
340
+ from . import util
341
+ util._finalizer_registry.clear()
342
+ util._run_after_forkers()
343
+
344
+
345
+ #
346
+ # We subclass bytes to avoid accidental transmission of auth keys over network
347
+ #
348
+
349
+ class AuthenticationString(bytes):
350
+ def __reduce__(self):
351
+ from .context import get_spawning_popen
352
+ if get_spawning_popen() is None:
353
+ raise TypeError(
354
+ 'Pickling an AuthenticationString object is '
355
+ 'disallowed for security reasons'
356
+ )
357
+ return AuthenticationString, (bytes(self),)
358
+
359
+
360
+ #
361
+ # Create object representing the parent process
362
+ #
363
+
364
+ class _ParentProcess(BaseProcess):
365
+
366
+ def __init__(self, name, pid, sentinel):
367
+ self._identity = ()
368
+ self._name = name
369
+ self._pid = pid
370
+ self._parent_pid = None
371
+ self._popen = None
372
+ self._closed = False
373
+ self._sentinel = sentinel
374
+ self._config = {}
375
+
376
+ def is_alive(self):
377
+ from multiprocessing.connection import wait
378
+ return not wait([self._sentinel], timeout=0)
379
+
380
+ @property
381
+ def ident(self):
382
+ return self._pid
383
+
384
+ def join(self, timeout=None):
385
+ '''
386
+ Wait until parent process terminates
387
+ '''
388
+ from multiprocessing.connection import wait
389
+ wait([self._sentinel], timeout=timeout)
390
+
391
+ pid = ident
392
+
393
+ #
394
+ # Create object representing the main process
395
+ #
396
+
397
+ class _MainProcess(BaseProcess):
398
+
399
+ def __init__(self):
400
+ self._identity = ()
401
+ self._name = 'MainProcess'
402
+ self._parent_pid = None
403
+ self._popen = None
404
+ self._closed = False
405
+ self._config = {'authkey': AuthenticationString(os.urandom(32)),
406
+ 'semprefix': '/mp'}
407
+ # Note that some versions of FreeBSD only allow named
408
+ # semaphores to have names of up to 14 characters. Therefore
409
+ # we choose a short prefix.
410
+ #
411
+ # On MacOSX in a sandbox it may be necessary to use a
412
+ # different prefix -- see #19478.
413
+ #
414
+ # Everything in self._config will be inherited by descendant
415
+ # processes.
416
+
417
+ def close(self):
418
+ pass
419
+
420
+
421
+ _parent_process = None
422
+ _current_process = _MainProcess()
423
+ _process_counter = itertools.count(1)
424
+ _children = set()
425
+ del _MainProcess
426
+
427
+ #
428
+ # Give names to some return codes
429
+ #
430
+
431
+ _exitcode_to_name = {}
432
+
433
+ for name, signum in list(signal.__dict__.items()):
434
+ if name[:3]=='SIG' and '_' not in name:
435
+ _exitcode_to_name[-signum] = f'-{name}'
436
+
437
+ # For debug and leak testing
438
+ _dangling = WeakSet()
lib/python3.1/multiprocessing/queues.py ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module implementing queues
3
+ #
4
+ # multiprocessing/queues.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = ['Queue', 'SimpleQueue', 'JoinableQueue']
11
+
12
+ import sys
13
+ import os
14
+ import threading
15
+ import collections
16
+ import time
17
+ import types
18
+ import weakref
19
+ import errno
20
+
21
+ from queue import Empty, Full
22
+
23
+ import _multiprocessing
24
+
25
+ from . import connection
26
+ from . import context
27
+ _ForkingPickler = context.reduction.ForkingPickler
28
+
29
+ from .util import debug, info, Finalize, register_after_fork, is_exiting
30
+
31
+ #
32
+ # Queue type using a pipe, buffer and thread
33
+ #
34
+
35
+ class Queue(object):
36
+
37
+ def __init__(self, maxsize=0, *, ctx):
38
+ if maxsize <= 0:
39
+ # Can raise ImportError (see issues #3770 and #23400)
40
+ from .synchronize import SEM_VALUE_MAX as maxsize
41
+ self._maxsize = maxsize
42
+ self._reader, self._writer = connection.Pipe(duplex=False)
43
+ self._rlock = ctx.Lock()
44
+ self._opid = os.getpid()
45
+ if sys.platform == 'win32':
46
+ self._wlock = None
47
+ else:
48
+ self._wlock = ctx.Lock()
49
+ self._sem = ctx.BoundedSemaphore(maxsize)
50
+ # For use by concurrent.futures
51
+ self._ignore_epipe = False
52
+ self._reset()
53
+
54
+ if sys.platform != 'win32':
55
+ register_after_fork(self, Queue._after_fork)
56
+
57
+ def __getstate__(self):
58
+ context.assert_spawning(self)
59
+ return (self._ignore_epipe, self._maxsize, self._reader, self._writer,
60
+ self._rlock, self._wlock, self._sem, self._opid)
61
+
62
+ def __setstate__(self, state):
63
+ (self._ignore_epipe, self._maxsize, self._reader, self._writer,
64
+ self._rlock, self._wlock, self._sem, self._opid) = state
65
+ self._reset()
66
+
67
+ def _after_fork(self):
68
+ debug('Queue._after_fork()')
69
+ self._reset(after_fork=True)
70
+
71
+ def _reset(self, after_fork=False):
72
+ if after_fork:
73
+ self._notempty._at_fork_reinit()
74
+ else:
75
+ self._notempty = threading.Condition(threading.Lock())
76
+ self._buffer = collections.deque()
77
+ self._thread = None
78
+ self._jointhread = None
79
+ self._joincancelled = False
80
+ self._closed = False
81
+ self._close = None
82
+ self._send_bytes = self._writer.send_bytes
83
+ self._recv_bytes = self._reader.recv_bytes
84
+ self._poll = self._reader.poll
85
+
86
+ def put(self, obj, block=True, timeout=None):
87
+ if self._closed:
88
+ raise ValueError(f"Queue {self!r} is closed")
89
+ if not self._sem.acquire(block, timeout):
90
+ raise Full
91
+
92
+ with self._notempty:
93
+ if self._thread is None:
94
+ self._start_thread()
95
+ self._buffer.append(obj)
96
+ self._notempty.notify()
97
+
98
+ def get(self, block=True, timeout=None):
99
+ if self._closed:
100
+ raise ValueError(f"Queue {self!r} is closed")
101
+ if block and timeout is None:
102
+ with self._rlock:
103
+ res = self._recv_bytes()
104
+ self._sem.release()
105
+ else:
106
+ if block:
107
+ deadline = time.monotonic() + timeout
108
+ if not self._rlock.acquire(block, timeout):
109
+ raise Empty
110
+ try:
111
+ if block:
112
+ timeout = deadline - time.monotonic()
113
+ if not self._poll(timeout):
114
+ raise Empty
115
+ elif not self._poll():
116
+ raise Empty
117
+ res = self._recv_bytes()
118
+ self._sem.release()
119
+ finally:
120
+ self._rlock.release()
121
+ # unserialize the data after having released the lock
122
+ return _ForkingPickler.loads(res)
123
+
124
+ def qsize(self):
125
+ # Raises NotImplementedError on Mac OSX because of broken sem_getvalue()
126
+ return self._maxsize - self._sem._semlock._get_value()
127
+
128
+ def empty(self):
129
+ return not self._poll()
130
+
131
+ def full(self):
132
+ return self._sem._semlock._is_zero()
133
+
134
+ def get_nowait(self):
135
+ return self.get(False)
136
+
137
+ def put_nowait(self, obj):
138
+ return self.put(obj, False)
139
+
140
+ def close(self):
141
+ self._closed = True
142
+ close = self._close
143
+ if close:
144
+ self._close = None
145
+ close()
146
+
147
+ def join_thread(self):
148
+ debug('Queue.join_thread()')
149
+ assert self._closed, "Queue {0!r} not closed".format(self)
150
+ if self._jointhread:
151
+ self._jointhread()
152
+
153
+ def cancel_join_thread(self):
154
+ debug('Queue.cancel_join_thread()')
155
+ self._joincancelled = True
156
+ try:
157
+ self._jointhread.cancel()
158
+ except AttributeError:
159
+ pass
160
+
161
+ def _start_thread(self):
162
+ debug('Queue._start_thread()')
163
+
164
+ # Start thread which transfers data from buffer to pipe
165
+ self._buffer.clear()
166
+ self._thread = threading.Thread(
167
+ target=Queue._feed,
168
+ args=(self._buffer, self._notempty, self._send_bytes,
169
+ self._wlock, self._reader.close, self._writer.close,
170
+ self._ignore_epipe, self._on_queue_feeder_error,
171
+ self._sem),
172
+ name='QueueFeederThread'
173
+ )
174
+ self._thread.daemon = True
175
+
176
+ debug('doing self._thread.start()')
177
+ self._thread.start()
178
+ debug('... done self._thread.start()')
179
+
180
+ if not self._joincancelled:
181
+ self._jointhread = Finalize(
182
+ self._thread, Queue._finalize_join,
183
+ [weakref.ref(self._thread)],
184
+ exitpriority=-5
185
+ )
186
+
187
+ # Send sentinel to the thread queue object when garbage collected
188
+ self._close = Finalize(
189
+ self, Queue._finalize_close,
190
+ [self._buffer, self._notempty],
191
+ exitpriority=10
192
+ )
193
+
194
+ @staticmethod
195
+ def _finalize_join(twr):
196
+ debug('joining queue thread')
197
+ thread = twr()
198
+ if thread is not None:
199
+ thread.join()
200
+ debug('... queue thread joined')
201
+ else:
202
+ debug('... queue thread already dead')
203
+
204
+ @staticmethod
205
+ def _finalize_close(buffer, notempty):
206
+ debug('telling queue thread to quit')
207
+ with notempty:
208
+ buffer.append(_sentinel)
209
+ notempty.notify()
210
+
211
+ @staticmethod
212
+ def _feed(buffer, notempty, send_bytes, writelock, reader_close,
213
+ writer_close, ignore_epipe, onerror, queue_sem):
214
+ debug('starting thread to feed data to pipe')
215
+ nacquire = notempty.acquire
216
+ nrelease = notempty.release
217
+ nwait = notempty.wait
218
+ bpopleft = buffer.popleft
219
+ sentinel = _sentinel
220
+ if sys.platform != 'win32':
221
+ wacquire = writelock.acquire
222
+ wrelease = writelock.release
223
+ else:
224
+ wacquire = None
225
+
226
+ while 1:
227
+ try:
228
+ nacquire()
229
+ try:
230
+ if not buffer:
231
+ nwait()
232
+ finally:
233
+ nrelease()
234
+ try:
235
+ while 1:
236
+ obj = bpopleft()
237
+ if obj is sentinel:
238
+ debug('feeder thread got sentinel -- exiting')
239
+ reader_close()
240
+ writer_close()
241
+ return
242
+
243
+ # serialize the data before acquiring the lock
244
+ obj = _ForkingPickler.dumps(obj)
245
+ if wacquire is None:
246
+ send_bytes(obj)
247
+ else:
248
+ wacquire()
249
+ try:
250
+ send_bytes(obj)
251
+ finally:
252
+ wrelease()
253
+ except IndexError:
254
+ pass
255
+ except Exception as e:
256
+ if ignore_epipe and getattr(e, 'errno', 0) == errno.EPIPE:
257
+ return
258
+ # Since this runs in a daemon thread the resources it uses
259
+ # may be become unusable while the process is cleaning up.
260
+ # We ignore errors which happen after the process has
261
+ # started to cleanup.
262
+ if is_exiting():
263
+ info('error in queue thread: %s', e)
264
+ return
265
+ else:
266
+ # Since the object has not been sent in the queue, we need
267
+ # to decrease the size of the queue. The error acts as
268
+ # if the object had been silently removed from the queue
269
+ # and this step is necessary to have a properly working
270
+ # queue.
271
+ queue_sem.release()
272
+ onerror(e, obj)
273
+
274
+ @staticmethod
275
+ def _on_queue_feeder_error(e, obj):
276
+ """
277
+ Private API hook called when feeding data in the background thread
278
+ raises an exception. For overriding by concurrent.futures.
279
+ """
280
+ import traceback
281
+ traceback.print_exc()
282
+
283
+
284
+ _sentinel = object()
285
+
286
+ #
287
+ # A queue type which also supports join() and task_done() methods
288
+ #
289
+ # Note that if you do not call task_done() for each finished task then
290
+ # eventually the counter's semaphore may overflow causing Bad Things
291
+ # to happen.
292
+ #
293
+
294
+ class JoinableQueue(Queue):
295
+
296
+ def __init__(self, maxsize=0, *, ctx):
297
+ Queue.__init__(self, maxsize, ctx=ctx)
298
+ self._unfinished_tasks = ctx.Semaphore(0)
299
+ self._cond = ctx.Condition()
300
+
301
+ def __getstate__(self):
302
+ return Queue.__getstate__(self) + (self._cond, self._unfinished_tasks)
303
+
304
+ def __setstate__(self, state):
305
+ Queue.__setstate__(self, state[:-2])
306
+ self._cond, self._unfinished_tasks = state[-2:]
307
+
308
+ def put(self, obj, block=True, timeout=None):
309
+ if self._closed:
310
+ raise ValueError(f"Queue {self!r} is closed")
311
+ if not self._sem.acquire(block, timeout):
312
+ raise Full
313
+
314
+ with self._notempty, self._cond:
315
+ if self._thread is None:
316
+ self._start_thread()
317
+ self._buffer.append(obj)
318
+ self._unfinished_tasks.release()
319
+ self._notempty.notify()
320
+
321
+ def task_done(self):
322
+ with self._cond:
323
+ if not self._unfinished_tasks.acquire(False):
324
+ raise ValueError('task_done() called too many times')
325
+ if self._unfinished_tasks._semlock._is_zero():
326
+ self._cond.notify_all()
327
+
328
+ def join(self):
329
+ with self._cond:
330
+ if not self._unfinished_tasks._semlock._is_zero():
331
+ self._cond.wait()
332
+
333
+ #
334
+ # Simplified Queue type -- really just a locked pipe
335
+ #
336
+
337
+ class SimpleQueue(object):
338
+
339
+ def __init__(self, *, ctx):
340
+ self._reader, self._writer = connection.Pipe(duplex=False)
341
+ self._rlock = ctx.Lock()
342
+ self._poll = self._reader.poll
343
+ if sys.platform == 'win32':
344
+ self._wlock = None
345
+ else:
346
+ self._wlock = ctx.Lock()
347
+
348
+ def close(self):
349
+ self._reader.close()
350
+ self._writer.close()
351
+
352
+ def empty(self):
353
+ return not self._poll()
354
+
355
+ def __getstate__(self):
356
+ context.assert_spawning(self)
357
+ return (self._reader, self._writer, self._rlock, self._wlock)
358
+
359
+ def __setstate__(self, state):
360
+ (self._reader, self._writer, self._rlock, self._wlock) = state
361
+ self._poll = self._reader.poll
362
+
363
+ def get(self):
364
+ with self._rlock:
365
+ res = self._reader.recv_bytes()
366
+ # unserialize the data after having released the lock
367
+ return _ForkingPickler.loads(res)
368
+
369
+ def put(self, obj):
370
+ # serialize the data before acquiring the lock
371
+ obj = _ForkingPickler.dumps(obj)
372
+ if self._wlock is None:
373
+ # writes to a message oriented win32 pipe are atomic
374
+ self._writer.send_bytes(obj)
375
+ else:
376
+ with self._wlock:
377
+ self._writer.send_bytes(obj)
378
+
379
+ __class_getitem__ = classmethod(types.GenericAlias)
lib/python3.1/multiprocessing/reduction.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module which deals with pickling of objects.
3
+ #
4
+ # multiprocessing/reduction.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ from abc import ABCMeta
11
+ import copyreg
12
+ import functools
13
+ import io
14
+ import os
15
+ import pickle
16
+ import socket
17
+ import sys
18
+
19
+ from . import context
20
+
21
+ __all__ = ['send_handle', 'recv_handle', 'ForkingPickler', 'register', 'dump']
22
+
23
+
24
+ HAVE_SEND_HANDLE = (sys.platform == 'win32' or
25
+ (hasattr(socket, 'CMSG_LEN') and
26
+ hasattr(socket, 'SCM_RIGHTS') and
27
+ hasattr(socket.socket, 'sendmsg')))
28
+
29
+ #
30
+ # Pickler subclass
31
+ #
32
+
33
+ class ForkingPickler(pickle.Pickler):
34
+ '''Pickler subclass used by multiprocessing.'''
35
+ _extra_reducers = {}
36
+ _copyreg_dispatch_table = copyreg.dispatch_table
37
+
38
+ def __init__(self, *args):
39
+ super().__init__(*args)
40
+ self.dispatch_table = self._copyreg_dispatch_table.copy()
41
+ self.dispatch_table.update(self._extra_reducers)
42
+
43
+ @classmethod
44
+ def register(cls, type, reduce):
45
+ '''Register a reduce function for a type.'''
46
+ cls._extra_reducers[type] = reduce
47
+
48
+ @classmethod
49
+ def dumps(cls, obj, protocol=None):
50
+ buf = io.BytesIO()
51
+ cls(buf, protocol).dump(obj)
52
+ return buf.getbuffer()
53
+
54
+ loads = pickle.loads
55
+
56
+ register = ForkingPickler.register
57
+
58
+ def dump(obj, file, protocol=None):
59
+ '''Replacement for pickle.dump() using ForkingPickler.'''
60
+ ForkingPickler(file, protocol).dump(obj)
61
+
62
+ #
63
+ # Platform specific definitions
64
+ #
65
+
66
+ if sys.platform == 'win32':
67
+ # Windows
68
+ __all__ += ['DupHandle', 'duplicate', 'steal_handle']
69
+ import _winapi
70
+
71
+ def duplicate(handle, target_process=None, inheritable=False,
72
+ *, source_process=None):
73
+ '''Duplicate a handle. (target_process is a handle not a pid!)'''
74
+ current_process = _winapi.GetCurrentProcess()
75
+ if source_process is None:
76
+ source_process = current_process
77
+ if target_process is None:
78
+ target_process = current_process
79
+ return _winapi.DuplicateHandle(
80
+ source_process, handle, target_process,
81
+ 0, inheritable, _winapi.DUPLICATE_SAME_ACCESS)
82
+
83
+ def steal_handle(source_pid, handle):
84
+ '''Steal a handle from process identified by source_pid.'''
85
+ source_process_handle = _winapi.OpenProcess(
86
+ _winapi.PROCESS_DUP_HANDLE, False, source_pid)
87
+ try:
88
+ return _winapi.DuplicateHandle(
89
+ source_process_handle, handle,
90
+ _winapi.GetCurrentProcess(), 0, False,
91
+ _winapi.DUPLICATE_SAME_ACCESS | _winapi.DUPLICATE_CLOSE_SOURCE)
92
+ finally:
93
+ _winapi.CloseHandle(source_process_handle)
94
+
95
+ def send_handle(conn, handle, destination_pid):
96
+ '''Send a handle over a local connection.'''
97
+ dh = DupHandle(handle, _winapi.DUPLICATE_SAME_ACCESS, destination_pid)
98
+ conn.send(dh)
99
+
100
+ def recv_handle(conn):
101
+ '''Receive a handle over a local connection.'''
102
+ return conn.recv().detach()
103
+
104
+ class DupHandle(object):
105
+ '''Picklable wrapper for a handle.'''
106
+ def __init__(self, handle, access, pid=None):
107
+ if pid is None:
108
+ # We just duplicate the handle in the current process and
109
+ # let the receiving process steal the handle.
110
+ pid = os.getpid()
111
+ proc = _winapi.OpenProcess(_winapi.PROCESS_DUP_HANDLE, False, pid)
112
+ try:
113
+ self._handle = _winapi.DuplicateHandle(
114
+ _winapi.GetCurrentProcess(),
115
+ handle, proc, access, False, 0)
116
+ finally:
117
+ _winapi.CloseHandle(proc)
118
+ self._access = access
119
+ self._pid = pid
120
+
121
+ def detach(self):
122
+ '''Get the handle. This should only be called once.'''
123
+ # retrieve handle from process which currently owns it
124
+ if self._pid == os.getpid():
125
+ # The handle has already been duplicated for this process.
126
+ return self._handle
127
+ # We must steal the handle from the process whose pid is self._pid.
128
+ proc = _winapi.OpenProcess(_winapi.PROCESS_DUP_HANDLE, False,
129
+ self._pid)
130
+ try:
131
+ return _winapi.DuplicateHandle(
132
+ proc, self._handle, _winapi.GetCurrentProcess(),
133
+ self._access, False, _winapi.DUPLICATE_CLOSE_SOURCE)
134
+ finally:
135
+ _winapi.CloseHandle(proc)
136
+
137
+ else:
138
+ # Unix
139
+ __all__ += ['DupFd', 'sendfds', 'recvfds']
140
+ import array
141
+
142
+ # On MacOSX we should acknowledge receipt of fds -- see Issue14669
143
+ ACKNOWLEDGE = sys.platform == 'darwin'
144
+
145
+ def sendfds(sock, fds):
146
+ '''Send an array of fds over an AF_UNIX socket.'''
147
+ fds = array.array('i', fds)
148
+ msg = bytes([len(fds) % 256])
149
+ sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds)])
150
+ if ACKNOWLEDGE and sock.recv(1) != b'A':
151
+ raise RuntimeError('did not receive acknowledgement of fd')
152
+
153
+ def recvfds(sock, size):
154
+ '''Receive an array of fds over an AF_UNIX socket.'''
155
+ a = array.array('i')
156
+ bytes_size = a.itemsize * size
157
+ msg, ancdata, flags, addr = sock.recvmsg(1, socket.CMSG_SPACE(bytes_size))
158
+ if not msg and not ancdata:
159
+ raise EOFError
160
+ try:
161
+ if ACKNOWLEDGE:
162
+ sock.send(b'A')
163
+ if len(ancdata) != 1:
164
+ raise RuntimeError('received %d items of ancdata' %
165
+ len(ancdata))
166
+ cmsg_level, cmsg_type, cmsg_data = ancdata[0]
167
+ if (cmsg_level == socket.SOL_SOCKET and
168
+ cmsg_type == socket.SCM_RIGHTS):
169
+ if len(cmsg_data) % a.itemsize != 0:
170
+ raise ValueError
171
+ a.frombytes(cmsg_data)
172
+ if len(a) % 256 != msg[0]:
173
+ raise AssertionError(
174
+ "Len is {0:n} but msg[0] is {1!r}".format(
175
+ len(a), msg[0]))
176
+ return list(a)
177
+ except (ValueError, IndexError):
178
+ pass
179
+ raise RuntimeError('Invalid data received')
180
+
181
+ def send_handle(conn, handle, destination_pid):
182
+ '''Send a handle over a local connection.'''
183
+ with socket.fromfd(conn.fileno(), socket.AF_UNIX, socket.SOCK_STREAM) as s:
184
+ sendfds(s, [handle])
185
+
186
+ def recv_handle(conn):
187
+ '''Receive a handle over a local connection.'''
188
+ with socket.fromfd(conn.fileno(), socket.AF_UNIX, socket.SOCK_STREAM) as s:
189
+ return recvfds(s, 1)[0]
190
+
191
+ def DupFd(fd):
192
+ '''Return a wrapper for an fd.'''
193
+ popen_obj = context.get_spawning_popen()
194
+ if popen_obj is not None:
195
+ return popen_obj.DupFd(popen_obj.duplicate_for_child(fd))
196
+ elif HAVE_SEND_HANDLE:
197
+ from . import resource_sharer
198
+ return resource_sharer.DupFd(fd)
199
+ else:
200
+ raise ValueError('SCM_RIGHTS appears not to be available')
201
+
202
+ #
203
+ # Try making some callable types picklable
204
+ #
205
+
206
+ def _reduce_method(m):
207
+ if m.__self__ is None:
208
+ return getattr, (m.__class__, m.__func__.__name__)
209
+ else:
210
+ return getattr, (m.__self__, m.__func__.__name__)
211
+ class _C:
212
+ def f(self):
213
+ pass
214
+ register(type(_C().f), _reduce_method)
215
+
216
+
217
+ def _reduce_method_descriptor(m):
218
+ return getattr, (m.__objclass__, m.__name__)
219
+ register(type(list.append), _reduce_method_descriptor)
220
+ register(type(int.__add__), _reduce_method_descriptor)
221
+
222
+
223
+ def _reduce_partial(p):
224
+ return _rebuild_partial, (p.func, p.args, p.keywords or {})
225
+ def _rebuild_partial(func, args, keywords):
226
+ return functools.partial(func, *args, **keywords)
227
+ register(functools.partial, _reduce_partial)
228
+
229
+ #
230
+ # Make sockets picklable
231
+ #
232
+
233
+ if sys.platform == 'win32':
234
+ def _reduce_socket(s):
235
+ from .resource_sharer import DupSocket
236
+ return _rebuild_socket, (DupSocket(s),)
237
+ def _rebuild_socket(ds):
238
+ return ds.detach()
239
+ register(socket.socket, _reduce_socket)
240
+
241
+ else:
242
+ def _reduce_socket(s):
243
+ df = DupFd(s.fileno())
244
+ return _rebuild_socket, (df, s.family, s.type, s.proto)
245
+ def _rebuild_socket(df, family, type, proto):
246
+ fd = df.detach()
247
+ return socket.socket(family, type, proto, fileno=fd)
248
+ register(socket.socket, _reduce_socket)
249
+
250
+
251
+ class AbstractReducer(metaclass=ABCMeta):
252
+ '''Abstract base class for use in implementing a Reduction class
253
+ suitable for use in replacing the standard reduction mechanism
254
+ used in multiprocessing.'''
255
+ ForkingPickler = ForkingPickler
256
+ register = register
257
+ dump = dump
258
+ send_handle = send_handle
259
+ recv_handle = recv_handle
260
+
261
+ if sys.platform == 'win32':
262
+ steal_handle = steal_handle
263
+ duplicate = duplicate
264
+ DupHandle = DupHandle
265
+ else:
266
+ sendfds = sendfds
267
+ recvfds = recvfds
268
+ DupFd = DupFd
269
+
270
+ _reduce_method = _reduce_method
271
+ _reduce_method_descriptor = _reduce_method_descriptor
272
+ _rebuild_partial = _rebuild_partial
273
+ _reduce_socket = _reduce_socket
274
+ _rebuild_socket = _rebuild_socket
275
+
276
+ def __init__(self, *args):
277
+ register(type(_C().f), _reduce_method)
278
+ register(type(list.append), _reduce_method_descriptor)
279
+ register(type(int.__add__), _reduce_method_descriptor)
280
+ register(functools.partial, _reduce_partial)
281
+ register(socket.socket, _reduce_socket)
lib/python3.1/multiprocessing/resource_sharer.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # We use a background thread for sharing fds on Unix, and for sharing sockets on
3
+ # Windows.
4
+ #
5
+ # A client which wants to pickle a resource registers it with the resource
6
+ # sharer and gets an identifier in return. The unpickling process will connect
7
+ # to the resource sharer, sends the identifier and its pid, and then receives
8
+ # the resource.
9
+ #
10
+
11
+ import os
12
+ import signal
13
+ import socket
14
+ import sys
15
+ import threading
16
+
17
+ from . import process
18
+ from .context import reduction
19
+ from . import util
20
+
21
+ __all__ = ['stop']
22
+
23
+
24
+ if sys.platform == 'win32':
25
+ __all__ += ['DupSocket']
26
+
27
+ class DupSocket(object):
28
+ '''Picklable wrapper for a socket.'''
29
+ def __init__(self, sock):
30
+ new_sock = sock.dup()
31
+ def send(conn, pid):
32
+ share = new_sock.share(pid)
33
+ conn.send_bytes(share)
34
+ self._id = _resource_sharer.register(send, new_sock.close)
35
+
36
+ def detach(self):
37
+ '''Get the socket. This should only be called once.'''
38
+ with _resource_sharer.get_connection(self._id) as conn:
39
+ share = conn.recv_bytes()
40
+ return socket.fromshare(share)
41
+
42
+ else:
43
+ __all__ += ['DupFd']
44
+
45
+ class DupFd(object):
46
+ '''Wrapper for fd which can be used at any time.'''
47
+ def __init__(self, fd):
48
+ new_fd = os.dup(fd)
49
+ def send(conn, pid):
50
+ reduction.send_handle(conn, new_fd, pid)
51
+ def close():
52
+ os.close(new_fd)
53
+ self._id = _resource_sharer.register(send, close)
54
+
55
+ def detach(self):
56
+ '''Get the fd. This should only be called once.'''
57
+ with _resource_sharer.get_connection(self._id) as conn:
58
+ return reduction.recv_handle(conn)
59
+
60
+
61
+ class _ResourceSharer(object):
62
+ '''Manager for resources using background thread.'''
63
+ def __init__(self):
64
+ self._key = 0
65
+ self._cache = {}
66
+ self._lock = threading.Lock()
67
+ self._listener = None
68
+ self._address = None
69
+ self._thread = None
70
+ util.register_after_fork(self, _ResourceSharer._afterfork)
71
+
72
+ def register(self, send, close):
73
+ '''Register resource, returning an identifier.'''
74
+ with self._lock:
75
+ if self._address is None:
76
+ self._start()
77
+ self._key += 1
78
+ self._cache[self._key] = (send, close)
79
+ return (self._address, self._key)
80
+
81
+ @staticmethod
82
+ def get_connection(ident):
83
+ '''Return connection from which to receive identified resource.'''
84
+ from .connection import Client
85
+ address, key = ident
86
+ c = Client(address, authkey=process.current_process().authkey)
87
+ c.send((key, os.getpid()))
88
+ return c
89
+
90
+ def stop(self, timeout=None):
91
+ '''Stop the background thread and clear registered resources.'''
92
+ from .connection import Client
93
+ with self._lock:
94
+ if self._address is not None:
95
+ c = Client(self._address,
96
+ authkey=process.current_process().authkey)
97
+ c.send(None)
98
+ c.close()
99
+ self._thread.join(timeout)
100
+ if self._thread.is_alive():
101
+ util.sub_warning('_ResourceSharer thread did '
102
+ 'not stop when asked')
103
+ self._listener.close()
104
+ self._thread = None
105
+ self._address = None
106
+ self._listener = None
107
+ for key, (send, close) in self._cache.items():
108
+ close()
109
+ self._cache.clear()
110
+
111
+ def _afterfork(self):
112
+ for key, (send, close) in self._cache.items():
113
+ close()
114
+ self._cache.clear()
115
+ self._lock._at_fork_reinit()
116
+ if self._listener is not None:
117
+ self._listener.close()
118
+ self._listener = None
119
+ self._address = None
120
+ self._thread = None
121
+
122
+ def _start(self):
123
+ from .connection import Listener
124
+ assert self._listener is None, "Already have Listener"
125
+ util.debug('starting listener and thread for sending handles')
126
+ self._listener = Listener(authkey=process.current_process().authkey)
127
+ self._address = self._listener.address
128
+ t = threading.Thread(target=self._serve)
129
+ t.daemon = True
130
+ t.start()
131
+ self._thread = t
132
+
133
+ def _serve(self):
134
+ if hasattr(signal, 'pthread_sigmask'):
135
+ signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
136
+ while 1:
137
+ try:
138
+ with self._listener.accept() as conn:
139
+ msg = conn.recv()
140
+ if msg is None:
141
+ break
142
+ key, destination_pid = msg
143
+ send, close = self._cache.pop(key)
144
+ try:
145
+ send(conn, destination_pid)
146
+ finally:
147
+ close()
148
+ except:
149
+ if not util.is_exiting():
150
+ sys.excepthook(*sys.exc_info())
151
+
152
+
153
+ _resource_sharer = _ResourceSharer()
154
+ stop = _resource_sharer.stop
lib/python3.1/multiprocessing/resource_tracker.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###############################################################################
2
+ # Server process to keep track of unlinked resources (like shared memory
3
+ # segments, semaphores etc.) and clean them.
4
+ #
5
+ # On Unix we run a server process which keeps track of unlinked
6
+ # resources. The server ignores SIGINT and SIGTERM and reads from a
7
+ # pipe. Every other process of the program has a copy of the writable
8
+ # end of the pipe, so we get EOF when all other processes have exited.
9
+ # Then the server process unlinks any remaining resource names.
10
+ #
11
+ # This is important because there may be system limits for such resources: for
12
+ # instance, the system only supports a limited number of named semaphores, and
13
+ # shared-memory segments live in the RAM. If a python process leaks such a
14
+ # resource, this resource will not be removed till the next reboot. Without
15
+ # this resource tracker process, "killall python" would probably leave unlinked
16
+ # resources.
17
+
18
+ import os
19
+ import signal
20
+ import sys
21
+ import threading
22
+ import warnings
23
+
24
+ from . import spawn
25
+ from . import util
26
+
27
+ __all__ = ['ensure_running', 'register', 'unregister']
28
+
29
+ _HAVE_SIGMASK = hasattr(signal, 'pthread_sigmask')
30
+ _IGNORED_SIGNALS = (signal.SIGINT, signal.SIGTERM)
31
+
32
+ _CLEANUP_FUNCS = {
33
+ 'noop': lambda: None,
34
+ }
35
+
36
+ if os.name == 'posix':
37
+ import _multiprocessing
38
+ import _posixshmem
39
+
40
+ # Use sem_unlink() to clean up named semaphores.
41
+ #
42
+ # sem_unlink() may be missing if the Python build process detected the
43
+ # absence of POSIX named semaphores. In that case, no named semaphores were
44
+ # ever opened, so no cleanup would be necessary.
45
+ if hasattr(_multiprocessing, 'sem_unlink'):
46
+ _CLEANUP_FUNCS.update({
47
+ 'semaphore': _multiprocessing.sem_unlink,
48
+ })
49
+ _CLEANUP_FUNCS.update({
50
+ 'shared_memory': _posixshmem.shm_unlink,
51
+ })
52
+
53
+
54
+ class ResourceTracker(object):
55
+
56
+ def __init__(self):
57
+ self._lock = threading.Lock()
58
+ self._fd = None
59
+ self._pid = None
60
+
61
+ def _stop(self):
62
+ with self._lock:
63
+ if self._fd is None:
64
+ # not running
65
+ return
66
+
67
+ # closing the "alive" file descriptor stops main()
68
+ os.close(self._fd)
69
+ self._fd = None
70
+
71
+ os.waitpid(self._pid, 0)
72
+ self._pid = None
73
+
74
+ def getfd(self):
75
+ self.ensure_running()
76
+ return self._fd
77
+
78
+ def ensure_running(self):
79
+ '''Make sure that resource tracker process is running.
80
+
81
+ This can be run from any process. Usually a child process will use
82
+ the resource created by its parent.'''
83
+ with self._lock:
84
+ if self._fd is not None:
85
+ # resource tracker was launched before, is it still running?
86
+ if self._check_alive():
87
+ # => still alive
88
+ return
89
+ # => dead, launch it again
90
+ os.close(self._fd)
91
+
92
+ # Clean-up to avoid dangling processes.
93
+ try:
94
+ # _pid can be None if this process is a child from another
95
+ # python process, which has started the resource_tracker.
96
+ if self._pid is not None:
97
+ os.waitpid(self._pid, 0)
98
+ except ChildProcessError:
99
+ # The resource_tracker has already been terminated.
100
+ pass
101
+ self._fd = None
102
+ self._pid = None
103
+
104
+ warnings.warn('resource_tracker: process died unexpectedly, '
105
+ 'relaunching. Some resources might leak.')
106
+
107
+ fds_to_pass = []
108
+ try:
109
+ fds_to_pass.append(sys.stderr.fileno())
110
+ except Exception:
111
+ pass
112
+ cmd = 'from multiprocessing.resource_tracker import main;main(%d)'
113
+ r, w = os.pipe()
114
+ try:
115
+ fds_to_pass.append(r)
116
+ # process will out live us, so no need to wait on pid
117
+ exe = spawn.get_executable()
118
+ args = [exe] + util._args_from_interpreter_flags()
119
+ args += ['-c', cmd % r]
120
+ # bpo-33613: Register a signal mask that will block the signals.
121
+ # This signal mask will be inherited by the child that is going
122
+ # to be spawned and will protect the child from a race condition
123
+ # that can make the child die before it registers signal handlers
124
+ # for SIGINT and SIGTERM. The mask is unregistered after spawning
125
+ # the child.
126
+ try:
127
+ if _HAVE_SIGMASK:
128
+ signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS)
129
+ pid = util.spawnv_passfds(exe, args, fds_to_pass)
130
+ finally:
131
+ if _HAVE_SIGMASK:
132
+ signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS)
133
+ except:
134
+ os.close(w)
135
+ raise
136
+ else:
137
+ self._fd = w
138
+ self._pid = pid
139
+ finally:
140
+ os.close(r)
141
+
142
+ def _check_alive(self):
143
+ '''Check that the pipe has not been closed by sending a probe.'''
144
+ try:
145
+ # We cannot use send here as it calls ensure_running, creating
146
+ # a cycle.
147
+ os.write(self._fd, b'PROBE:0:noop\n')
148
+ except OSError:
149
+ return False
150
+ else:
151
+ return True
152
+
153
+ def register(self, name, rtype):
154
+ '''Register name of resource with resource tracker.'''
155
+ self._send('REGISTER', name, rtype)
156
+
157
+ def unregister(self, name, rtype):
158
+ '''Unregister name of resource with resource tracker.'''
159
+ self._send('UNREGISTER', name, rtype)
160
+
161
+ def _send(self, cmd, name, rtype):
162
+ self.ensure_running()
163
+ msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii')
164
+ if len(msg) > 512:
165
+ # posix guarantees that writes to a pipe of less than PIPE_BUF
166
+ # bytes are atomic, and that PIPE_BUF >= 512
167
+ raise ValueError('msg too long')
168
+ nbytes = os.write(self._fd, msg)
169
+ assert nbytes == len(msg), "nbytes {0:n} but len(msg) {1:n}".format(
170
+ nbytes, len(msg))
171
+
172
+
173
+ _resource_tracker = ResourceTracker()
174
+ ensure_running = _resource_tracker.ensure_running
175
+ register = _resource_tracker.register
176
+ unregister = _resource_tracker.unregister
177
+ getfd = _resource_tracker.getfd
178
+
179
+ def main(fd):
180
+ '''Run resource tracker.'''
181
+ # protect the process from ^C and "killall python" etc
182
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
183
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
184
+ if _HAVE_SIGMASK:
185
+ signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS)
186
+
187
+ for f in (sys.stdin, sys.stdout):
188
+ try:
189
+ f.close()
190
+ except Exception:
191
+ pass
192
+
193
+ cache = {rtype: set() for rtype in _CLEANUP_FUNCS.keys()}
194
+ try:
195
+ # keep track of registered/unregistered resources
196
+ with open(fd, 'rb') as f:
197
+ for line in f:
198
+ try:
199
+ cmd, name, rtype = line.strip().decode('ascii').split(':')
200
+ cleanup_func = _CLEANUP_FUNCS.get(rtype, None)
201
+ if cleanup_func is None:
202
+ raise ValueError(
203
+ f'Cannot register {name} for automatic cleanup: '
204
+ f'unknown resource type {rtype}')
205
+
206
+ if cmd == 'REGISTER':
207
+ cache[rtype].add(name)
208
+ elif cmd == 'UNREGISTER':
209
+ cache[rtype].remove(name)
210
+ elif cmd == 'PROBE':
211
+ pass
212
+ else:
213
+ raise RuntimeError('unrecognized command %r' % cmd)
214
+ except Exception:
215
+ try:
216
+ sys.excepthook(*sys.exc_info())
217
+ except:
218
+ pass
219
+ finally:
220
+ # all processes have terminated; cleanup any remaining resources
221
+ for rtype, rtype_cache in cache.items():
222
+ if rtype_cache:
223
+ try:
224
+ warnings.warn('resource_tracker: There appear to be %d '
225
+ 'leaked %s objects to clean up at shutdown' %
226
+ (len(rtype_cache), rtype))
227
+ except Exception:
228
+ pass
229
+ for name in rtype_cache:
230
+ # For some reason the process which created and registered this
231
+ # resource has failed to unregister it. Presumably it has
232
+ # died. We therefore unlink it.
233
+ try:
234
+ try:
235
+ _CLEANUP_FUNCS[rtype](name)
236
+ except Exception as e:
237
+ warnings.warn('resource_tracker: %r: %s' % (name, e))
238
+ finally:
239
+ pass
lib/python3.1/multiprocessing/shared_memory.py ADDED
@@ -0,0 +1,534 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Provides shared memory for direct access across processes.
2
+
3
+ The API of this package is currently provisional. Refer to the
4
+ documentation for details.
5
+ """
6
+
7
+
8
+ __all__ = [ 'SharedMemory', 'ShareableList' ]
9
+
10
+
11
+ from functools import partial
12
+ import mmap
13
+ import os
14
+ import errno
15
+ import struct
16
+ import secrets
17
+ import types
18
+
19
+ if os.name == "nt":
20
+ import _winapi
21
+ _USE_POSIX = False
22
+ else:
23
+ import _posixshmem
24
+ _USE_POSIX = True
25
+
26
+ from . import resource_tracker
27
+
28
+ _O_CREX = os.O_CREAT | os.O_EXCL
29
+
30
+ # FreeBSD (and perhaps other BSDs) limit names to 14 characters.
31
+ _SHM_SAFE_NAME_LENGTH = 14
32
+
33
+ # Shared memory block name prefix
34
+ if _USE_POSIX:
35
+ _SHM_NAME_PREFIX = '/psm_'
36
+ else:
37
+ _SHM_NAME_PREFIX = 'wnsm_'
38
+
39
+
40
+ def _make_filename():
41
+ "Create a random filename for the shared memory object."
42
+ # number of random bytes to use for name
43
+ nbytes = (_SHM_SAFE_NAME_LENGTH - len(_SHM_NAME_PREFIX)) // 2
44
+ assert nbytes >= 2, '_SHM_NAME_PREFIX too long'
45
+ name = _SHM_NAME_PREFIX + secrets.token_hex(nbytes)
46
+ assert len(name) <= _SHM_SAFE_NAME_LENGTH
47
+ return name
48
+
49
+
50
+ class SharedMemory:
51
+ """Creates a new shared memory block or attaches to an existing
52
+ shared memory block.
53
+
54
+ Every shared memory block is assigned a unique name. This enables
55
+ one process to create a shared memory block with a particular name
56
+ so that a different process can attach to that same shared memory
57
+ block using that same name.
58
+
59
+ As a resource for sharing data across processes, shared memory blocks
60
+ may outlive the original process that created them. When one process
61
+ no longer needs access to a shared memory block that might still be
62
+ needed by other processes, the close() method should be called.
63
+ When a shared memory block is no longer needed by any process, the
64
+ unlink() method should be called to ensure proper cleanup."""
65
+
66
+ # Defaults; enables close() and unlink() to run without errors.
67
+ _name = None
68
+ _fd = -1
69
+ _mmap = None
70
+ _buf = None
71
+ _flags = os.O_RDWR
72
+ _mode = 0o600
73
+ _prepend_leading_slash = True if _USE_POSIX else False
74
+
75
+ def __init__(self, name=None, create=False, size=0):
76
+ if not size >= 0:
77
+ raise ValueError("'size' must be a positive integer")
78
+ if create:
79
+ self._flags = _O_CREX | os.O_RDWR
80
+ if size == 0:
81
+ raise ValueError("'size' must be a positive number different from zero")
82
+ if name is None and not self._flags & os.O_EXCL:
83
+ raise ValueError("'name' can only be None if create=True")
84
+
85
+ if _USE_POSIX:
86
+
87
+ # POSIX Shared Memory
88
+
89
+ if name is None:
90
+ while True:
91
+ name = _make_filename()
92
+ try:
93
+ self._fd = _posixshmem.shm_open(
94
+ name,
95
+ self._flags,
96
+ mode=self._mode
97
+ )
98
+ except FileExistsError:
99
+ continue
100
+ self._name = name
101
+ break
102
+ else:
103
+ name = "/" + name if self._prepend_leading_slash else name
104
+ self._fd = _posixshmem.shm_open(
105
+ name,
106
+ self._flags,
107
+ mode=self._mode
108
+ )
109
+ self._name = name
110
+ try:
111
+ if create and size:
112
+ os.ftruncate(self._fd, size)
113
+ stats = os.fstat(self._fd)
114
+ size = stats.st_size
115
+ self._mmap = mmap.mmap(self._fd, size)
116
+ except OSError:
117
+ self.unlink()
118
+ raise
119
+
120
+ resource_tracker.register(self._name, "shared_memory")
121
+
122
+ else:
123
+
124
+ # Windows Named Shared Memory
125
+
126
+ if create:
127
+ while True:
128
+ temp_name = _make_filename() if name is None else name
129
+ # Create and reserve shared memory block with this name
130
+ # until it can be attached to by mmap.
131
+ h_map = _winapi.CreateFileMapping(
132
+ _winapi.INVALID_HANDLE_VALUE,
133
+ _winapi.NULL,
134
+ _winapi.PAGE_READWRITE,
135
+ (size >> 32) & 0xFFFFFFFF,
136
+ size & 0xFFFFFFFF,
137
+ temp_name
138
+ )
139
+ try:
140
+ last_error_code = _winapi.GetLastError()
141
+ if last_error_code == _winapi.ERROR_ALREADY_EXISTS:
142
+ if name is not None:
143
+ raise FileExistsError(
144
+ errno.EEXIST,
145
+ os.strerror(errno.EEXIST),
146
+ name,
147
+ _winapi.ERROR_ALREADY_EXISTS
148
+ )
149
+ else:
150
+ continue
151
+ self._mmap = mmap.mmap(-1, size, tagname=temp_name)
152
+ finally:
153
+ _winapi.CloseHandle(h_map)
154
+ self._name = temp_name
155
+ break
156
+
157
+ else:
158
+ self._name = name
159
+ # Dynamically determine the existing named shared memory
160
+ # block's size which is likely a multiple of mmap.PAGESIZE.
161
+ h_map = _winapi.OpenFileMapping(
162
+ _winapi.FILE_MAP_READ,
163
+ False,
164
+ name
165
+ )
166
+ try:
167
+ p_buf = _winapi.MapViewOfFile(
168
+ h_map,
169
+ _winapi.FILE_MAP_READ,
170
+ 0,
171
+ 0,
172
+ 0
173
+ )
174
+ finally:
175
+ _winapi.CloseHandle(h_map)
176
+ try:
177
+ size = _winapi.VirtualQuerySize(p_buf)
178
+ finally:
179
+ _winapi.UnmapViewOfFile(p_buf)
180
+ self._mmap = mmap.mmap(-1, size, tagname=name)
181
+
182
+ self._size = size
183
+ self._buf = memoryview(self._mmap)
184
+
185
+ def __del__(self):
186
+ try:
187
+ self.close()
188
+ except OSError:
189
+ pass
190
+
191
+ def __reduce__(self):
192
+ return (
193
+ self.__class__,
194
+ (
195
+ self.name,
196
+ False,
197
+ self.size,
198
+ ),
199
+ )
200
+
201
+ def __repr__(self):
202
+ return f'{self.__class__.__name__}({self.name!r}, size={self.size})'
203
+
204
+ @property
205
+ def buf(self):
206
+ "A memoryview of contents of the shared memory block."
207
+ return self._buf
208
+
209
+ @property
210
+ def name(self):
211
+ "Unique name that identifies the shared memory block."
212
+ reported_name = self._name
213
+ if _USE_POSIX and self._prepend_leading_slash:
214
+ if self._name.startswith("/"):
215
+ reported_name = self._name[1:]
216
+ return reported_name
217
+
218
+ @property
219
+ def size(self):
220
+ "Size in bytes."
221
+ return self._size
222
+
223
+ def close(self):
224
+ """Closes access to the shared memory from this instance but does
225
+ not destroy the shared memory block."""
226
+ if self._buf is not None:
227
+ self._buf.release()
228
+ self._buf = None
229
+ if self._mmap is not None:
230
+ self._mmap.close()
231
+ self._mmap = None
232
+ if _USE_POSIX and self._fd >= 0:
233
+ os.close(self._fd)
234
+ self._fd = -1
235
+
236
+ def unlink(self):
237
+ """Requests that the underlying shared memory block be destroyed.
238
+
239
+ In order to ensure proper cleanup of resources, unlink should be
240
+ called once (and only once) across all processes which have access
241
+ to the shared memory block."""
242
+ if _USE_POSIX and self._name:
243
+ _posixshmem.shm_unlink(self._name)
244
+ resource_tracker.unregister(self._name, "shared_memory")
245
+
246
+
247
+ _encoding = "utf8"
248
+
249
+ class ShareableList:
250
+ """Pattern for a mutable list-like object shareable via a shared
251
+ memory block. It differs from the built-in list type in that these
252
+ lists can not change their overall length (i.e. no append, insert,
253
+ etc.)
254
+
255
+ Because values are packed into a memoryview as bytes, the struct
256
+ packing format for any storable value must require no more than 8
257
+ characters to describe its format."""
258
+
259
+ # The shared memory area is organized as follows:
260
+ # - 8 bytes: number of items (N) as a 64-bit integer
261
+ # - (N + 1) * 8 bytes: offsets of each element from the start of the
262
+ # data area
263
+ # - K bytes: the data area storing item values (with encoding and size
264
+ # depending on their respective types)
265
+ # - N * 8 bytes: `struct` format string for each element
266
+ # - N bytes: index into _back_transforms_mapping for each element
267
+ # (for reconstructing the corresponding Python value)
268
+ _types_mapping = {
269
+ int: "q",
270
+ float: "d",
271
+ bool: "xxxxxxx?",
272
+ str: "%ds",
273
+ bytes: "%ds",
274
+ None.__class__: "xxxxxx?x",
275
+ }
276
+ _alignment = 8
277
+ _back_transforms_mapping = {
278
+ 0: lambda value: value, # int, float, bool
279
+ 1: lambda value: value.rstrip(b'\x00').decode(_encoding), # str
280
+ 2: lambda value: value.rstrip(b'\x00'), # bytes
281
+ 3: lambda _value: None, # None
282
+ }
283
+
284
+ @staticmethod
285
+ def _extract_recreation_code(value):
286
+ """Used in concert with _back_transforms_mapping to convert values
287
+ into the appropriate Python objects when retrieving them from
288
+ the list as well as when storing them."""
289
+ if not isinstance(value, (str, bytes, None.__class__)):
290
+ return 0
291
+ elif isinstance(value, str):
292
+ return 1
293
+ elif isinstance(value, bytes):
294
+ return 2
295
+ else:
296
+ return 3 # NoneType
297
+
298
+ def __init__(self, sequence=None, *, name=None):
299
+ if name is None or sequence is not None:
300
+ sequence = sequence or ()
301
+ _formats = [
302
+ self._types_mapping[type(item)]
303
+ if not isinstance(item, (str, bytes))
304
+ else self._types_mapping[type(item)] % (
305
+ self._alignment * (len(item) // self._alignment + 1),
306
+ )
307
+ for item in sequence
308
+ ]
309
+ self._list_len = len(_formats)
310
+ assert sum(len(fmt) <= 8 for fmt in _formats) == self._list_len
311
+ offset = 0
312
+ # The offsets of each list element into the shared memory's
313
+ # data area (0 meaning the start of the data area, not the start
314
+ # of the shared memory area).
315
+ self._allocated_offsets = [0]
316
+ for fmt in _formats:
317
+ offset += self._alignment if fmt[-1] != "s" else int(fmt[:-1])
318
+ self._allocated_offsets.append(offset)
319
+ _recreation_codes = [
320
+ self._extract_recreation_code(item) for item in sequence
321
+ ]
322
+ requested_size = struct.calcsize(
323
+ "q" + self._format_size_metainfo +
324
+ "".join(_formats) +
325
+ self._format_packing_metainfo +
326
+ self._format_back_transform_codes
327
+ )
328
+
329
+ self.shm = SharedMemory(name, create=True, size=requested_size)
330
+ else:
331
+ self.shm = SharedMemory(name)
332
+
333
+ if sequence is not None:
334
+ _enc = _encoding
335
+ struct.pack_into(
336
+ "q" + self._format_size_metainfo,
337
+ self.shm.buf,
338
+ 0,
339
+ self._list_len,
340
+ *(self._allocated_offsets)
341
+ )
342
+ struct.pack_into(
343
+ "".join(_formats),
344
+ self.shm.buf,
345
+ self._offset_data_start,
346
+ *(v.encode(_enc) if isinstance(v, str) else v for v in sequence)
347
+ )
348
+ struct.pack_into(
349
+ self._format_packing_metainfo,
350
+ self.shm.buf,
351
+ self._offset_packing_formats,
352
+ *(v.encode(_enc) for v in _formats)
353
+ )
354
+ struct.pack_into(
355
+ self._format_back_transform_codes,
356
+ self.shm.buf,
357
+ self._offset_back_transform_codes,
358
+ *(_recreation_codes)
359
+ )
360
+
361
+ else:
362
+ self._list_len = len(self) # Obtains size from offset 0 in buffer.
363
+ self._allocated_offsets = list(
364
+ struct.unpack_from(
365
+ self._format_size_metainfo,
366
+ self.shm.buf,
367
+ 1 * 8
368
+ )
369
+ )
370
+
371
+ def _get_packing_format(self, position):
372
+ "Gets the packing format for a single value stored in the list."
373
+ position = position if position >= 0 else position + self._list_len
374
+ if (position >= self._list_len) or (self._list_len < 0):
375
+ raise IndexError("Requested position out of range.")
376
+
377
+ v = struct.unpack_from(
378
+ "8s",
379
+ self.shm.buf,
380
+ self._offset_packing_formats + position * 8
381
+ )[0]
382
+ fmt = v.rstrip(b'\x00')
383
+ fmt_as_str = fmt.decode(_encoding)
384
+
385
+ return fmt_as_str
386
+
387
+ def _get_back_transform(self, position):
388
+ "Gets the back transformation function for a single value."
389
+
390
+ if (position >= self._list_len) or (self._list_len < 0):
391
+ raise IndexError("Requested position out of range.")
392
+
393
+ transform_code = struct.unpack_from(
394
+ "b",
395
+ self.shm.buf,
396
+ self._offset_back_transform_codes + position
397
+ )[0]
398
+ transform_function = self._back_transforms_mapping[transform_code]
399
+
400
+ return transform_function
401
+
402
+ def _set_packing_format_and_transform(self, position, fmt_as_str, value):
403
+ """Sets the packing format and back transformation code for a
404
+ single value in the list at the specified position."""
405
+
406
+ if (position >= self._list_len) or (self._list_len < 0):
407
+ raise IndexError("Requested position out of range.")
408
+
409
+ struct.pack_into(
410
+ "8s",
411
+ self.shm.buf,
412
+ self._offset_packing_formats + position * 8,
413
+ fmt_as_str.encode(_encoding)
414
+ )
415
+
416
+ transform_code = self._extract_recreation_code(value)
417
+ struct.pack_into(
418
+ "b",
419
+ self.shm.buf,
420
+ self._offset_back_transform_codes + position,
421
+ transform_code
422
+ )
423
+
424
+ def __getitem__(self, position):
425
+ position = position if position >= 0 else position + self._list_len
426
+ try:
427
+ offset = self._offset_data_start + self._allocated_offsets[position]
428
+ (v,) = struct.unpack_from(
429
+ self._get_packing_format(position),
430
+ self.shm.buf,
431
+ offset
432
+ )
433
+ except IndexError:
434
+ raise IndexError("index out of range")
435
+
436
+ back_transform = self._get_back_transform(position)
437
+ v = back_transform(v)
438
+
439
+ return v
440
+
441
+ def __setitem__(self, position, value):
442
+ position = position if position >= 0 else position + self._list_len
443
+ try:
444
+ item_offset = self._allocated_offsets[position]
445
+ offset = self._offset_data_start + item_offset
446
+ current_format = self._get_packing_format(position)
447
+ except IndexError:
448
+ raise IndexError("assignment index out of range")
449
+
450
+ if not isinstance(value, (str, bytes)):
451
+ new_format = self._types_mapping[type(value)]
452
+ encoded_value = value
453
+ else:
454
+ allocated_length = self._allocated_offsets[position + 1] - item_offset
455
+
456
+ encoded_value = (value.encode(_encoding)
457
+ if isinstance(value, str) else value)
458
+ if len(encoded_value) > allocated_length:
459
+ raise ValueError("bytes/str item exceeds available storage")
460
+ if current_format[-1] == "s":
461
+ new_format = current_format
462
+ else:
463
+ new_format = self._types_mapping[str] % (
464
+ allocated_length,
465
+ )
466
+
467
+ self._set_packing_format_and_transform(
468
+ position,
469
+ new_format,
470
+ value
471
+ )
472
+ struct.pack_into(new_format, self.shm.buf, offset, encoded_value)
473
+
474
+ def __reduce__(self):
475
+ return partial(self.__class__, name=self.shm.name), ()
476
+
477
+ def __len__(self):
478
+ return struct.unpack_from("q", self.shm.buf, 0)[0]
479
+
480
+ def __repr__(self):
481
+ return f'{self.__class__.__name__}({list(self)}, name={self.shm.name!r})'
482
+
483
+ @property
484
+ def format(self):
485
+ "The struct packing format used by all currently stored items."
486
+ return "".join(
487
+ self._get_packing_format(i) for i in range(self._list_len)
488
+ )
489
+
490
+ @property
491
+ def _format_size_metainfo(self):
492
+ "The struct packing format used for the items' storage offsets."
493
+ return "q" * (self._list_len + 1)
494
+
495
+ @property
496
+ def _format_packing_metainfo(self):
497
+ "The struct packing format used for the items' packing formats."
498
+ return "8s" * self._list_len
499
+
500
+ @property
501
+ def _format_back_transform_codes(self):
502
+ "The struct packing format used for the items' back transforms."
503
+ return "b" * self._list_len
504
+
505
+ @property
506
+ def _offset_data_start(self):
507
+ # - 8 bytes for the list length
508
+ # - (N + 1) * 8 bytes for the element offsets
509
+ return (self._list_len + 2) * 8
510
+
511
+ @property
512
+ def _offset_packing_formats(self):
513
+ return self._offset_data_start + self._allocated_offsets[-1]
514
+
515
+ @property
516
+ def _offset_back_transform_codes(self):
517
+ return self._offset_packing_formats + self._list_len * 8
518
+
519
+ def count(self, value):
520
+ "L.count(value) -> integer -- return number of occurrences of value."
521
+
522
+ return sum(value == entry for entry in self)
523
+
524
+ def index(self, value):
525
+ """L.index(value) -> integer -- return first index of value.
526
+ Raises ValueError if the value is not present."""
527
+
528
+ for position, entry in enumerate(self):
529
+ if value == entry:
530
+ return position
531
+ else:
532
+ raise ValueError(f"{value!r} not in this container")
533
+
534
+ __class_getitem__ = classmethod(types.GenericAlias)
lib/python3.1/multiprocessing/sharedctypes.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module which supports allocation of ctypes objects from shared memory
3
+ #
4
+ # multiprocessing/sharedctypes.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ import ctypes
11
+ import weakref
12
+
13
+ from . import heap
14
+ from . import get_context
15
+
16
+ from .context import reduction, assert_spawning
17
+ _ForkingPickler = reduction.ForkingPickler
18
+
19
+ __all__ = ['RawValue', 'RawArray', 'Value', 'Array', 'copy', 'synchronized']
20
+
21
+ #
22
+ #
23
+ #
24
+
25
+ typecode_to_type = {
26
+ 'c': ctypes.c_char, 'u': ctypes.c_wchar,
27
+ 'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
28
+ 'h': ctypes.c_short, 'H': ctypes.c_ushort,
29
+ 'i': ctypes.c_int, 'I': ctypes.c_uint,
30
+ 'l': ctypes.c_long, 'L': ctypes.c_ulong,
31
+ 'q': ctypes.c_longlong, 'Q': ctypes.c_ulonglong,
32
+ 'f': ctypes.c_float, 'd': ctypes.c_double
33
+ }
34
+
35
+ #
36
+ #
37
+ #
38
+
39
+ def _new_value(type_):
40
+ size = ctypes.sizeof(type_)
41
+ wrapper = heap.BufferWrapper(size)
42
+ return rebuild_ctype(type_, wrapper, None)
43
+
44
+ def RawValue(typecode_or_type, *args):
45
+ '''
46
+ Returns a ctypes object allocated from shared memory
47
+ '''
48
+ type_ = typecode_to_type.get(typecode_or_type, typecode_or_type)
49
+ obj = _new_value(type_)
50
+ ctypes.memset(ctypes.addressof(obj), 0, ctypes.sizeof(obj))
51
+ obj.__init__(*args)
52
+ return obj
53
+
54
+ def RawArray(typecode_or_type, size_or_initializer):
55
+ '''
56
+ Returns a ctypes array allocated from shared memory
57
+ '''
58
+ type_ = typecode_to_type.get(typecode_or_type, typecode_or_type)
59
+ if isinstance(size_or_initializer, int):
60
+ type_ = type_ * size_or_initializer
61
+ obj = _new_value(type_)
62
+ ctypes.memset(ctypes.addressof(obj), 0, ctypes.sizeof(obj))
63
+ return obj
64
+ else:
65
+ type_ = type_ * len(size_or_initializer)
66
+ result = _new_value(type_)
67
+ result.__init__(*size_or_initializer)
68
+ return result
69
+
70
+ def Value(typecode_or_type, *args, lock=True, ctx=None):
71
+ '''
72
+ Return a synchronization wrapper for a Value
73
+ '''
74
+ obj = RawValue(typecode_or_type, *args)
75
+ if lock is False:
76
+ return obj
77
+ if lock in (True, None):
78
+ ctx = ctx or get_context()
79
+ lock = ctx.RLock()
80
+ if not hasattr(lock, 'acquire'):
81
+ raise AttributeError("%r has no method 'acquire'" % lock)
82
+ return synchronized(obj, lock, ctx=ctx)
83
+
84
+ def Array(typecode_or_type, size_or_initializer, *, lock=True, ctx=None):
85
+ '''
86
+ Return a synchronization wrapper for a RawArray
87
+ '''
88
+ obj = RawArray(typecode_or_type, size_or_initializer)
89
+ if lock is False:
90
+ return obj
91
+ if lock in (True, None):
92
+ ctx = ctx or get_context()
93
+ lock = ctx.RLock()
94
+ if not hasattr(lock, 'acquire'):
95
+ raise AttributeError("%r has no method 'acquire'" % lock)
96
+ return synchronized(obj, lock, ctx=ctx)
97
+
98
+ def copy(obj):
99
+ new_obj = _new_value(type(obj))
100
+ ctypes.pointer(new_obj)[0] = obj
101
+ return new_obj
102
+
103
+ def synchronized(obj, lock=None, ctx=None):
104
+ assert not isinstance(obj, SynchronizedBase), 'object already synchronized'
105
+ ctx = ctx or get_context()
106
+
107
+ if isinstance(obj, ctypes._SimpleCData):
108
+ return Synchronized(obj, lock, ctx)
109
+ elif isinstance(obj, ctypes.Array):
110
+ if obj._type_ is ctypes.c_char:
111
+ return SynchronizedString(obj, lock, ctx)
112
+ return SynchronizedArray(obj, lock, ctx)
113
+ else:
114
+ cls = type(obj)
115
+ try:
116
+ scls = class_cache[cls]
117
+ except KeyError:
118
+ names = [field[0] for field in cls._fields_]
119
+ d = {name: make_property(name) for name in names}
120
+ classname = 'Synchronized' + cls.__name__
121
+ scls = class_cache[cls] = type(classname, (SynchronizedBase,), d)
122
+ return scls(obj, lock, ctx)
123
+
124
+ #
125
+ # Functions for pickling/unpickling
126
+ #
127
+
128
+ def reduce_ctype(obj):
129
+ assert_spawning(obj)
130
+ if isinstance(obj, ctypes.Array):
131
+ return rebuild_ctype, (obj._type_, obj._wrapper, obj._length_)
132
+ else:
133
+ return rebuild_ctype, (type(obj), obj._wrapper, None)
134
+
135
+ def rebuild_ctype(type_, wrapper, length):
136
+ if length is not None:
137
+ type_ = type_ * length
138
+ _ForkingPickler.register(type_, reduce_ctype)
139
+ buf = wrapper.create_memoryview()
140
+ obj = type_.from_buffer(buf)
141
+ obj._wrapper = wrapper
142
+ return obj
143
+
144
+ #
145
+ # Function to create properties
146
+ #
147
+
148
+ def make_property(name):
149
+ try:
150
+ return prop_cache[name]
151
+ except KeyError:
152
+ d = {}
153
+ exec(template % ((name,)*7), d)
154
+ prop_cache[name] = d[name]
155
+ return d[name]
156
+
157
+ template = '''
158
+ def get%s(self):
159
+ self.acquire()
160
+ try:
161
+ return self._obj.%s
162
+ finally:
163
+ self.release()
164
+ def set%s(self, value):
165
+ self.acquire()
166
+ try:
167
+ self._obj.%s = value
168
+ finally:
169
+ self.release()
170
+ %s = property(get%s, set%s)
171
+ '''
172
+
173
+ prop_cache = {}
174
+ class_cache = weakref.WeakKeyDictionary()
175
+
176
+ #
177
+ # Synchronized wrappers
178
+ #
179
+
180
+ class SynchronizedBase(object):
181
+
182
+ def __init__(self, obj, lock=None, ctx=None):
183
+ self._obj = obj
184
+ if lock:
185
+ self._lock = lock
186
+ else:
187
+ ctx = ctx or get_context(force=True)
188
+ self._lock = ctx.RLock()
189
+ self.acquire = self._lock.acquire
190
+ self.release = self._lock.release
191
+
192
+ def __enter__(self):
193
+ return self._lock.__enter__()
194
+
195
+ def __exit__(self, *args):
196
+ return self._lock.__exit__(*args)
197
+
198
+ def __reduce__(self):
199
+ assert_spawning(self)
200
+ return synchronized, (self._obj, self._lock)
201
+
202
+ def get_obj(self):
203
+ return self._obj
204
+
205
+ def get_lock(self):
206
+ return self._lock
207
+
208
+ def __repr__(self):
209
+ return '<%s wrapper for %s>' % (type(self).__name__, self._obj)
210
+
211
+
212
+ class Synchronized(SynchronizedBase):
213
+ value = make_property('value')
214
+
215
+
216
+ class SynchronizedArray(SynchronizedBase):
217
+
218
+ def __len__(self):
219
+ return len(self._obj)
220
+
221
+ def __getitem__(self, i):
222
+ with self:
223
+ return self._obj[i]
224
+
225
+ def __setitem__(self, i, value):
226
+ with self:
227
+ self._obj[i] = value
228
+
229
+ def __getslice__(self, start, stop):
230
+ with self:
231
+ return self._obj[start:stop]
232
+
233
+ def __setslice__(self, start, stop, values):
234
+ with self:
235
+ self._obj[start:stop] = values
236
+
237
+
238
+ class SynchronizedString(SynchronizedArray):
239
+ value = make_property('value')
240
+ raw = make_property('raw')
lib/python3.1/multiprocessing/spawn.py ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Code used to start processes when using the spawn or forkserver
3
+ # start methods.
4
+ #
5
+ # multiprocessing/spawn.py
6
+ #
7
+ # Copyright (c) 2006-2008, R Oudkerk
8
+ # Licensed to PSF under a Contributor Agreement.
9
+ #
10
+
11
+ import os
12
+ import sys
13
+ import runpy
14
+ import types
15
+
16
+ from . import get_start_method, set_start_method
17
+ from . import process
18
+ from .context import reduction
19
+ from . import util
20
+
21
+ __all__ = ['_main', 'freeze_support', 'set_executable', 'get_executable',
22
+ 'get_preparation_data', 'get_command_line', 'import_main_path']
23
+
24
+ #
25
+ # _python_exe is the assumed path to the python executable.
26
+ # People embedding Python want to modify it.
27
+ #
28
+
29
+ if sys.platform != 'win32':
30
+ WINEXE = False
31
+ WINSERVICE = False
32
+ else:
33
+ WINEXE = getattr(sys, 'frozen', False)
34
+ WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
35
+
36
+ if WINSERVICE:
37
+ _python_exe = os.path.join(sys.exec_prefix, 'python.exe')
38
+ else:
39
+ _python_exe = sys.executable
40
+
41
+ def set_executable(exe):
42
+ global _python_exe
43
+ _python_exe = exe
44
+
45
+ def get_executable():
46
+ return _python_exe
47
+
48
+ #
49
+ #
50
+ #
51
+
52
+ def is_forking(argv):
53
+ '''
54
+ Return whether commandline indicates we are forking
55
+ '''
56
+ if len(argv) >= 2 and argv[1] == '--multiprocessing-fork':
57
+ return True
58
+ else:
59
+ return False
60
+
61
+
62
+ def freeze_support():
63
+ '''
64
+ Run code for process object if this in not the main process
65
+ '''
66
+ if is_forking(sys.argv):
67
+ kwds = {}
68
+ for arg in sys.argv[2:]:
69
+ name, value = arg.split('=')
70
+ if value == 'None':
71
+ kwds[name] = None
72
+ else:
73
+ kwds[name] = int(value)
74
+ spawn_main(**kwds)
75
+ sys.exit()
76
+
77
+
78
+ def get_command_line(**kwds):
79
+ '''
80
+ Returns prefix of command line used for spawning a child process
81
+ '''
82
+ if getattr(sys, 'frozen', False):
83
+ return ([sys.executable, '--multiprocessing-fork'] +
84
+ ['%s=%r' % item for item in kwds.items()])
85
+ else:
86
+ prog = 'from multiprocessing.spawn import spawn_main; spawn_main(%s)'
87
+ prog %= ', '.join('%s=%r' % item for item in kwds.items())
88
+ opts = util._args_from_interpreter_flags()
89
+ return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork']
90
+
91
+
92
+ def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None):
93
+ '''
94
+ Run code specified by data received over pipe
95
+ '''
96
+ assert is_forking(sys.argv), "Not forking"
97
+ if sys.platform == 'win32':
98
+ import msvcrt
99
+ import _winapi
100
+
101
+ if parent_pid is not None:
102
+ source_process = _winapi.OpenProcess(
103
+ _winapi.SYNCHRONIZE | _winapi.PROCESS_DUP_HANDLE,
104
+ False, parent_pid)
105
+ else:
106
+ source_process = None
107
+ new_handle = reduction.duplicate(pipe_handle,
108
+ source_process=source_process)
109
+ fd = msvcrt.open_osfhandle(new_handle, os.O_RDONLY)
110
+ parent_sentinel = source_process
111
+ else:
112
+ from . import resource_tracker
113
+ resource_tracker._resource_tracker._fd = tracker_fd
114
+ fd = pipe_handle
115
+ parent_sentinel = os.dup(pipe_handle)
116
+ exitcode = _main(fd, parent_sentinel)
117
+ sys.exit(exitcode)
118
+
119
+
120
+ def _main(fd, parent_sentinel):
121
+ with os.fdopen(fd, 'rb', closefd=True) as from_parent:
122
+ process.current_process()._inheriting = True
123
+ try:
124
+ preparation_data = reduction.pickle.load(from_parent)
125
+ prepare(preparation_data)
126
+ self = reduction.pickle.load(from_parent)
127
+ finally:
128
+ del process.current_process()._inheriting
129
+ return self._bootstrap(parent_sentinel)
130
+
131
+
132
+ def _check_not_importing_main():
133
+ if getattr(process.current_process(), '_inheriting', False):
134
+ raise RuntimeError('''
135
+ An attempt has been made to start a new process before the
136
+ current process has finished its bootstrapping phase.
137
+
138
+ This probably means that you are not using fork to start your
139
+ child processes and you have forgotten to use the proper idiom
140
+ in the main module:
141
+
142
+ if __name__ == '__main__':
143
+ freeze_support()
144
+ ...
145
+
146
+ The "freeze_support()" line can be omitted if the program
147
+ is not going to be frozen to produce an executable.''')
148
+
149
+
150
+ def get_preparation_data(name):
151
+ '''
152
+ Return info about parent needed by child to unpickle process object
153
+ '''
154
+ _check_not_importing_main()
155
+ d = dict(
156
+ log_to_stderr=util._log_to_stderr,
157
+ authkey=process.current_process().authkey,
158
+ )
159
+
160
+ if util._logger is not None:
161
+ d['log_level'] = util._logger.getEffectiveLevel()
162
+
163
+ sys_path=sys.path.copy()
164
+ try:
165
+ i = sys_path.index('')
166
+ except ValueError:
167
+ pass
168
+ else:
169
+ sys_path[i] = process.ORIGINAL_DIR
170
+
171
+ d.update(
172
+ name=name,
173
+ sys_path=sys_path,
174
+ sys_argv=sys.argv,
175
+ orig_dir=process.ORIGINAL_DIR,
176
+ dir=os.getcwd(),
177
+ start_method=get_start_method(),
178
+ )
179
+
180
+ # Figure out whether to initialise main in the subprocess as a module
181
+ # or through direct execution (or to leave it alone entirely)
182
+ main_module = sys.modules['__main__']
183
+ main_mod_name = getattr(main_module.__spec__, "name", None)
184
+ if main_mod_name is not None:
185
+ d['init_main_from_name'] = main_mod_name
186
+ elif sys.platform != 'win32' or (not WINEXE and not WINSERVICE):
187
+ main_path = getattr(main_module, '__file__', None)
188
+ if main_path is not None:
189
+ if (not os.path.isabs(main_path) and
190
+ process.ORIGINAL_DIR is not None):
191
+ main_path = os.path.join(process.ORIGINAL_DIR, main_path)
192
+ d['init_main_from_path'] = os.path.normpath(main_path)
193
+
194
+ return d
195
+
196
+ #
197
+ # Prepare current process
198
+ #
199
+
200
+ old_main_modules = []
201
+
202
+ def prepare(data):
203
+ '''
204
+ Try to get current process ready to unpickle process object
205
+ '''
206
+ if 'name' in data:
207
+ process.current_process().name = data['name']
208
+
209
+ if 'authkey' in data:
210
+ process.current_process().authkey = data['authkey']
211
+
212
+ if 'log_to_stderr' in data and data['log_to_stderr']:
213
+ util.log_to_stderr()
214
+
215
+ if 'log_level' in data:
216
+ util.get_logger().setLevel(data['log_level'])
217
+
218
+ if 'sys_path' in data:
219
+ sys.path = data['sys_path']
220
+
221
+ if 'sys_argv' in data:
222
+ sys.argv = data['sys_argv']
223
+
224
+ if 'dir' in data:
225
+ os.chdir(data['dir'])
226
+
227
+ if 'orig_dir' in data:
228
+ process.ORIGINAL_DIR = data['orig_dir']
229
+
230
+ if 'start_method' in data:
231
+ set_start_method(data['start_method'], force=True)
232
+
233
+ if 'init_main_from_name' in data:
234
+ _fixup_main_from_name(data['init_main_from_name'])
235
+ elif 'init_main_from_path' in data:
236
+ _fixup_main_from_path(data['init_main_from_path'])
237
+
238
+ # Multiprocessing module helpers to fix up the main module in
239
+ # spawned subprocesses
240
+ def _fixup_main_from_name(mod_name):
241
+ # __main__.py files for packages, directories, zip archives, etc, run
242
+ # their "main only" code unconditionally, so we don't even try to
243
+ # populate anything in __main__, nor do we make any changes to
244
+ # __main__ attributes
245
+ current_main = sys.modules['__main__']
246
+ if mod_name == "__main__" or mod_name.endswith(".__main__"):
247
+ return
248
+
249
+ # If this process was forked, __main__ may already be populated
250
+ if getattr(current_main.__spec__, "name", None) == mod_name:
251
+ return
252
+
253
+ # Otherwise, __main__ may contain some non-main code where we need to
254
+ # support unpickling it properly. We rerun it as __mp_main__ and make
255
+ # the normal __main__ an alias to that
256
+ old_main_modules.append(current_main)
257
+ main_module = types.ModuleType("__mp_main__")
258
+ main_content = runpy.run_module(mod_name,
259
+ run_name="__mp_main__",
260
+ alter_sys=True)
261
+ main_module.__dict__.update(main_content)
262
+ sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module
263
+
264
+
265
+ def _fixup_main_from_path(main_path):
266
+ # If this process was forked, __main__ may already be populated
267
+ current_main = sys.modules['__main__']
268
+
269
+ # Unfortunately, the main ipython launch script historically had no
270
+ # "if __name__ == '__main__'" guard, so we work around that
271
+ # by treating it like a __main__.py file
272
+ # See https://github.com/ipython/ipython/issues/4698
273
+ main_name = os.path.splitext(os.path.basename(main_path))[0]
274
+ if main_name == 'ipython':
275
+ return
276
+
277
+ # Otherwise, if __file__ already has the setting we expect,
278
+ # there's nothing more to do
279
+ if getattr(current_main, '__file__', None) == main_path:
280
+ return
281
+
282
+ # If the parent process has sent a path through rather than a module
283
+ # name we assume it is an executable script that may contain
284
+ # non-main code that needs to be executed
285
+ old_main_modules.append(current_main)
286
+ main_module = types.ModuleType("__mp_main__")
287
+ main_content = runpy.run_path(main_path,
288
+ run_name="__mp_main__")
289
+ main_module.__dict__.update(main_content)
290
+ sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module
291
+
292
+
293
+ def import_main_path(main_path):
294
+ '''
295
+ Set sys.modules['__main__'] to module at main_path
296
+ '''
297
+ _fixup_main_from_path(main_path)
lib/python3.1/multiprocessing/synchronize.py ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module implementing synchronization primitives
3
+ #
4
+ # multiprocessing/synchronize.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ __all__ = [
11
+ 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition', 'Event'
12
+ ]
13
+
14
+ import threading
15
+ import sys
16
+ import tempfile
17
+ import _multiprocessing
18
+ import time
19
+
20
+ from . import context
21
+ from . import process
22
+ from . import util
23
+
24
+ # Try to import the mp.synchronize module cleanly, if it fails
25
+ # raise ImportError for platforms lacking a working sem_open implementation.
26
+ # See issue 3770
27
+ try:
28
+ from _multiprocessing import SemLock, sem_unlink
29
+ except (ImportError):
30
+ raise ImportError("This platform lacks a functioning sem_open" +
31
+ " implementation, therefore, the required" +
32
+ " synchronization primitives needed will not" +
33
+ " function, see issue 3770.")
34
+
35
+ #
36
+ # Constants
37
+ #
38
+
39
+ RECURSIVE_MUTEX, SEMAPHORE = list(range(2))
40
+ SEM_VALUE_MAX = _multiprocessing.SemLock.SEM_VALUE_MAX
41
+
42
+ #
43
+ # Base class for semaphores and mutexes; wraps `_multiprocessing.SemLock`
44
+ #
45
+
46
+ class SemLock(object):
47
+
48
+ _rand = tempfile._RandomNameSequence()
49
+
50
+ def __init__(self, kind, value, maxvalue, *, ctx):
51
+ if ctx is None:
52
+ ctx = context._default_context.get_context()
53
+ name = ctx.get_start_method()
54
+ unlink_now = sys.platform == 'win32' or name == 'fork'
55
+ for i in range(100):
56
+ try:
57
+ sl = self._semlock = _multiprocessing.SemLock(
58
+ kind, value, maxvalue, self._make_name(),
59
+ unlink_now)
60
+ except FileExistsError:
61
+ pass
62
+ else:
63
+ break
64
+ else:
65
+ raise FileExistsError('cannot find name for semaphore')
66
+
67
+ util.debug('created semlock with handle %s' % sl.handle)
68
+ self._make_methods()
69
+
70
+ if sys.platform != 'win32':
71
+ def _after_fork(obj):
72
+ obj._semlock._after_fork()
73
+ util.register_after_fork(self, _after_fork)
74
+
75
+ if self._semlock.name is not None:
76
+ # We only get here if we are on Unix with forking
77
+ # disabled. When the object is garbage collected or the
78
+ # process shuts down we unlink the semaphore name
79
+ from .resource_tracker import register
80
+ register(self._semlock.name, "semaphore")
81
+ util.Finalize(self, SemLock._cleanup, (self._semlock.name,),
82
+ exitpriority=0)
83
+
84
+ @staticmethod
85
+ def _cleanup(name):
86
+ from .resource_tracker import unregister
87
+ sem_unlink(name)
88
+ unregister(name, "semaphore")
89
+
90
+ def _make_methods(self):
91
+ self.acquire = self._semlock.acquire
92
+ self.release = self._semlock.release
93
+
94
+ def __enter__(self):
95
+ return self._semlock.__enter__()
96
+
97
+ def __exit__(self, *args):
98
+ return self._semlock.__exit__(*args)
99
+
100
+ def __getstate__(self):
101
+ context.assert_spawning(self)
102
+ sl = self._semlock
103
+ if sys.platform == 'win32':
104
+ h = context.get_spawning_popen().duplicate_for_child(sl.handle)
105
+ else:
106
+ h = sl.handle
107
+ return (h, sl.kind, sl.maxvalue, sl.name)
108
+
109
+ def __setstate__(self, state):
110
+ self._semlock = _multiprocessing.SemLock._rebuild(*state)
111
+ util.debug('recreated blocker with handle %r' % state[0])
112
+ self._make_methods()
113
+
114
+ @staticmethod
115
+ def _make_name():
116
+ return '%s-%s' % (process.current_process()._config['semprefix'],
117
+ next(SemLock._rand))
118
+
119
+ #
120
+ # Semaphore
121
+ #
122
+
123
+ class Semaphore(SemLock):
124
+
125
+ def __init__(self, value=1, *, ctx):
126
+ SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx)
127
+
128
+ def get_value(self):
129
+ return self._semlock._get_value()
130
+
131
+ def __repr__(self):
132
+ try:
133
+ value = self._semlock._get_value()
134
+ except Exception:
135
+ value = 'unknown'
136
+ return '<%s(value=%s)>' % (self.__class__.__name__, value)
137
+
138
+ #
139
+ # Bounded semaphore
140
+ #
141
+
142
+ class BoundedSemaphore(Semaphore):
143
+
144
+ def __init__(self, value=1, *, ctx):
145
+ SemLock.__init__(self, SEMAPHORE, value, value, ctx=ctx)
146
+
147
+ def __repr__(self):
148
+ try:
149
+ value = self._semlock._get_value()
150
+ except Exception:
151
+ value = 'unknown'
152
+ return '<%s(value=%s, maxvalue=%s)>' % \
153
+ (self.__class__.__name__, value, self._semlock.maxvalue)
154
+
155
+ #
156
+ # Non-recursive lock
157
+ #
158
+
159
+ class Lock(SemLock):
160
+
161
+ def __init__(self, *, ctx):
162
+ SemLock.__init__(self, SEMAPHORE, 1, 1, ctx=ctx)
163
+
164
+ def __repr__(self):
165
+ try:
166
+ if self._semlock._is_mine():
167
+ name = process.current_process().name
168
+ if threading.current_thread().name != 'MainThread':
169
+ name += '|' + threading.current_thread().name
170
+ elif self._semlock._get_value() == 1:
171
+ name = 'None'
172
+ elif self._semlock._count() > 0:
173
+ name = 'SomeOtherThread'
174
+ else:
175
+ name = 'SomeOtherProcess'
176
+ except Exception:
177
+ name = 'unknown'
178
+ return '<%s(owner=%s)>' % (self.__class__.__name__, name)
179
+
180
+ #
181
+ # Recursive lock
182
+ #
183
+
184
+ class RLock(SemLock):
185
+
186
+ def __init__(self, *, ctx):
187
+ SemLock.__init__(self, RECURSIVE_MUTEX, 1, 1, ctx=ctx)
188
+
189
+ def __repr__(self):
190
+ try:
191
+ if self._semlock._is_mine():
192
+ name = process.current_process().name
193
+ if threading.current_thread().name != 'MainThread':
194
+ name += '|' + threading.current_thread().name
195
+ count = self._semlock._count()
196
+ elif self._semlock._get_value() == 1:
197
+ name, count = 'None', 0
198
+ elif self._semlock._count() > 0:
199
+ name, count = 'SomeOtherThread', 'nonzero'
200
+ else:
201
+ name, count = 'SomeOtherProcess', 'nonzero'
202
+ except Exception:
203
+ name, count = 'unknown', 'unknown'
204
+ return '<%s(%s, %s)>' % (self.__class__.__name__, name, count)
205
+
206
+ #
207
+ # Condition variable
208
+ #
209
+
210
+ class Condition(object):
211
+
212
+ def __init__(self, lock=None, *, ctx):
213
+ self._lock = lock or ctx.RLock()
214
+ self._sleeping_count = ctx.Semaphore(0)
215
+ self._woken_count = ctx.Semaphore(0)
216
+ self._wait_semaphore = ctx.Semaphore(0)
217
+ self._make_methods()
218
+
219
+ def __getstate__(self):
220
+ context.assert_spawning(self)
221
+ return (self._lock, self._sleeping_count,
222
+ self._woken_count, self._wait_semaphore)
223
+
224
+ def __setstate__(self, state):
225
+ (self._lock, self._sleeping_count,
226
+ self._woken_count, self._wait_semaphore) = state
227
+ self._make_methods()
228
+
229
+ def __enter__(self):
230
+ return self._lock.__enter__()
231
+
232
+ def __exit__(self, *args):
233
+ return self._lock.__exit__(*args)
234
+
235
+ def _make_methods(self):
236
+ self.acquire = self._lock.acquire
237
+ self.release = self._lock.release
238
+
239
+ def __repr__(self):
240
+ try:
241
+ num_waiters = (self._sleeping_count._semlock._get_value() -
242
+ self._woken_count._semlock._get_value())
243
+ except Exception:
244
+ num_waiters = 'unknown'
245
+ return '<%s(%s, %s)>' % (self.__class__.__name__, self._lock, num_waiters)
246
+
247
+ def wait(self, timeout=None):
248
+ assert self._lock._semlock._is_mine(), \
249
+ 'must acquire() condition before using wait()'
250
+
251
+ # indicate that this thread is going to sleep
252
+ self._sleeping_count.release()
253
+
254
+ # release lock
255
+ count = self._lock._semlock._count()
256
+ for i in range(count):
257
+ self._lock.release()
258
+
259
+ try:
260
+ # wait for notification or timeout
261
+ return self._wait_semaphore.acquire(True, timeout)
262
+ finally:
263
+ # indicate that this thread has woken
264
+ self._woken_count.release()
265
+
266
+ # reacquire lock
267
+ for i in range(count):
268
+ self._lock.acquire()
269
+
270
+ def notify(self, n=1):
271
+ assert self._lock._semlock._is_mine(), 'lock is not owned'
272
+ assert not self._wait_semaphore.acquire(
273
+ False), ('notify: Should not have been able to acquire '
274
+ + '_wait_semaphore')
275
+
276
+ # to take account of timeouts since last notify*() we subtract
277
+ # woken_count from sleeping_count and rezero woken_count
278
+ while self._woken_count.acquire(False):
279
+ res = self._sleeping_count.acquire(False)
280
+ assert res, ('notify: Bug in sleeping_count.acquire'
281
+ + '- res should not be False')
282
+
283
+ sleepers = 0
284
+ while sleepers < n and self._sleeping_count.acquire(False):
285
+ self._wait_semaphore.release() # wake up one sleeper
286
+ sleepers += 1
287
+
288
+ if sleepers:
289
+ for i in range(sleepers):
290
+ self._woken_count.acquire() # wait for a sleeper to wake
291
+
292
+ # rezero wait_semaphore in case some timeouts just happened
293
+ while self._wait_semaphore.acquire(False):
294
+ pass
295
+
296
+ def notify_all(self):
297
+ self.notify(n=sys.maxsize)
298
+
299
+ def wait_for(self, predicate, timeout=None):
300
+ result = predicate()
301
+ if result:
302
+ return result
303
+ if timeout is not None:
304
+ endtime = time.monotonic() + timeout
305
+ else:
306
+ endtime = None
307
+ waittime = None
308
+ while not result:
309
+ if endtime is not None:
310
+ waittime = endtime - time.monotonic()
311
+ if waittime <= 0:
312
+ break
313
+ self.wait(waittime)
314
+ result = predicate()
315
+ return result
316
+
317
+ #
318
+ # Event
319
+ #
320
+
321
+ class Event(object):
322
+
323
+ def __init__(self, *, ctx):
324
+ self._cond = ctx.Condition(ctx.Lock())
325
+ self._flag = ctx.Semaphore(0)
326
+
327
+ def is_set(self):
328
+ with self._cond:
329
+ if self._flag.acquire(False):
330
+ self._flag.release()
331
+ return True
332
+ return False
333
+
334
+ def set(self):
335
+ with self._cond:
336
+ self._flag.acquire(False)
337
+ self._flag.release()
338
+ self._cond.notify_all()
339
+
340
+ def clear(self):
341
+ with self._cond:
342
+ self._flag.acquire(False)
343
+
344
+ def wait(self, timeout=None):
345
+ with self._cond:
346
+ if self._flag.acquire(False):
347
+ self._flag.release()
348
+ else:
349
+ self._cond.wait(timeout)
350
+
351
+ if self._flag.acquire(False):
352
+ self._flag.release()
353
+ return True
354
+ return False
355
+
356
+ #
357
+ # Barrier
358
+ #
359
+
360
+ class Barrier(threading.Barrier):
361
+
362
+ def __init__(self, parties, action=None, timeout=None, *, ctx):
363
+ import struct
364
+ from .heap import BufferWrapper
365
+ wrapper = BufferWrapper(struct.calcsize('i') * 2)
366
+ cond = ctx.Condition()
367
+ self.__setstate__((parties, action, timeout, cond, wrapper))
368
+ self._state = 0
369
+ self._count = 0
370
+
371
+ def __setstate__(self, state):
372
+ (self._parties, self._action, self._timeout,
373
+ self._cond, self._wrapper) = state
374
+ self._array = self._wrapper.create_memoryview().cast('i')
375
+
376
+ def __getstate__(self):
377
+ return (self._parties, self._action, self._timeout,
378
+ self._cond, self._wrapper)
379
+
380
+ @property
381
+ def _state(self):
382
+ return self._array[0]
383
+
384
+ @_state.setter
385
+ def _state(self, value):
386
+ self._array[0] = value
387
+
388
+ @property
389
+ def _count(self):
390
+ return self._array[1]
391
+
392
+ @_count.setter
393
+ def _count(self, value):
394
+ self._array[1] = value
lib/python3.1/multiprocessing/util.py ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Module providing various facilities to other parts of the package
3
+ #
4
+ # multiprocessing/util.py
5
+ #
6
+ # Copyright (c) 2006-2008, R Oudkerk
7
+ # Licensed to PSF under a Contributor Agreement.
8
+ #
9
+
10
+ import os
11
+ import itertools
12
+ import sys
13
+ import weakref
14
+ import atexit
15
+ import threading # we want threading to install it's
16
+ # cleanup function before multiprocessing does
17
+ from subprocess import _args_from_interpreter_flags
18
+
19
+ from . import process
20
+
21
+ __all__ = [
22
+ 'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger',
23
+ 'log_to_stderr', 'get_temp_dir', 'register_after_fork',
24
+ 'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal',
25
+ 'close_all_fds_except', 'SUBDEBUG', 'SUBWARNING',
26
+ ]
27
+
28
+ #
29
+ # Logging
30
+ #
31
+
32
+ NOTSET = 0
33
+ SUBDEBUG = 5
34
+ DEBUG = 10
35
+ INFO = 20
36
+ SUBWARNING = 25
37
+
38
+ LOGGER_NAME = 'multiprocessing'
39
+ DEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s'
40
+
41
+ _logger = None
42
+ _log_to_stderr = False
43
+
44
+ def sub_debug(msg, *args):
45
+ if _logger:
46
+ _logger.log(SUBDEBUG, msg, *args)
47
+
48
+ def debug(msg, *args):
49
+ if _logger:
50
+ _logger.log(DEBUG, msg, *args)
51
+
52
+ def info(msg, *args):
53
+ if _logger:
54
+ _logger.log(INFO, msg, *args)
55
+
56
+ def sub_warning(msg, *args):
57
+ if _logger:
58
+ _logger.log(SUBWARNING, msg, *args)
59
+
60
+ def get_logger():
61
+ '''
62
+ Returns logger used by multiprocessing
63
+ '''
64
+ global _logger
65
+ import logging
66
+
67
+ logging._acquireLock()
68
+ try:
69
+ if not _logger:
70
+
71
+ _logger = logging.getLogger(LOGGER_NAME)
72
+ _logger.propagate = 0
73
+
74
+ # XXX multiprocessing should cleanup before logging
75
+ if hasattr(atexit, 'unregister'):
76
+ atexit.unregister(_exit_function)
77
+ atexit.register(_exit_function)
78
+ else:
79
+ atexit._exithandlers.remove((_exit_function, (), {}))
80
+ atexit._exithandlers.append((_exit_function, (), {}))
81
+
82
+ finally:
83
+ logging._releaseLock()
84
+
85
+ return _logger
86
+
87
+ def log_to_stderr(level=None):
88
+ '''
89
+ Turn on logging and add a handler which prints to stderr
90
+ '''
91
+ global _log_to_stderr
92
+ import logging
93
+
94
+ logger = get_logger()
95
+ formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT)
96
+ handler = logging.StreamHandler()
97
+ handler.setFormatter(formatter)
98
+ logger.addHandler(handler)
99
+
100
+ if level:
101
+ logger.setLevel(level)
102
+ _log_to_stderr = True
103
+ return _logger
104
+
105
+
106
+ # Abstract socket support
107
+
108
+ def _platform_supports_abstract_sockets():
109
+ if sys.platform == "linux":
110
+ return True
111
+ if hasattr(sys, 'getandroidapilevel'):
112
+ return True
113
+ return False
114
+
115
+
116
+ def is_abstract_socket_namespace(address):
117
+ if not address:
118
+ return False
119
+ if isinstance(address, bytes):
120
+ return address[0] == 0
121
+ elif isinstance(address, str):
122
+ return address[0] == "\0"
123
+ raise TypeError(f'address type of {address!r} unrecognized')
124
+
125
+
126
+ abstract_sockets_supported = _platform_supports_abstract_sockets()
127
+
128
+ #
129
+ # Function returning a temp directory which will be removed on exit
130
+ #
131
+
132
+ def _remove_temp_dir(rmtree, tempdir):
133
+ rmtree(tempdir)
134
+
135
+ current_process = process.current_process()
136
+ # current_process() can be None if the finalizer is called
137
+ # late during Python finalization
138
+ if current_process is not None:
139
+ current_process._config['tempdir'] = None
140
+
141
+ def get_temp_dir():
142
+ # get name of a temp directory which will be automatically cleaned up
143
+ tempdir = process.current_process()._config.get('tempdir')
144
+ if tempdir is None:
145
+ import shutil, tempfile
146
+ tempdir = tempfile.mkdtemp(prefix='pymp-')
147
+ info('created temp directory %s', tempdir)
148
+ # keep a strong reference to shutil.rmtree(), since the finalizer
149
+ # can be called late during Python shutdown
150
+ Finalize(None, _remove_temp_dir, args=(shutil.rmtree, tempdir),
151
+ exitpriority=-100)
152
+ process.current_process()._config['tempdir'] = tempdir
153
+ return tempdir
154
+
155
+ #
156
+ # Support for reinitialization of objects when bootstrapping a child process
157
+ #
158
+
159
+ _afterfork_registry = weakref.WeakValueDictionary()
160
+ _afterfork_counter = itertools.count()
161
+
162
+ def _run_after_forkers():
163
+ items = list(_afterfork_registry.items())
164
+ items.sort()
165
+ for (index, ident, func), obj in items:
166
+ try:
167
+ func(obj)
168
+ except Exception as e:
169
+ info('after forker raised exception %s', e)
170
+
171
+ def register_after_fork(obj, func):
172
+ _afterfork_registry[(next(_afterfork_counter), id(obj), func)] = obj
173
+
174
+ #
175
+ # Finalization using weakrefs
176
+ #
177
+
178
+ _finalizer_registry = {}
179
+ _finalizer_counter = itertools.count()
180
+
181
+
182
+ class Finalize(object):
183
+ '''
184
+ Class which supports object finalization using weakrefs
185
+ '''
186
+ def __init__(self, obj, callback, args=(), kwargs=None, exitpriority=None):
187
+ if (exitpriority is not None) and not isinstance(exitpriority,int):
188
+ raise TypeError(
189
+ "Exitpriority ({0!r}) must be None or int, not {1!s}".format(
190
+ exitpriority, type(exitpriority)))
191
+
192
+ if obj is not None:
193
+ self._weakref = weakref.ref(obj, self)
194
+ elif exitpriority is None:
195
+ raise ValueError("Without object, exitpriority cannot be None")
196
+
197
+ self._callback = callback
198
+ self._args = args
199
+ self._kwargs = kwargs or {}
200
+ self._key = (exitpriority, next(_finalizer_counter))
201
+ self._pid = os.getpid()
202
+
203
+ _finalizer_registry[self._key] = self
204
+
205
+ def __call__(self, wr=None,
206
+ # Need to bind these locally because the globals can have
207
+ # been cleared at shutdown
208
+ _finalizer_registry=_finalizer_registry,
209
+ sub_debug=sub_debug, getpid=os.getpid):
210
+ '''
211
+ Run the callback unless it has already been called or cancelled
212
+ '''
213
+ try:
214
+ del _finalizer_registry[self._key]
215
+ except KeyError:
216
+ sub_debug('finalizer no longer registered')
217
+ else:
218
+ if self._pid != getpid():
219
+ sub_debug('finalizer ignored because different process')
220
+ res = None
221
+ else:
222
+ sub_debug('finalizer calling %s with args %s and kwargs %s',
223
+ self._callback, self._args, self._kwargs)
224
+ res = self._callback(*self._args, **self._kwargs)
225
+ self._weakref = self._callback = self._args = \
226
+ self._kwargs = self._key = None
227
+ return res
228
+
229
+ def cancel(self):
230
+ '''
231
+ Cancel finalization of the object
232
+ '''
233
+ try:
234
+ del _finalizer_registry[self._key]
235
+ except KeyError:
236
+ pass
237
+ else:
238
+ self._weakref = self._callback = self._args = \
239
+ self._kwargs = self._key = None
240
+
241
+ def still_active(self):
242
+ '''
243
+ Return whether this finalizer is still waiting to invoke callback
244
+ '''
245
+ return self._key in _finalizer_registry
246
+
247
+ def __repr__(self):
248
+ try:
249
+ obj = self._weakref()
250
+ except (AttributeError, TypeError):
251
+ obj = None
252
+
253
+ if obj is None:
254
+ return '<%s object, dead>' % self.__class__.__name__
255
+
256
+ x = '<%s object, callback=%s' % (
257
+ self.__class__.__name__,
258
+ getattr(self._callback, '__name__', self._callback))
259
+ if self._args:
260
+ x += ', args=' + str(self._args)
261
+ if self._kwargs:
262
+ x += ', kwargs=' + str(self._kwargs)
263
+ if self._key[0] is not None:
264
+ x += ', exitpriority=' + str(self._key[0])
265
+ return x + '>'
266
+
267
+
268
+ def _run_finalizers(minpriority=None):
269
+ '''
270
+ Run all finalizers whose exit priority is not None and at least minpriority
271
+
272
+ Finalizers with highest priority are called first; finalizers with
273
+ the same priority will be called in reverse order of creation.
274
+ '''
275
+ if _finalizer_registry is None:
276
+ # This function may be called after this module's globals are
277
+ # destroyed. See the _exit_function function in this module for more
278
+ # notes.
279
+ return
280
+
281
+ if minpriority is None:
282
+ f = lambda p : p[0] is not None
283
+ else:
284
+ f = lambda p : p[0] is not None and p[0] >= minpriority
285
+
286
+ # Careful: _finalizer_registry may be mutated while this function
287
+ # is running (either by a GC run or by another thread).
288
+
289
+ # list(_finalizer_registry) should be atomic, while
290
+ # list(_finalizer_registry.items()) is not.
291
+ keys = [key for key in list(_finalizer_registry) if f(key)]
292
+ keys.sort(reverse=True)
293
+
294
+ for key in keys:
295
+ finalizer = _finalizer_registry.get(key)
296
+ # key may have been removed from the registry
297
+ if finalizer is not None:
298
+ sub_debug('calling %s', finalizer)
299
+ try:
300
+ finalizer()
301
+ except Exception:
302
+ import traceback
303
+ traceback.print_exc()
304
+
305
+ if minpriority is None:
306
+ _finalizer_registry.clear()
307
+
308
+ #
309
+ # Clean up on exit
310
+ #
311
+
312
+ def is_exiting():
313
+ '''
314
+ Returns true if the process is shutting down
315
+ '''
316
+ return _exiting or _exiting is None
317
+
318
+ _exiting = False
319
+
320
+ def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
321
+ active_children=process.active_children,
322
+ current_process=process.current_process):
323
+ # We hold on to references to functions in the arglist due to the
324
+ # situation described below, where this function is called after this
325
+ # module's globals are destroyed.
326
+
327
+ global _exiting
328
+
329
+ if not _exiting:
330
+ _exiting = True
331
+
332
+ info('process shutting down')
333
+ debug('running all "atexit" finalizers with priority >= 0')
334
+ _run_finalizers(0)
335
+
336
+ if current_process() is not None:
337
+ # We check if the current process is None here because if
338
+ # it's None, any call to ``active_children()`` will raise
339
+ # an AttributeError (active_children winds up trying to
340
+ # get attributes from util._current_process). One
341
+ # situation where this can happen is if someone has
342
+ # manipulated sys.modules, causing this module to be
343
+ # garbage collected. The destructor for the module type
344
+ # then replaces all values in the module dict with None.
345
+ # For instance, after setuptools runs a test it replaces
346
+ # sys.modules with a copy created earlier. See issues
347
+ # #9775 and #15881. Also related: #4106, #9205, and
348
+ # #9207.
349
+
350
+ for p in active_children():
351
+ if p.daemon:
352
+ info('calling terminate() for daemon %s', p.name)
353
+ p._popen.terminate()
354
+
355
+ for p in active_children():
356
+ info('calling join() for process %s', p.name)
357
+ p.join()
358
+
359
+ debug('running the remaining "atexit" finalizers')
360
+ _run_finalizers()
361
+
362
+ atexit.register(_exit_function)
363
+
364
+ #
365
+ # Some fork aware types
366
+ #
367
+
368
+ class ForkAwareThreadLock(object):
369
+ def __init__(self):
370
+ self._lock = threading.Lock()
371
+ self.acquire = self._lock.acquire
372
+ self.release = self._lock.release
373
+ register_after_fork(self, ForkAwareThreadLock._at_fork_reinit)
374
+
375
+ def _at_fork_reinit(self):
376
+ self._lock._at_fork_reinit()
377
+
378
+ def __enter__(self):
379
+ return self._lock.__enter__()
380
+
381
+ def __exit__(self, *args):
382
+ return self._lock.__exit__(*args)
383
+
384
+
385
+ class ForkAwareLocal(threading.local):
386
+ def __init__(self):
387
+ register_after_fork(self, lambda obj : obj.__dict__.clear())
388
+ def __reduce__(self):
389
+ return type(self), ()
390
+
391
+ #
392
+ # Close fds except those specified
393
+ #
394
+
395
+ try:
396
+ MAXFD = os.sysconf("SC_OPEN_MAX")
397
+ except Exception:
398
+ MAXFD = 256
399
+
400
+ def close_all_fds_except(fds):
401
+ fds = list(fds) + [-1, MAXFD]
402
+ fds.sort()
403
+ assert fds[-1] == MAXFD, 'fd too large'
404
+ for i in range(len(fds) - 1):
405
+ os.closerange(fds[i]+1, fds[i+1])
406
+ #
407
+ # Close sys.stdin and replace stdin with os.devnull
408
+ #
409
+
410
+ def _close_stdin():
411
+ if sys.stdin is None:
412
+ return
413
+
414
+ try:
415
+ sys.stdin.close()
416
+ except (OSError, ValueError):
417
+ pass
418
+
419
+ try:
420
+ fd = os.open(os.devnull, os.O_RDONLY)
421
+ try:
422
+ sys.stdin = open(fd, encoding="utf-8", closefd=False)
423
+ except:
424
+ os.close(fd)
425
+ raise
426
+ except (OSError, ValueError):
427
+ pass
428
+
429
+ #
430
+ # Flush standard streams, if any
431
+ #
432
+
433
+ def _flush_std_streams():
434
+ try:
435
+ sys.stdout.flush()
436
+ except (AttributeError, ValueError):
437
+ pass
438
+ try:
439
+ sys.stderr.flush()
440
+ except (AttributeError, ValueError):
441
+ pass
442
+
443
+ #
444
+ # Start a program with only specified fds kept open
445
+ #
446
+
447
+ def spawnv_passfds(path, args, passfds):
448
+ import _posixsubprocess
449
+ passfds = tuple(sorted(map(int, passfds)))
450
+ errpipe_read, errpipe_write = os.pipe()
451
+ try:
452
+ return _posixsubprocess.fork_exec(
453
+ args, [os.fsencode(path)], True, passfds, None, None,
454
+ -1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
455
+ False, False, None, None, None, -1, None)
456
+ finally:
457
+ os.close(errpipe_read)
458
+ os.close(errpipe_write)
459
+
460
+
461
+ def close_fds(*fds):
462
+ """Close each file descriptor given as an argument"""
463
+ for fd in fds:
464
+ os.close(fd)
465
+
466
+
467
+ def _cleanup_tests():
468
+ """Cleanup multiprocessing resources when multiprocessing tests
469
+ completed."""
470
+
471
+ from test import support
472
+
473
+ # cleanup multiprocessing
474
+ process._cleanup()
475
+
476
+ # Stop the ForkServer process if it's running
477
+ from multiprocessing import forkserver
478
+ forkserver._forkserver._stop()
479
+
480
+ # Stop the ResourceTracker process if it's running
481
+ from multiprocessing import resource_tracker
482
+ resource_tracker._resource_tracker._stop()
483
+
484
+ # bpo-37421: Explicitly call _run_finalizers() to remove immediately
485
+ # temporary directories created by multiprocessing.util.get_temp_dir().
486
+ _run_finalizers()
487
+ support.gc_collect()
488
+
489
+ support.reap_children()
lib/python3.1/site-packages/README.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ This directory exists so that 3rd party packages can be installed
2
+ here. Read the source for site.py for more details.
lib/python3.1/site-packages/aiohttp/.hash/_cparser.pxd.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 5276d46021e0e0d7577e0c9155800cbf62932d60a50783fec42aefb63febedec /home/runner/work/aiohttp/aiohttp/aiohttp/_cparser.pxd
lib/python3.1/site-packages/aiohttp/.hash/_find_header.pxd.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ d067f01423cddb3c442933b5fcc039b18ab651fcec1bc91c577693aafc25cf78 /home/runner/work/aiohttp/aiohttp/aiohttp/_find_header.pxd
lib/python3.1/site-packages/aiohttp/.hash/_http_parser.pyx.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ d4bd3b3cab898e00c642eaa59b2f7ae5ae5aa1374e698597f7d805a302f23e21 /home/runner/work/aiohttp/aiohttp/aiohttp/_http_parser.pyx