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
= _current_process
._counter
.next()
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
, basestring
), '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)
224 sys
.stdin
= open(os
.devnull
)
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, 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 signal
.__dict
__.items():
296 if name
[:3]=='SIG' and '_' not in name
:
297 _exitcode_to_name
[-signum
] = name