blob: 0bb21c469d5edfecf2c7b50f5c8495bcb3f3507c [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
Richard Oudkerk7aaa1ef2013-02-26 12:39:57 +000013import errno
Benjamin Petersone711caf2008-06-11 16:44:04 +000014
15from multiprocessing import util, process
16
Richard Oudkerk73d9a292012-06-14 15:30:10 +010017__all__ = ['Popen', 'assert_spawning', 'duplicate', 'close', 'ForkingPickler']
Benjamin Petersone711caf2008-06-11 16:44:04 +000018
19#
20# Check that the current thread is spawning a child process
21#
22
23def assert_spawning(self):
24 if not Popen.thread_is_spawning():
25 raise RuntimeError(
26 '%s objects should only be shared between processes'
27 ' through inheritance' % type(self).__name__
28 )
29
30#
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000031# Try making some callable types picklable
32#
33
Antoine Pitrou846fd302012-03-17 00:23:04 +010034from pickle import Pickler
35from copyreg import dispatch_table
36
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000037class ForkingPickler(Pickler):
Antoine Pitrou846fd302012-03-17 00:23:04 +010038 _extra_reducers = {}
39 def __init__(self, *args):
40 Pickler.__init__(self, *args)
41 self.dispatch_table = dispatch_table.copy()
42 self.dispatch_table.update(self._extra_reducers)
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000043 @classmethod
44 def register(cls, type, reduce):
Antoine Pitrou846fd302012-03-17 00:23:04 +010045 cls._extra_reducers[type] = reduce
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +000046
47def _reduce_method(m):
48 if m.__self__ is None:
49 return getattr, (m.__class__, m.__func__.__name__)
50 else:
51 return getattr, (m.__self__, m.__func__.__name__)
52class _C:
53 def f(self):
54 pass
55ForkingPickler.register(type(_C().f), _reduce_method)
56
57
58def _reduce_method_descriptor(m):
59 return getattr, (m.__objclass__, m.__name__)
60ForkingPickler.register(type(list.append), _reduce_method_descriptor)
61ForkingPickler.register(type(int.__add__), _reduce_method_descriptor)
62
63try:
64 from functools import partial
65except ImportError:
66 pass
67else:
68 def _reduce_partial(p):
69 return _rebuild_partial, (p.func, p.args, p.keywords or {})
70 def _rebuild_partial(func, args, keywords):
71 return partial(func, *args, **keywords)
72 ForkingPickler.register(partial, _reduce_partial)
73
74#
Benjamin Petersone711caf2008-06-11 16:44:04 +000075# Unix
76#
77
78if sys.platform != 'win32':
Benjamin Petersone711caf2008-06-11 16:44:04 +000079 duplicate = os.dup
80 close = os.close
81
82 #
83 # We define a Popen class similar to the one from subprocess, but
84 # whose constructor takes a process object as its argument.
85 #
86
87 class Popen(object):
88
89 def __init__(self, process_obj):
90 sys.stdout.flush()
91 sys.stderr.flush()
92 self.returncode = None
93
Antoine Pitrou176f07d2011-06-06 19:35:31 +020094 r, w = os.pipe()
95 self.sentinel = r
96
Benjamin Petersone711caf2008-06-11 16:44:04 +000097 self.pid = os.fork()
98 if self.pid == 0:
Antoine Pitrou176f07d2011-06-06 19:35:31 +020099 os.close(r)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000100 if 'random' in sys.modules:
101 import random
102 random.seed()
103 code = process_obj._bootstrap()
Benjamin Petersone711caf2008-06-11 16:44:04 +0000104 os._exit(code)
105
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200106 # `w` will be closed when the child exits, at which point `r`
107 # will become ready for reading (using e.g. select()).
108 os.close(w)
109 util.Finalize(self, os.close, (r,))
110
Benjamin Petersone711caf2008-06-11 16:44:04 +0000111 def poll(self, flag=os.WNOHANG):
112 if self.returncode is None:
Richard Oudkerk7aaa1ef2013-02-26 12:39:57 +0000113 while True:
114 try:
115 pid, sts = os.waitpid(self.pid, flag)
116 except os.error as e:
117 if e.errno == errno.EINTR:
118 continue
119 # Child process not yet created. See #1731717
120 # e.errno == errno.ECHILD == 10
121 return None
122 else:
123 break
Benjamin Petersone711caf2008-06-11 16:44:04 +0000124 if pid == self.pid:
125 if os.WIFSIGNALED(sts):
126 self.returncode = -os.WTERMSIG(sts)
127 else:
128 assert os.WIFEXITED(sts)
129 self.returncode = os.WEXITSTATUS(sts)
130 return self.returncode
131
132 def wait(self, timeout=None):
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200133 if self.returncode is None:
134 if timeout is not None:
Richard Oudkerk59d54042012-05-10 16:11:12 +0100135 from .connection import wait
136 if not wait([self.sentinel], timeout):
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200137 return None
Richard Oudkerk59d54042012-05-10 16:11:12 +0100138 # This shouldn't block if wait() returned successfully.
Antoine Pitrou176f07d2011-06-06 19:35:31 +0200139 return self.poll(os.WNOHANG if timeout == 0.0 else 0)
140 return self.returncode
Benjamin Petersone711caf2008-06-11 16:44:04 +0000141
142 def terminate(self):
143 if self.returncode is None:
144 try:
145 os.kill(self.pid, signal.SIGTERM)
Florent Xicluna04842a82011-11-11 20:05:50 +0100146 except OSError:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000147 if self.wait(timeout=0.1) is None:
148 raise
149
150 @staticmethod
151 def thread_is_spawning():
152 return False
153
154#
155# Windows
156#
157
158else:
159 import _thread
160 import msvcrt
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200161 import _winapi
Benjamin Petersone711caf2008-06-11 16:44:04 +0000162
Florent Xicluna04842a82011-11-11 20:05:50 +0100163 from pickle import load, HIGHEST_PROTOCOL
Benjamin Petersone711caf2008-06-11 16:44:04 +0000164
Amaury Forgeot d'Arc949d47d2008-08-19 21:30:55 +0000165 def dump(obj, file, protocol=None):
166 ForkingPickler(file, protocol).dump(obj)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000167
168 #
169 #
170 #
171
172 TERMINATE = 0x10000
173 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
brian.curtine2f29982011-04-11 17:56:23 -0500174 WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
Benjamin Petersone711caf2008-06-11 16:44:04 +0000175
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200176 close = _winapi.CloseHandle
Benjamin Petersone711caf2008-06-11 16:44:04 +0000177
178 #
179 # _python_exe is the assumed path to the python executable.
180 # People embedding Python want to modify it.
181 #
182
brian.curtine2f29982011-04-11 17:56:23 -0500183 if WINSERVICE:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000184 _python_exe = os.path.join(sys.exec_prefix, 'python.exe')
185 else:
186 _python_exe = sys.executable
187
188 def set_executable(exe):
189 global _python_exe
190 _python_exe = exe
191
192 #
193 #
194 #
195
196 def duplicate(handle, target_process=None, inheritable=False):
197 if target_process is None:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200198 target_process = _winapi.GetCurrentProcess()
199 return _winapi.DuplicateHandle(
200 _winapi.GetCurrentProcess(), handle, target_process,
201 0, inheritable, _winapi.DUPLICATE_SAME_ACCESS
202 )
Benjamin Petersone711caf2008-06-11 16:44:04 +0000203
204 #
205 # We define a Popen class similar to the one from subprocess, but
206 # whose constructor takes a process object as its argument.
207 #
208
209 class Popen(object):
210 '''
211 Start a subprocess to run the code of a process object
212 '''
213 _tls = _thread._local()
214
215 def __init__(self, process_obj):
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100216 cmd = ' '.join('"%s"' % x for x in get_command_line())
217 prep_data = get_preparation_data(process_obj._name)
218
Benjamin Petersone711caf2008-06-11 16:44:04 +0000219 # create pipe for communication with child
220 rfd, wfd = os.pipe()
221
222 # get handle for read end of the pipe and make it inheritable
223 rhandle = duplicate(msvcrt.get_osfhandle(rfd), inheritable=True)
224 os.close(rfd)
225
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100226 with open(wfd, 'wb', closefd=True) as to_child:
227 # start process
228 try:
229 hp, ht, pid, tid = _winapi.CreateProcess(
230 _python_exe, cmd + (' %s' % rhandle),
231 None, None, 1, 0, None, None, None
232 )
233 _winapi.CloseHandle(ht)
234 finally:
235 close(rhandle)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000236
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100237 # set attributes of self
238 self.pid = pid
239 self.returncode = None
240 self._handle = hp
241 self.sentinel = int(hp)
Richard Oudkerk021f4c22012-11-15 18:16:35 +0000242 util.Finalize(self, _winapi.CloseHandle, (self.sentinel,))
Benjamin Petersone711caf2008-06-11 16:44:04 +0000243
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100244 # send information to child
245 Popen._tls.process_handle = int(hp)
246 try:
247 dump(prep_data, to_child, HIGHEST_PROTOCOL)
248 dump(process_obj, to_child, HIGHEST_PROTOCOL)
249 finally:
250 del Popen._tls.process_handle
Benjamin Petersone711caf2008-06-11 16:44:04 +0000251
252 @staticmethod
253 def thread_is_spawning():
254 return getattr(Popen._tls, 'process_handle', None) is not None
255
256 @staticmethod
257 def duplicate_for_child(handle):
258 return duplicate(handle, Popen._tls.process_handle)
259
260 def wait(self, timeout=None):
261 if self.returncode is None:
262 if timeout is None:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200263 msecs = _winapi.INFINITE
Benjamin Petersone711caf2008-06-11 16:44:04 +0000264 else:
265 msecs = max(0, int(timeout * 1000 + 0.5))
266
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200267 res = _winapi.WaitForSingleObject(int(self._handle), msecs)
268 if res == _winapi.WAIT_OBJECT_0:
269 code = _winapi.GetExitCodeProcess(self._handle)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000270 if code == TERMINATE:
271 code = -signal.SIGTERM
272 self.returncode = code
273
274 return self.returncode
275
276 def poll(self):
277 return self.wait(timeout=0)
278
279 def terminate(self):
280 if self.returncode is None:
281 try:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200282 _winapi.TerminateProcess(int(self._handle), TERMINATE)
Richard Oudkerkb3035802012-08-01 17:44:18 +0100283 except OSError:
284 if self.wait(timeout=1.0) is None:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000285 raise
286
287 #
288 #
289 #
290
291 def is_forking(argv):
292 '''
293 Return whether commandline indicates we are forking
294 '''
295 if len(argv) >= 2 and argv[1] == '--multiprocessing-fork':
296 assert len(argv) == 3
297 return True
298 else:
299 return False
300
301
302 def freeze_support():
303 '''
304 Run code for process object if this in not the main process
305 '''
306 if is_forking(sys.argv):
307 main()
308 sys.exit()
309
310
311 def get_command_line():
312 '''
313 Returns prefix of command line used for spawning a child process
314 '''
Richard Oudkerke88a2442012-08-14 11:41:32 +0100315 if getattr(process.current_process(), '_inheriting', False):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000316 raise RuntimeError('''
317 Attempt to start a new process before the current process
318 has finished its bootstrapping phase.
319
320 This probably means that you are on Windows and you have
321 forgotten to use the proper idiom in the main module:
322
323 if __name__ == '__main__':
324 freeze_support()
325 ...
326
327 The "freeze_support()" line can be omitted if the program
328 is not going to be frozen to produce a Windows executable.''')
329
330 if getattr(sys, 'frozen', False):
331 return [sys.executable, '--multiprocessing-fork']
332 else:
333 prog = 'from multiprocessing.forking import main; main()'
Richard Oudkerk77c84f22012-05-18 14:28:02 +0100334 opts = util._args_from_interpreter_flags()
335 return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000336
337
338 def main():
339 '''
340 Run code specifed by data received over pipe
341 '''
342 assert is_forking(sys.argv)
343
344 handle = int(sys.argv[-1])
345 fd = msvcrt.open_osfhandle(handle, os.O_RDONLY)
346 from_parent = os.fdopen(fd, 'rb')
347
348 process.current_process()._inheriting = True
349 preparation_data = load(from_parent)
350 prepare(preparation_data)
351 self = load(from_parent)
352 process.current_process()._inheriting = False
353
354 from_parent.close()
355
356 exitcode = self._bootstrap()
Richard Oudkerk73d9a292012-06-14 15:30:10 +0100357 sys.exit(exitcode)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000358
359
360 def get_preparation_data(name):
361 '''
362 Return info about parent needed by child to unpickle process object
363 '''
364 from .util import _logger, _log_to_stderr
365
366 d = dict(
367 name=name,
368 sys_path=sys.path,
369 sys_argv=sys.argv,
370 log_to_stderr=_log_to_stderr,
371 orig_dir=process.ORIGINAL_DIR,
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000372 authkey=process.current_process().authkey,
Benjamin Petersone711caf2008-06-11 16:44:04 +0000373 )
374
375 if _logger is not None:
376 d['log_level'] = _logger.getEffectiveLevel()
377
brian.curtine2f29982011-04-11 17:56:23 -0500378 if not WINEXE and not WINSERVICE:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000379 main_path = getattr(sys.modules['__main__'], '__file__', None)
380 if not main_path and sys.argv[0] not in ('', '-c'):
381 main_path = sys.argv[0]
382 if main_path is not None:
383 if not os.path.isabs(main_path) and \
384 process.ORIGINAL_DIR is not None:
385 main_path = os.path.join(process.ORIGINAL_DIR, main_path)
386 d['main_path'] = os.path.normpath(main_path)
387
388 return d
389
Benjamin Petersone711caf2008-06-11 16:44:04 +0000390#
391# Prepare current process
392#
393
394old_main_modules = []
395
396def prepare(data):
397 '''
398 Try to get current process ready to unpickle process object
399 '''
400 old_main_modules.append(sys.modules['__main__'])
401
402 if 'name' in data:
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000403 process.current_process().name = data['name']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000404
405 if 'authkey' in data:
406 process.current_process()._authkey = data['authkey']
407
408 if 'log_to_stderr' in data and data['log_to_stderr']:
409 util.log_to_stderr()
410
411 if 'log_level' in data:
412 util.get_logger().setLevel(data['log_level'])
413
414 if 'sys_path' in data:
415 sys.path = data['sys_path']
416
417 if 'sys_argv' in data:
418 sys.argv = data['sys_argv']
419
420 if 'dir' in data:
421 os.chdir(data['dir'])
422
423 if 'orig_dir' in data:
424 process.ORIGINAL_DIR = data['orig_dir']
425
426 if 'main_path' in data:
Nick Coghlan793ee1f2011-01-30 01:24:08 +0000427 # XXX (ncoghlan): The following code makes several bogus
428 # assumptions regarding the relationship between __file__
429 # and a module's real name. See PEP 302 and issue #10845
Benjamin Petersone711caf2008-06-11 16:44:04 +0000430 main_path = data['main_path']
431 main_name = os.path.splitext(os.path.basename(main_path))[0]
432 if main_name == '__init__':
433 main_name = os.path.basename(os.path.dirname(main_path))
434
Nick Coghlan793ee1f2011-01-30 01:24:08 +0000435 if main_name == '__main__':
436 main_module = sys.modules['__main__']
437 main_module.__file__ = main_path
438 elif main_name != 'ipython':
439 # Main modules not actually called __main__.py may
440 # contain additional code that should still be executed
Benjamin Petersone711caf2008-06-11 16:44:04 +0000441 import imp
442
443 if main_path is None:
444 dirs = None
445 elif os.path.basename(main_path).startswith('__init__.py'):
446 dirs = [os.path.dirname(os.path.dirname(main_path))]
447 else:
448 dirs = [os.path.dirname(main_path)]
449
450 assert main_name not in sys.modules, main_name
451 file, path_name, etc = imp.find_module(main_name, dirs)
452 try:
453 # We would like to do "imp.load_module('__main__', ...)"
454 # here. However, that would cause 'if __name__ ==
455 # "__main__"' clauses to be executed.
456 main_module = imp.load_module(
457 '__parents_main__', file, path_name, etc
458 )
459 finally:
460 if file:
461 file.close()
462
463 sys.modules['__main__'] = main_module
464 main_module.__name__ = '__main__'
465
466 # Try to make the potentially picklable objects in
467 # sys.modules['__main__'] realize they are in the main
468 # module -- somewhat ugly.
469 for obj in list(main_module.__dict__.values()):
470 try:
471 if obj.__module__ == '__parents_main__':
472 obj.__module__ = '__main__'
473 except Exception:
474 pass