blob: a0b3d68f9fc13ee71246f62297fa84e95114b5ff [file] [log] [blame]
Benjamin Petersone711caf2008-06-11 16:44:04 +00001#
2# Module for starting a process object using os.fork() or CreateProcess()
3#
4# multiprocessing/forking.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
10import os
11import sys
12import signal
13
14from multiprocessing import util, process
15
Richard Oudkerk73d9a292012-06-14 15:30:10 +010016__all__ = ['Popen', 'assert_spawning', 'duplicate', 'close', 'ForkingPickler']
Benjamin Petersone711caf2008-06-11 16:44:04 +000017
18#
19# Check that the current thread is spawning a child process
20#
21
22def assert_spawning(self):
23 if not Popen.thread_is_spawning():
24 raise RuntimeError(
25 '%s objects should only be shared between processes'
26 ' through inheritance' % type(self).__name__
27 )
28
29#
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000030# Try making some callable types picklable
31#
32
Antoine Pitrou846fd302012-03-17 00:23:04 +010033from pickle import Pickler
34from copyreg import dispatch_table
35
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000036class ForkingPickler(Pickler):
Antoine Pitrou846fd302012-03-17 00:23:04 +010037 _extra_reducers = {}
38 def __init__(self, *args):
39 Pickler.__init__(self, *args)
40 self.dispatch_table = dispatch_table.copy()
41 self.dispatch_table.update(self._extra_reducers)
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000042 @classmethod
43 def register(cls, type, reduce):
Antoine Pitrou846fd302012-03-17 00:23:04 +010044 cls._extra_reducers[type] = reduce
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000045
46def _reduce_method(m):
47 if m.__self__ is None:
48 return getattr, (m.__class__, m.__func__.__name__)
49 else:
50 return getattr, (m.__self__, m.__func__.__name__)
51class _C:
52 def f(self):
53 pass
54ForkingPickler.register(type(_C().f), _reduce_method)
55
56
57def _reduce_method_descriptor(m):
58 return getattr, (m.__objclass__, m.__name__)
59ForkingPickler.register(type(list.append), _reduce_method_descriptor)
60ForkingPickler.register(type(int.__add__), _reduce_method_descriptor)
61
62try:
63 from functools import partial
64except ImportError:
65 pass
66else:
67 def _reduce_partial(p):
68 return _rebuild_partial, (p.func, p.args, p.keywords or {})
69 def _rebuild_partial(func, args, keywords):
70 return partial(func, *args, **keywords)
71 ForkingPickler.register(partial, _reduce_partial)
72
73#
Benjamin Petersone711caf2008-06-11 16:44:04 +000074# Unix
75#
76
77if sys.platform != 'win32':
Benjamin Petersone711caf2008-06-11 16:44:04 +000078 duplicate = os.dup
79 close = os.close
80
81 #
82 # We define a Popen class similar to the one from subprocess, but
83 # whose constructor takes a process object as its argument.
84 #
85
86 class Popen(object):
87
88 def __init__(self, process_obj):
89 sys.stdout.flush()
90 sys.stderr.flush()
91 self.returncode = None
92
Antoine Pitrou176f07d2011-06-06 19:35:31 +020093 r, w = os.pipe()
94 self.sentinel = r
95
Benjamin Petersone711caf2008-06-11 16:44:04 +000096 self.pid = os.fork()
97 if self.pid == 0:
Antoine Pitrou176f07d2011-06-06 19:35:31 +020098 os.close(r)
Benjamin Petersone711caf2008-06-11 16:44:04 +000099 if 'random' in sys.modules:
100 import random
101 random.seed()
102 code = process_obj._bootstrap()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000103 os._exit(code)
104
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200105 # `w` will be closed when the child exits, at which point `r`
106 # will become ready for reading (using e.g. select()).
107 os.close(w)
108 util.Finalize(self, os.close, (r,))
109
Benjamin Petersone711caf2008-06-11 16:44:04 +0000110 def poll(self, flag=os.WNOHANG):
111 if self.returncode is None:
Florent Xicluna998171f2010-03-08 13:32:17 +0000112 try:
113 pid, sts = os.waitpid(self.pid, flag)
114 except os.error:
115 # Child process not yet created. See #1731717
116 # e.errno == errno.ECHILD == 10
117 return None
Benjamin Petersone711caf2008-06-11 16:44:04 +0000118 if pid == self.pid:
119 if os.WIFSIGNALED(sts):
120 self.returncode = -os.WTERMSIG(sts)
121 else:
122 assert os.WIFEXITED(sts)
123 self.returncode = os.WEXITSTATUS(sts)
124 return self.returncode
125
126 def wait(self, timeout=None):
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200127 if self.returncode is None:
128 if timeout is not None:
Richard Oudkerk59d54042012-05-10 16:11:12 +0100129 from .connection import wait
130 if not wait([self.sentinel], timeout):
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200131 return None
Richard Oudkerk59d54042012-05-10 16:11:12 +0100132 # This shouldn't block if wait() returned successfully.
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200133 return self.poll(os.WNOHANG if timeout == 0.0 else 0)
134 return self.returncode
Benjamin Petersone711caf2008-06-11 16:44:04 +0000135
136 def terminate(self):
137 if self.returncode is None:
138 try:
139 os.kill(self.pid, signal.SIGTERM)
Florent Xicluna04842a82011-11-11 20:05:50 +0100140 except OSError:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000141 if self.wait(timeout=0.1) is None:
142 raise
143
144 @staticmethod
145 def thread_is_spawning():
146 return False
147
148#
149# Windows
150#
151
152else:
153 import _thread
154 import msvcrt
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200155 import _winapi
Benjamin Petersone711caf2008-06-11 16:44:04 +0000156
Florent Xicluna04842a82011-11-11 20:05:50 +0100157 from pickle import load, HIGHEST_PROTOCOL
Benjamin Petersone711caf2008-06-11 16:44:04 +0000158
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +0000159 def dump(obj, file, protocol=None):
160 ForkingPickler(file, protocol).dump(obj)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000161
162 #
163 #
164 #
165
166 TERMINATE = 0x10000
167 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
brian.curtine2f29982011-04-11 17:56:23 -0500168 WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
Benjamin Petersone711caf2008-06-11 16:44:04 +0000169
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200170 close = _winapi.CloseHandle
Benjamin Petersone711caf2008-06-11 16:44:04 +0000171
172 #
173 # _python_exe is the assumed path to the python executable.
174 # People embedding Python want to modify it.
175 #
176
brian.curtine2f29982011-04-11 17:56:23 -0500177 if WINSERVICE:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000178 _python_exe = os.path.join(sys.exec_prefix, 'python.exe')
179 else:
180 _python_exe = sys.executable
181
182 def set_executable(exe):
183 global _python_exe
184 _python_exe = exe
185
186 #
187 #
188 #
189
190 def duplicate(handle, target_process=None, inheritable=False):
191 if target_process is None:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200192 target_process = _winapi.GetCurrentProcess()
193 return _winapi.DuplicateHandle(
194 _winapi.GetCurrentProcess(), handle, target_process,
195 0, inheritable, _winapi.DUPLICATE_SAME_ACCESS
196 )
Benjamin Petersone711caf2008-06-11 16:44:04 +0000197
198 #
199 # We define a Popen class similar to the one from subprocess, but
200 # whose constructor takes a process object as its argument.
201 #
202
203 class Popen(object):
204 '''
205 Start a subprocess to run the code of a process object
206 '''
207 _tls = _thread._local()
208
209 def __init__(self, process_obj):
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100210 cmd = ' '.join('"%s"' % x for x in get_command_line())
211 prep_data = get_preparation_data(process_obj._name)
212
Benjamin Petersone711caf2008-06-11 16:44:04 +0000213 # create pipe for communication with child
214 rfd, wfd = os.pipe()
215
216 # get handle for read end of the pipe and make it inheritable
217 rhandle = duplicate(msvcrt.get_osfhandle(rfd), inheritable=True)
218 os.close(rfd)
219
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100220 with open(wfd, 'wb', closefd=True) as to_child:
221 # start process
222 try:
223 hp, ht, pid, tid = _winapi.CreateProcess(
224 _python_exe, cmd + (' %s' % rhandle),
225 None, None, 1, 0, None, None, None
226 )
227 _winapi.CloseHandle(ht)
228 finally:
229 close(rhandle)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000230
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100231 # set attributes of self
232 self.pid = pid
233 self.returncode = None
234 self._handle = hp
235 self.sentinel = int(hp)
Richard Oudkerk021f4c22012-11-15 18:16:35 +0000236 util.Finalize(self, _winapi.CloseHandle, (self.sentinel,))
Benjamin Petersone711caf2008-06-11 16:44:04 +0000237
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100238 # send information to child
239 Popen._tls.process_handle = int(hp)
240 try:
241 dump(prep_data, to_child, HIGHEST_PROTOCOL)
242 dump(process_obj, to_child, HIGHEST_PROTOCOL)
243 finally:
244 del Popen._tls.process_handle
Benjamin Petersone711caf2008-06-11 16:44:04 +0000245
246 @staticmethod
247 def thread_is_spawning():
248 return getattr(Popen._tls, 'process_handle', None) is not None
249
250 @staticmethod
251 def duplicate_for_child(handle):
252 return duplicate(handle, Popen._tls.process_handle)
253
254 def wait(self, timeout=None):
255 if self.returncode is None:
256 if timeout is None:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200257 msecs = _winapi.INFINITE
Benjamin Petersone711caf2008-06-11 16:44:04 +0000258 else:
259 msecs = max(0, int(timeout * 1000 + 0.5))
260
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200261 res = _winapi.WaitForSingleObject(int(self._handle), msecs)
262 if res == _winapi.WAIT_OBJECT_0:
263 code = _winapi.GetExitCodeProcess(self._handle)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000264 if code == TERMINATE:
265 code = -signal.SIGTERM
266 self.returncode = code
267
268 return self.returncode
269
270 def poll(self):
271 return self.wait(timeout=0)
272
273 def terminate(self):
274 if self.returncode is None:
275 try:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200276 _winapi.TerminateProcess(int(self._handle), TERMINATE)
Richard Oudkerkb3035802012-08-01 17:44:18 +0100277 except OSError:
278 if self.wait(timeout=1.0) is None:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000279 raise
280
281 #
282 #
283 #
284
285 def is_forking(argv):
286 '''
287 Return whether commandline indicates we are forking
288 '''
289 if len(argv) >= 2 and argv[1] == '--multiprocessing-fork':
290 assert len(argv) == 3
291 return True
292 else:
293 return False
294
295
296 def freeze_support():
297 '''
298 Run code for process object if this in not the main process
299 '''
300 if is_forking(sys.argv):
301 main()
302 sys.exit()
303
304
305 def get_command_line():
306 '''
307 Returns prefix of command line used for spawning a child process
308 '''
Richard Oudkerke88a2442012-08-14 11:41:32 +0100309 if getattr(process.current_process(), '_inheriting', False):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000310 raise RuntimeError('''
311 Attempt to start a new process before the current process
312 has finished its bootstrapping phase.
313
314 This probably means that you are on Windows and you have
315 forgotten to use the proper idiom in the main module:
316
317 if __name__ == '__main__':
318 freeze_support()
319 ...
320
321 The "freeze_support()" line can be omitted if the program
322 is not going to be frozen to produce a Windows executable.''')
323
324 if getattr(sys, 'frozen', False):
325 return [sys.executable, '--multiprocessing-fork']
326 else:
327 prog = 'from multiprocessing.forking import main; main()'
Richard Oudkerk77c84f22012-05-18 14:28:02 +0100328 opts = util._args_from_interpreter_flags()
329 return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000330
331
332 def main():
333 '''
334 Run code specifed by data received over pipe
335 '''
336 assert is_forking(sys.argv)
337
338 handle = int(sys.argv[-1])
339 fd = msvcrt.open_osfhandle(handle, os.O_RDONLY)
340 from_parent = os.fdopen(fd, 'rb')
341
342 process.current_process()._inheriting = True
343 preparation_data = load(from_parent)
344 prepare(preparation_data)
345 self = load(from_parent)
346 process.current_process()._inheriting = False
347
348 from_parent.close()
349
350 exitcode = self._bootstrap()
Richard Oudkerk73d9a292012-06-14 15:30:10 +0100351 sys.exit(exitcode)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000352
353
354 def get_preparation_data(name):
355 '''
356 Return info about parent needed by child to unpickle process object
357 '''
358 from .util import _logger, _log_to_stderr
359
360 d = dict(
361 name=name,
362 sys_path=sys.path,
363 sys_argv=sys.argv,
364 log_to_stderr=_log_to_stderr,
365 orig_dir=process.ORIGINAL_DIR,
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000366 authkey=process.current_process().authkey,
Benjamin Petersone711caf2008-06-11 16:44:04 +0000367 )
368
369 if _logger is not None:
370 d['log_level'] = _logger.getEffectiveLevel()
371
brian.curtine2f29982011-04-11 17:56:23 -0500372 if not WINEXE and not WINSERVICE:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000373 main_path = getattr(sys.modules['__main__'], '__file__', None)
374 if not main_path and sys.argv[0] not in ('', '-c'):
375 main_path = sys.argv[0]
376 if main_path is not None:
377 if not os.path.isabs(main_path) and \
378 process.ORIGINAL_DIR is not None:
379 main_path = os.path.join(process.ORIGINAL_DIR, main_path)
380 d['main_path'] = os.path.normpath(main_path)
381
382 return d
383
Benjamin Petersone711caf2008-06-11 16:44:04 +0000384#
385# Prepare current process
386#
387
388old_main_modules = []
389
390def prepare(data):
391 '''
392 Try to get current process ready to unpickle process object
393 '''
394 old_main_modules.append(sys.modules['__main__'])
395
396 if 'name' in data:
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000397 process.current_process().name = data['name']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000398
399 if 'authkey' in data:
400 process.current_process()._authkey = data['authkey']
401
402 if 'log_to_stderr' in data and data['log_to_stderr']:
403 util.log_to_stderr()
404
405 if 'log_level' in data:
406 util.get_logger().setLevel(data['log_level'])
407
408 if 'sys_path' in data:
409 sys.path = data['sys_path']
410
411 if 'sys_argv' in data:
412 sys.argv = data['sys_argv']
413
414 if 'dir' in data:
415 os.chdir(data['dir'])
416
417 if 'orig_dir' in data:
418 process.ORIGINAL_DIR = data['orig_dir']
419
420 if 'main_path' in data:
Nick Coghlan793ee1f2011-01-30 01:24:08 +0000421 # XXX (ncoghlan): The following code makes several bogus
422 # assumptions regarding the relationship between __file__
423 # and a module's real name. See PEP 302 and issue #10845
Benjamin Petersone711caf2008-06-11 16:44:04 +0000424 main_path = data['main_path']
425 main_name = os.path.splitext(os.path.basename(main_path))[0]
426 if main_name == '__init__':
427 main_name = os.path.basename(os.path.dirname(main_path))
428
Nick Coghlan793ee1f2011-01-30 01:24:08 +0000429 if main_name == '__main__':
430 main_module = sys.modules['__main__']
431 main_module.__file__ = main_path
432 elif main_name != 'ipython':
433 # Main modules not actually called __main__.py may
434 # contain additional code that should still be executed
Benjamin Petersone711caf2008-06-11 16:44:04 +0000435 import imp
436
437 if main_path is None:
438 dirs = None
439 elif os.path.basename(main_path).startswith('__init__.py'):
440 dirs = [os.path.dirname(os.path.dirname(main_path))]
441 else:
442 dirs = [os.path.dirname(main_path)]
443
444 assert main_name not in sys.modules, main_name
Richard Oudkerk5046e972012-10-08 13:07:00 +0100445 sys.modules.pop('__mp_main__', None)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000446 file, path_name, etc = imp.find_module(main_name, dirs)
447 try:
Richard Oudkerk5046e972012-10-08 13:07:00 +0100448 # We should not do 'imp.load_module("__main__", ...)'
449 # since that would execute 'if __name__ == "__main__"'
450 # clauses, potentially causing a psuedo fork bomb.
Benjamin Petersone711caf2008-06-11 16:44:04 +0000451 main_module = imp.load_module(
Richard Oudkerk5046e972012-10-08 13:07:00 +0100452 '__mp_main__', file, path_name, etc
Benjamin Petersone711caf2008-06-11 16:44:04 +0000453 )
454 finally:
455 if file:
456 file.close()
457
Richard Oudkerk5046e972012-10-08 13:07:00 +0100458 sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module