blob: 8e500dc93dc6bdbc3c228b9dd851ff98ea83f0d8 [file] [log] [blame]
Benjamin Petersone711caf2008-06-11 16:44:04 +00001#
2# Module providing the `Process` class which emulates `threading.Thread`
3#
4# multiprocessing/process.py
5#
R. David Murray3fc969a2010-12-14 01:38:16 +00006# Copyright (c) 2006-2008, R Oudkerk
Richard Oudkerk3e268aa2012-04-30 12:13:55 +01007# Licensed to PSF under a Contributor Agreement.
Benjamin Petersone711caf2008-06-11 16:44:04 +00008#
9
Richard Oudkerkb1694cf2013-10-16 16:41:56 +010010__all__ = ['BaseProcess', 'current_process', 'active_children']
Benjamin Petersone711caf2008-06-11 16:44:04 +000011
12#
13# Imports
14#
15
16import os
17import sys
18import signal
19import itertools
Antoine Pitrouc081c0c2011-07-15 22:12:24 +020020from _weakrefset import WeakSet
Benjamin Petersone711caf2008-06-11 16:44:04 +000021
22#
23#
24#
25
26try:
27 ORIGINAL_DIR = os.path.abspath(os.getcwd())
28except OSError:
29 ORIGINAL_DIR = None
30
Benjamin Petersone711caf2008-06-11 16:44:04 +000031#
32# Public functions
33#
34
35def current_process():
36 '''
37 Return process object representing the current process
38 '''
39 return _current_process
40
41def active_children():
42 '''
43 Return list of process objects corresponding to live child processes
44 '''
45 _cleanup()
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010046 return list(_children)
Benjamin Petersone711caf2008-06-11 16:44:04 +000047
48#
49#
50#
51
52def _cleanup():
53 # check for processes which have finished
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010054 for p in list(_children):
Benjamin Petersone711caf2008-06-11 16:44:04 +000055 if p._popen.poll() is not None:
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010056 _children.discard(p)
Benjamin Petersone711caf2008-06-11 16:44:04 +000057
58#
59# The `Process` class
60#
61
Richard Oudkerkb1694cf2013-10-16 16:41:56 +010062class BaseProcess(object):
Benjamin Petersone711caf2008-06-11 16:44:04 +000063 '''
64 Process objects represent activity that is run in a separate process
65
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010066 The class is analogous to `threading.Thread`
Benjamin Petersone711caf2008-06-11 16:44:04 +000067 '''
Richard Oudkerkb1694cf2013-10-16 16:41:56 +010068 def _Popen(self):
69 raise NotImplementedError
Benjamin Petersone711caf2008-06-11 16:44:04 +000070
Antoine Pitrou0bd4deb2011-02-25 22:07:43 +000071 def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
72 *, daemon=None):
Benjamin Petersone711caf2008-06-11 16:44:04 +000073 assert group is None, 'group argument must be None for now'
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010074 count = next(_process_counter)
Benjamin Petersone711caf2008-06-11 16:44:04 +000075 self._identity = _current_process._identity + (count,)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010076 self._config = _current_process._config.copy()
Benjamin Petersone711caf2008-06-11 16:44:04 +000077 self._parent_pid = os.getpid()
78 self._popen = None
Antoine Pitrou13e96cc2017-06-24 19:22:23 +020079 self._closed = False
Benjamin Petersone711caf2008-06-11 16:44:04 +000080 self._target = target
81 self._args = tuple(args)
82 self._kwargs = dict(kwargs)
83 self._name = name or type(self).__name__ + '-' + \
84 ':'.join(str(i) for i in self._identity)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010085 if daemon is not None:
86 self.daemon = daemon
Antoine Pitrouc081c0c2011-07-15 22:12:24 +020087 _dangling.add(self)
Benjamin Petersone711caf2008-06-11 16:44:04 +000088
Antoine Pitrou13e96cc2017-06-24 19:22:23 +020089 def _check_closed(self):
90 if self._closed:
91 raise ValueError("process object is closed")
92
Benjamin Petersone711caf2008-06-11 16:44:04 +000093 def run(self):
94 '''
95 Method to be run in sub-process; can be overridden in sub-class
96 '''
97 if self._target:
98 self._target(*self._args, **self._kwargs)
99
100 def start(self):
101 '''
102 Start child process
103 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200104 self._check_closed()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000105 assert self._popen is None, 'cannot start a process twice'
106 assert self._parent_pid == os.getpid(), \
107 'can only start a process object created by current process'
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100108 assert not _current_process._config.get('daemon'), \
Benjamin Petersone711caf2008-06-11 16:44:04 +0000109 'daemonic processes are not allowed to have children'
110 _cleanup()
Richard Oudkerkb1694cf2013-10-16 16:41:56 +0100111 self._popen = self._Popen(self)
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200112 self._sentinel = self._popen.sentinel
Antoine Pitrou79d37ae2017-06-28 12:29:08 +0200113 # Avoid a refcycle if the target function holds an indirect
114 # reference to the process object (see bpo-30775)
115 del self._target, self._args, self._kwargs
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100116 _children.add(self)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000117
118 def terminate(self):
119 '''
120 Terminate process; sends SIGTERM signal or uses TerminateProcess()
121 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200122 self._check_closed()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000123 self._popen.terminate()
124
Vitor Pereiraba75af72017-07-18 16:34:23 +0100125 def kill(self):
126 '''
127 Terminate process; sends SIGKILL signal or uses TerminateProcess()
128 '''
129 self._check_closed()
130 self._popen.kill()
131
Benjamin Petersone711caf2008-06-11 16:44:04 +0000132 def join(self, timeout=None):
133 '''
134 Wait until child process terminates
135 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200136 self._check_closed()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000137 assert self._parent_pid == os.getpid(), 'can only join a child process'
138 assert self._popen is not None, 'can only join a started process'
139 res = self._popen.wait(timeout)
140 if res is not None:
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100141 _children.discard(self)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000142
143 def is_alive(self):
144 '''
145 Return whether process is alive
146 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200147 self._check_closed()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000148 if self is _current_process:
149 return True
150 assert self._parent_pid == os.getpid(), 'can only test a child process'
Victor Stinner2db64822017-07-26 02:32:42 +0200151
Benjamin Petersone711caf2008-06-11 16:44:04 +0000152 if self._popen is None:
153 return False
Victor Stinner2db64822017-07-26 02:32:42 +0200154
155 returncode = self._popen.poll()
156 if returncode is None:
157 return True
158 else:
159 _children.discard(self)
160 return False
Benjamin Petersone711caf2008-06-11 16:44:04 +0000161
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200162 def close(self):
163 '''
164 Close the Process object.
165
166 This method releases resources held by the Process object. It is
167 an error to call this method if the child process is still running.
168 '''
169 if self._popen is not None:
170 if self._popen.poll() is None:
171 raise ValueError("Cannot close a process while it is still running. "
172 "You should first call join() or terminate().")
173 self._popen.close()
174 self._popen = None
175 del self._sentinel
176 _children.discard(self)
177 self._closed = True
178
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000179 @property
180 def name(self):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000181 return self._name
182
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000183 @name.setter
184 def name(self, name):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000185 assert isinstance(name, str), 'name must be a string'
186 self._name = name
187
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000188 @property
189 def daemon(self):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000190 '''
191 Return whether process is a daemon
192 '''
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100193 return self._config.get('daemon', False)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000194
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000195 @daemon.setter
196 def daemon(self, daemonic):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000197 '''
198 Set whether process is a daemon
199 '''
200 assert self._popen is None, 'process has already started'
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100201 self._config['daemon'] = daemonic
Benjamin Petersone711caf2008-06-11 16:44:04 +0000202
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000203 @property
204 def authkey(self):
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100205 return self._config['authkey']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000206
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000207 @authkey.setter
208 def authkey(self, authkey):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000209 '''
210 Set authorization key of process
211 '''
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100212 self._config['authkey'] = AuthenticationString(authkey)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000213
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000214 @property
215 def exitcode(self):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000216 '''
217 Return exit code of process or `None` if it has yet to stop
218 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200219 self._check_closed()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000220 if self._popen is None:
221 return self._popen
222 return self._popen.poll()
223
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000224 @property
225 def ident(self):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000226 '''
Florent Xiclunab519d232010-03-04 16:10:55 +0000227 Return identifier (PID) of process or `None` if it has yet to start
Benjamin Petersone711caf2008-06-11 16:44:04 +0000228 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200229 self._check_closed()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000230 if self is _current_process:
231 return os.getpid()
232 else:
233 return self._popen and self._popen.pid
234
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000235 pid = ident
Benjamin Petersone711caf2008-06-11 16:44:04 +0000236
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200237 @property
238 def sentinel(self):
239 '''
240 Return a file descriptor (Unix) or handle (Windows) suitable for
241 waiting for process termination.
242 '''
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200243 self._check_closed()
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200244 try:
245 return self._sentinel
246 except AttributeError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +0300247 raise ValueError("process not started") from None
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200248
Benjamin Petersone711caf2008-06-11 16:44:04 +0000249 def __repr__(self):
250 if self is _current_process:
251 status = 'started'
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200252 elif self._closed:
253 status = 'closed'
Benjamin Petersone711caf2008-06-11 16:44:04 +0000254 elif self._parent_pid != os.getpid():
255 status = 'unknown'
256 elif self._popen is None:
257 status = 'initial'
258 else:
259 if self._popen.poll() is not None:
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000260 status = self.exitcode
Benjamin Petersone711caf2008-06-11 16:44:04 +0000261 else:
262 status = 'started'
263
264 if type(status) is int:
265 if status == 0:
266 status = 'stopped'
267 else:
268 status = 'stopped[%s]' % _exitcode_to_name.get(status, status)
269
270 return '<%s(%s, %s%s)>' % (type(self).__name__, self._name,
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100271 status, self.daemon and ' daemon' or '')
Benjamin Petersone711caf2008-06-11 16:44:04 +0000272
273 ##
274
275 def _bootstrap(self):
Richard Oudkerkb1694cf2013-10-16 16:41:56 +0100276 from . import util, context
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100277 global _current_process, _process_counter, _children
Benjamin Petersone711caf2008-06-11 16:44:04 +0000278
279 try:
Richard Oudkerkb1694cf2013-10-16 16:41:56 +0100280 if self._start_method is not None:
281 context._force_start_method(self._start_method)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100282 _process_counter = itertools.count(1)
283 _children = set()
Victor Stinnera6d865c2016-03-25 09:29:50 +0100284 util._close_stdin()
Victor Stinner0f83b152011-06-17 12:31:49 +0200285 old_process = _current_process
Benjamin Petersone711caf2008-06-11 16:44:04 +0000286 _current_process = self
Victor Stinner0f83b152011-06-17 12:31:49 +0200287 try:
288 util._finalizer_registry.clear()
289 util._run_after_forkers()
290 finally:
291 # delay finalization of the old process object until after
292 # _run_after_forkers() is executed
293 del old_process
Benjamin Petersone711caf2008-06-11 16:44:04 +0000294 util.info('child process calling self.run()')
295 try:
296 self.run()
297 exitcode = 0
298 finally:
299 util._exit_function()
300 except SystemExit as e:
301 if not e.args:
302 exitcode = 1
Richard Oudkerk29471de2012-06-06 19:04:57 +0100303 elif isinstance(e.args[0], int):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000304 exitcode = e.args[0]
305 else:
Richard Oudkerk29471de2012-06-06 19:04:57 +0100306 sys.stderr.write(str(e.args[0]) + '\n')
Richard Oudkerk8731d7b2013-11-17 17:24:11 +0000307 exitcode = 1
Benjamin Petersone711caf2008-06-11 16:44:04 +0000308 except:
309 exitcode = 1
310 import traceback
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000311 sys.stderr.write('Process %s:\n' % self.name)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000312 traceback.print_exc()
Antoine Pitrou84a0fbf2012-01-27 10:52:37 +0100313 finally:
314 util.info('process exiting with exitcode %d' % exitcode)
315 sys.stdout.flush()
316 sys.stderr.flush()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000317
Benjamin Petersone711caf2008-06-11 16:44:04 +0000318 return exitcode
319
320#
321# We subclass bytes to avoid accidental transmission of auth keys over network
322#
323
324class AuthenticationString(bytes):
325 def __reduce__(self):
Richard Oudkerkb1694cf2013-10-16 16:41:56 +0100326 from .context import get_spawning_popen
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100327 if get_spawning_popen() is None:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000328 raise TypeError(
329 'Pickling an AuthenticationString object is '
330 'disallowed for security reasons'
331 )
332 return AuthenticationString, (bytes(self),)
333
334#
335# Create object representing the main process
336#
337
Richard Oudkerkb1694cf2013-10-16 16:41:56 +0100338class _MainProcess(BaseProcess):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000339
340 def __init__(self):
341 self._identity = ()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000342 self._name = 'MainProcess'
343 self._parent_pid = None
344 self._popen = None
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200345 self._closed = False
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100346 self._config = {'authkey': AuthenticationString(os.urandom(32)),
Richard Oudkerke9436972013-11-02 17:05:07 +0000347 'semprefix': '/mp'}
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100348 # Note that some versions of FreeBSD only allow named
Richard Oudkerke9436972013-11-02 17:05:07 +0000349 # semaphores to have names of up to 14 characters. Therefore
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100350 # we choose a short prefix.
Richard Oudkerke9436972013-11-02 17:05:07 +0000351 #
352 # On MacOSX in a sandbox it may be necessary to use a
353 # different prefix -- see #19478.
354 #
355 # Everything in self._config will be inherited by descendant
356 # processes.
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100357
Antoine Pitrou13e96cc2017-06-24 19:22:23 +0200358 def close(self):
359 pass
360
Benjamin Petersone711caf2008-06-11 16:44:04 +0000361
362_current_process = _MainProcess()
Richard Oudkerk84ed9a62013-08-14 15:35:41 +0100363_process_counter = itertools.count(1)
364_children = set()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000365del _MainProcess
366
367#
368# Give names to some return codes
369#
370
371_exitcode_to_name = {}
372
373for name, signum in list(signal.__dict__.items()):
374 if name[:3]=='SIG' and '_' not in name:
375 _exitcode_to_name[-signum] = name
Antoine Pitrouc081c0c2011-07-15 22:12:24 +0200376
377# For debug and leak testing
378_dangling = WeakSet()