FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
cpython/Lib/multiprocessing/process.py at main · python/cpython · GitHub
python
cpython
Repository navigation
Code
Issues
5k+
(5k+)
Pull requests
2.5k
(2.5k)
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
cpython
/
Lib
/
multiprocessing
/
process.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
443 lines (377 loc) · 11.9 KB
Breadcrumbs
cpython
/
Lib
/
multiprocessing
/
process.py
Copy path
File metadata and controls
443 lines (377 loc) · 11.9 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
#
# Module providing the `Process` class which emulates `threading.Thread`
#
# multiprocessing/process.py
#
# Copyright (c) 2006-2008, R Oudkerk
# Licensed to PSF under a Contributor Agreement.
#
__all__
=
[
'BaseProcess'
,
'current_process'
,
'active_children'
,
'parent_process'
]
#
# Imports
#
import
os
import
sys
import
signal
import
itertools
import
threading
from
_weakrefset
import
WeakSet
#
#
#
try
:
ORIGINAL_DIR
=
os
.
path
.
abspath
(
os
.
getcwd
())
except
OSError
:
ORIGINAL_DIR
=
None
#
# Public functions
#
def
current_process
():
'''
Return process object representing the current process
'''
return
_current_process
def
active_children
():
'''
Return list of process objects corresponding to live child processes
'''
_cleanup
()
return
list
(
_children
)
def
parent_process
():
'''
Return process object representing the parent process
'''
return
_parent_process
#
#
#
def
_cleanup
():
# check for processes which have finished
for
p
in
list
(
_children
):
if
(
child_popen
:=
p
.
_popen
)
and
child_popen
.
poll
()
is
not
None
:
_children
.
discard
(
p
)
#
# The `Process` class
#
class
BaseProcess
(
object
):
'''
Process objects represent activity that is run in a separate process
The class is analogous to `threading.Thread`
'''
def
_Popen
(
self
):
raise
NotImplementedError
def
__init__
(
self
,
group
=
None
,
target
=
None
,
name
=
None
,
args
=
(),
kwargs
=
None
,
*
,
daemon
=
None
):
assert
group
is
None
,
'group argument must be None for now'
count
=
next
(
_process_counter
)
self
.
_identity
=
_current_process
.
_identity
+
(
count
,)
self
.
_config
=
_current_process
.
_config
.
copy
()
self
.
_parent_pid
=
os
.
getpid
()
self
.
_parent_name
=
_current_process
.
name
self
.
_popen
=
None
self
.
_closed
=
False
self
.
_target
=
target
self
.
_args
=
tuple
(
args
)
self
.
_kwargs
=
dict
(
kwargs
)
if
kwargs
else
{}
self
.
_name
=
name
or
type
(
self
).
__name__
+
'-'
+
\
':'
.
join
(
str
(
i
)
for
i
in
self
.
_identity
)
if
daemon
is
not
None
:
self
.
daemon
=
daemon
_dangling
.
add
(
self
)
def
_check_closed
(
self
):
if
self
.
_closed
:
raise
ValueError
(
"process object is closed"
)
def
run
(
self
):
'''
Method to be run in sub-process; can be overridden in sub-class
'''
if
self
.
_target
:
self
.
_target
(
*
self
.
_args
,
**
self
.
_kwargs
)
def
start
(
self
):
'''
Start child process
'''
self
.
_check_closed
()
assert
self
.
_popen
is
None
,
'cannot start a process twice'
assert
self
.
_parent_pid
==
os
.
getpid
(), \
'can only start a process object created by current process'
assert
not
_current_process
.
_config
.
get
(
'daemon'
), \
'daemonic processes are not allowed to have children'
_cleanup
()
self
.
_popen
=
self
.
_Popen
(
self
)
self
.
_sentinel
=
self
.
_popen
.
sentinel
# Avoid a refcycle if the target function holds an indirect
# reference to the process object (see bpo-30775)
del
self
.
_target
,
self
.
_args
,
self
.
_kwargs
_children
.
add
(
self
)
def
interrupt
(
self
):
'''
Terminate process; sends SIGINT signal
'''
self
.
_check_closed
()
self
.
_popen
.
interrupt
()
def
terminate
(
self
):
'''
Terminate process; sends SIGTERM signal or uses TerminateProcess()
'''
self
.
_check_closed
()
self
.
_popen
.
terminate
()
def
kill
(
self
):
'''
Terminate process; sends SIGKILL signal or uses TerminateProcess()
'''
self
.
_check_closed
()
self
.
_popen
.
kill
()
def
join
(
self
,
timeout
=
None
):
'''
Wait until child process terminates
'''
self
.
_check_closed
()
assert
self
.
_parent_pid
==
os
.
getpid
(),
'can only join a child process'
assert
self
.
_popen
is
not
None
,
'can only join a started process'
res
=
self
.
_popen
.
wait
(
timeout
)
if
res
is
not
None
:
_children
.
discard
(
self
)
def
is_alive
(
self
):
'''
Return whether process is alive
'''
self
.
_check_closed
()
if
self
is
_current_process
:
return
True
assert
self
.
_parent_pid
==
os
.
getpid
(),
'can only test a child process'
if
self
.
_popen
is
None
:
return
False
returncode
=
self
.
_popen
.
poll
()
if
returncode
is
None
:
return
True
else
:
_children
.
discard
(
self
)
return
False
def
close
(
self
):
'''
Close the Process object.
This method releases resources held by the Process object. It is
an error to call this method if the child process is still running.
'''
if
self
.
_popen
is
not
None
:
if
self
.
_popen
.
poll
()
is
None
:
raise
ValueError
(
"Cannot close a process while it is still running. "
"You should first call join() or terminate()."
)
self
.
_popen
.
close
()
self
.
_popen
=
None
del
self
.
_sentinel
_children
.
discard
(
self
)
self
.
_closed
=
True
@
property
def
name
(
self
):
return
self
.
_name
@
name
.
setter
def
name
(
self
,
name
):
assert
isinstance
(
name
,
str
),
'name must be a string'
self
.
_name
=
name
@
property
def
daemon
(
self
):
'''
Return whether process is a daemon
'''
return
self
.
_config
.
get
(
'daemon'
,
False
)
@
daemon
.
setter
def
daemon
(
self
,
daemonic
):
'''
Set whether process is a daemon
'''
assert
self
.
_popen
is
None
,
'process has already started'
self
.
_config
[
'daemon'
]
=
daemonic
@
property
def
authkey
(
self
):
return
self
.
_config
[
'authkey'
]
@
authkey
.
setter
def
authkey
(
self
,
authkey
):
'''
Set authorization key of process
'''
self
.
_config
[
'authkey'
]
=
AuthenticationString
(
authkey
)
@
property
def
exitcode
(
self
):
'''
Return exit code of process or `None` if it has yet to stop
'''
self
.
_check_closed
()
if
self
.
_popen
is
None
:
return
self
.
_popen
return
self
.
_popen
.
poll
()
@
property
def
ident
(
self
):
'''
Return identifier (PID) of process or `None` if it has yet to start
'''
self
.
_check_closed
()
if
self
is
_current_process
:
return
os
.
getpid
()
else
:
return
self
.
_popen
and
self
.
_popen
.
pid
pid
=
ident
@
property
def
sentinel
(
self
):
'''
Return a file descriptor (Unix) or handle (Windows) suitable for
waiting for process termination.
'''
self
.
_check_closed
()
try
:
return
self
.
_sentinel
except
AttributeError
:
raise
ValueError
(
"process not started"
)
from
None
def
__repr__
(
self
):
exitcode
=
None
if
self
is
_current_process
:
status
=
'started'
elif
self
.
_closed
:
status
=
'closed'
elif
self
.
_parent_pid
!=
os
.
getpid
():
status
=
'unknown'
elif
self
.
_popen
is
None
:
status
=
'initial'
else
:
exitcode
=
self
.
_popen
.
poll
()
if
exitcode
is
not
None
:
status
=
'stopped'
else
:
status
=
'started'
info
=
[
type
(
self
).
__name__
,
'name=%r'
%
self
.
_name
]
if
self
.
_popen
is
not
None
:
info
.
append
(
'pid=%s'
%
self
.
_popen
.
pid
)
info
.
append
(
'parent=%s'
%
self
.
_parent_pid
)
info
.
append
(
status
)
if
exitcode
is
not
None
:
exitcode
=
_exitcode_to_name
.
get
(
exitcode
,
exitcode
)
info
.
append
(
'exitcode=%s'
%
exitcode
)
if
self
.
daemon
:
info
.
append
(
'daemon'
)
return
'<%s>'
%
' '
.
join
(
info
)
##
def
_bootstrap
(
self
,
parent_sentinel
=
None
):
from
.
import
util
,
context
global
_current_process
,
_parent_process
,
_process_counter
,
_children
try
:
if
self
.
_start_method
is
not
None
:
context
.
_force_start_method
(
self
.
_start_method
)
_process_counter
=
itertools
.
count
(
1
)
_children
=
set
()
util
.
_close_stdin
()
old_process
=
_current_process
_current_process
=
self
_parent_process
=
_ParentProcess
(
self
.
_parent_name
,
self
.
_parent_pid
,
parent_sentinel
)
if
threading
.
_HAVE_THREAD_NATIVE_ID
:
threading
.
main_thread
().
_set_native_id
()
try
:
self
.
_after_fork
()
finally
:
# delay finalization of the old process object until after
# _run_after_forkers() is executed
del
old_process
util
.
info
(
'child process calling self.run()'
)
self
.
run
()
exitcode
=
0
except
SystemExit
as
e
:
if
e
.
code
is
None
:
exitcode
=
0
elif
isinstance
(
e
.
code
,
int
):
exitcode
=
e
.
code
else
:
sys
.
stderr
.
write
(
str
(
e
.
code
)
+
'
\n
'
)
exitcode
=
1
except
:
exitcode
=
1
import
traceback
sys
.
stderr
.
write
(
'Process %s:
\n
'
%
self
.
name
)
traceback
.
print_exc
()
finally
:
threading
.
_shutdown
()
util
.
info
(
'process exiting with exitcode %d'
%
exitcode
)
util
.
_flush_std_streams
()
return
exitcode
@
staticmethod
def
_after_fork
():
from
.
import
util
util
.
_finalizer_registry
.
clear
()
util
.
_run_after_forkers
()
#
# We subclass bytes to avoid accidental transmission of auth keys over network
#
class
AuthenticationString
(
bytes
):
def
__reduce__
(
self
):
from
.
context
import
get_spawning_popen
if
get_spawning_popen
()
is
None
:
raise
TypeError
(
'Pickling an AuthenticationString object is '
'disallowed for security reasons'
)
return
AuthenticationString
, (
bytes
(
self
),)
#
# Create object representing the parent process
#
class
_ParentProcess
(
BaseProcess
):
def
__init__
(
self
,
name
,
pid
,
sentinel
):
self
.
_identity
=
()
self
.
_name
=
name
self
.
_pid
=
pid
self
.
_parent_pid
=
None
self
.
_popen
=
None
self
.
_closed
=
False
self
.
_sentinel
=
sentinel
self
.
_config
=
{}
def
is_alive
(
self
):
from
multiprocessing
.
connection
import
wait
return
not
wait
([
self
.
_sentinel
],
timeout
=
0
)
@
property
def
ident
(
self
):
return
self
.
_pid
def
join
(
self
,
timeout
=
None
):
'''
Wait until parent process terminates
'''
from
multiprocessing
.
connection
import
wait
wait
([
self
.
_sentinel
],
timeout
=
timeout
)
pid
=
ident
#
# Create object representing the main process
#
class
_MainProcess
(
BaseProcess
):
def
__init__
(
self
):
self
.
_identity
=
()
self
.
_name
=
'MainProcess'
self
.
_parent_pid
=
None
self
.
_popen
=
None
self
.
_closed
=
False
self
.
_config
=
{
'authkey'
:
AuthenticationString
(
os
.
urandom
(
32
)),
'semprefix'
:
'/mp'
}
# Note that some versions of FreeBSD only allow named
# semaphores to have names of up to 14 characters. Therefore
# we choose a short prefix.
#
# On MacOSX in a sandbox it may be necessary to use a
# different prefix -- see #19478.
#
# Everything in self._config will be inherited by descendant
# processes.
def
close
(
self
):
pass
_parent_process
=
None
_current_process
=
_MainProcess
()
_process_counter
=
itertools
.
count
(
1
)
_children
=
set
()
del
_MainProcess
#
# Give names to some return codes
#
_exitcode_to_name
=
{}
for
name
,
signum
in
list
(
signal
.
__dict__
.
items
()):
if
name
[:
3
]
==
'SIG'
and
'_'
not
in
name
:
_exitcode_to_name
[
-
signum
]
=
f'-
{
name
}
'
del
name
,
signum
# For debug and leak testing
_dangling
=
WeakSet
()
Back
|
FazBrowse Home
|
New Git URL