2
# Module providing the `Process` class which emulates `threading.Thread`
4
# multiprocessing/process.py
6
# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
9
__all__ = ['Process', 'current_process', 'active_children']
25
ORIGINAL_DIR = os.path.abspath(os.getcwd())
33
def current_process():
35
Return process object representing the current process
37
return _current_process
39
def active_children():
41
Return list of process objects corresponding to live child processes
44
return list(_current_process._children)
51
# check for processes which have finished
52
for p in list(_current_process._children):
53
if p._popen.poll() is not None:
54
_current_process._children.discard(p)
60
class Process(object):
62
Process objects represent activity that is run in a separate process
64
The class is analagous to `threading.Thread`
68
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
69
assert group is None, 'group argument must be None for now'
70
count = next(_current_process._counter)
71
self._identity = _current_process._identity + (count,)
72
self._authkey = _current_process._authkey
73
self._daemonic = _current_process._daemonic
74
self._tempdir = _current_process._tempdir
75
self._parent_pid = os.getpid()
78
self._args = tuple(args)
79
self._kwargs = dict(kwargs)
80
self._name = name or type(self).__name__ + '-' + \
81
':'.join(str(i) for i in self._identity)
85
Method to be run in sub-process; can be overridden in sub-class
88
self._target(*self._args, **self._kwargs)
94
assert self._popen is None, 'cannot start a process twice'
95
assert self._parent_pid == os.getpid(), \
96
'can only start a process object created by current process'
97
assert not _current_process._daemonic, \
98
'daemonic processes are not allowed to have children'
100
if self._Popen is not None:
103
from .forking import Popen
104
self._popen = Popen(self)
105
_current_process._children.add(self)
109
Terminate process; sends SIGTERM signal or uses TerminateProcess()
111
self._popen.terminate()
113
def join(self, timeout=None):
115
Wait until child process terminates
117
assert self._parent_pid == os.getpid(), 'can only join a child process'
118
assert self._popen is not None, 'can only join a started process'
119
res = self._popen.wait(timeout)
121
_current_process._children.discard(self)
125
Return whether process is alive
127
if self is _current_process:
129
assert self._parent_pid == os.getpid(), 'can only test a child process'
130
if self._popen is None:
133
return self._popen.returncode is None
140
def name(self, name):
141
assert isinstance(name, str), 'name must be a string'
147
Return whether process is a daemon
149
return self._daemonic
152
def daemon(self, daemonic):
154
Set whether process is a daemon
156
assert self._popen is None, 'process has already started'
157
self._daemonic = daemonic
164
def authkey(self, authkey):
166
Set authorization key of process
168
self._authkey = AuthenticationString(authkey)
173
Return exit code of process or `None` if it has yet to stop
175
if self._popen is None:
177
return self._popen.poll()
182
Return indentifier (PID) of process or `None` if it has yet to start
184
if self is _current_process:
187
return self._popen and self._popen.pid
192
if self is _current_process:
194
elif self._parent_pid != os.getpid():
196
elif self._popen is None:
199
if self._popen.poll() is not None:
200
status = self.exitcode
204
if type(status) is int:
208
status = 'stopped[%s]' % _exitcode_to_name.get(status, status)
210
return '<%s(%s, %s%s)>' % (type(self).__name__, self._name,
211
status, self._daemonic and ' daemon' or '')
215
def _bootstrap(self):
217
global _current_process
220
self._children = set()
221
self._counter = itertools.count(1)
222
if sys.stdin is not None:
224
os.close(sys.stdin.fileno())
225
except (OSError, ValueError):
227
_current_process = self
228
util._finalizer_registry.clear()
229
util._run_after_forkers()
230
util.info('child process calling self.run()')
235
util._exit_function()
236
except SystemExit as e:
239
elif type(e.args[0]) is int:
242
sys.stderr.write(e.args[0] + '\n')
248
sys.stderr.write('Process %s:\n' % self.name)
250
traceback.print_exc()
252
util.info('process exiting with exitcode %d' % exitcode)
256
# We subclass bytes to avoid accidental transmission of auth keys over network
259
class AuthenticationString(bytes):
260
def __reduce__(self):
261
from .forking import Popen
262
if not Popen.thread_is_spawning():
264
'Pickling an AuthenticationString object is '
265
'disallowed for security reasons'
267
return AuthenticationString, (bytes(self),)
270
# Create object representing the main process
273
class _MainProcess(Process):
277
self._daemonic = False
278
self._name = 'MainProcess'
279
self._parent_pid = None
281
self._counter = itertools.count(1)
282
self._children = set()
283
self._authkey = AuthenticationString(os.urandom(32))
286
_current_process = _MainProcess()
290
# Give names to some return codes
293
_exitcode_to_name = {}
295
for name, signum in list(signal.__dict__.items()):
296
if name[:3]=='SIG' and '_' not in name:
297
_exitcode_to_name[-signum] = name