blob: af6580dc5dcc8a9aea8e17d5b3d33a58eaf2f688 [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)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000236
Richard Oudkerkbd7b5dd2012-06-04 18:59:10 +0100237 # send information to child
238 Popen._tls.process_handle = int(hp)
239 try:
240 dump(prep_data, to_child, HIGHEST_PROTOCOL)
241 dump(process_obj, to_child, HIGHEST_PROTOCOL)
242 finally:
243 del Popen._tls.process_handle
Benjamin Petersone711caf2008-06-11 16:44:04 +0000244
245 @staticmethod
246 def thread_is_spawning():
247 return getattr(Popen._tls, 'process_handle', None) is not None
248
249 @staticmethod
250 def duplicate_for_child(handle):
251 return duplicate(handle, Popen._tls.process_handle)
252
253 def wait(self, timeout=None):
254 if self.returncode is None:
255 if timeout is None:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200256 msecs = _winapi.INFINITE
Benjamin Petersone711caf2008-06-11 16:44:04 +0000257 else:
258 msecs = max(0, int(timeout * 1000 + 0.5))
259
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200260 res = _winapi.WaitForSingleObject(int(self._handle), msecs)
261 if res == _winapi.WAIT_OBJECT_0:
262 code = _winapi.GetExitCodeProcess(self._handle)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000263 if code == TERMINATE:
264 code = -signal.SIGTERM
265 self.returncode = code
266
267 return self.returncode
268
269 def poll(self):
270 return self.wait(timeout=0)
271
272 def terminate(self):
273 if self.returncode is None:
274 try:
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200275 _winapi.TerminateProcess(int(self._handle), TERMINATE)
Richard Oudkerkb3035802012-08-01 17:44:18 +0100276 except OSError:
277 if self.wait(timeout=1.0) is None:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000278 raise
279
280 #
281 #
282 #
283
284 def is_forking(argv):
285 '''
286 Return whether commandline indicates we are forking
287 '''
288 if len(argv) >= 2 and argv[1] == '--multiprocessing-fork':
289 assert len(argv) == 3
290 return True
291 else:
292 return False
293
294
295 def freeze_support():
296 '''
297 Run code for process object if this in not the main process
298 '''
299 if is_forking(sys.argv):
300 main()
301 sys.exit()
302
303
304 def get_command_line():
305 '''
306 Returns prefix of command line used for spawning a child process
307 '''
Richard Oudkerke88a2442012-08-14 11:41:32 +0100308 if getattr(process.current_process(), '_inheriting', False):
Benjamin Petersone711caf2008-06-11 16:44:04 +0000309 raise RuntimeError('''
310 Attempt to start a new process before the current process
311 has finished its bootstrapping phase.
312
313 This probably means that you are on Windows and you have
314 forgotten to use the proper idiom in the main module:
315
316 if __name__ == '__main__':
317 freeze_support()
318 ...
319
320 The "freeze_support()" line can be omitted if the program
321 is not going to be frozen to produce a Windows executable.''')
322
323 if getattr(sys, 'frozen', False):
324 return [sys.executable, '--multiprocessing-fork']
325 else:
326 prog = 'from multiprocessing.forking import main; main()'
Richard Oudkerk77c84f22012-05-18 14:28:02 +0100327 opts = util._args_from_interpreter_flags()
328 return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000329
330
331 def main():
332 '''
333 Run code specifed by data received over pipe
334 '''
335 assert is_forking(sys.argv)
336
337 handle = int(sys.argv[-1])
338 fd = msvcrt.open_osfhandle(handle, os.O_RDONLY)
339 from_parent = os.fdopen(fd, 'rb')
340
341 process.current_process()._inheriting = True
342 preparation_data = load(from_parent)
343 prepare(preparation_data)
344 self = load(from_parent)
345 process.current_process()._inheriting = False
346
347 from_parent.close()
348
349 exitcode = self._bootstrap()
Richard Oudkerk73d9a292012-06-14 15:30:10 +0100350 sys.exit(exitcode)
Benjamin Petersone711caf2008-06-11 16:44:04 +0000351
352
353 def get_preparation_data(name):
354 '''
355 Return info about parent needed by child to unpickle process object
356 '''
357 from .util import _logger, _log_to_stderr
358
359 d = dict(
360 name=name,
361 sys_path=sys.path,
362 sys_argv=sys.argv,
363 log_to_stderr=_log_to_stderr,
364 orig_dir=process.ORIGINAL_DIR,
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000365 authkey=process.current_process().authkey,
Benjamin Petersone711caf2008-06-11 16:44:04 +0000366 )
367
368 if _logger is not None:
369 d['log_level'] = _logger.getEffectiveLevel()
370
brian.curtine2f29982011-04-11 17:56:23 -0500371 if not WINEXE and not WINSERVICE:
Benjamin Petersone711caf2008-06-11 16:44:04 +0000372 main_path = getattr(sys.modules['__main__'], '__file__', None)
373 if not main_path and sys.argv[0] not in ('', '-c'):
374 main_path = sys.argv[0]
375 if main_path is not None:
376 if not os.path.isabs(main_path) and \
377 process.ORIGINAL_DIR is not None:
378 main_path = os.path.join(process.ORIGINAL_DIR, main_path)
379 d['main_path'] = os.path.normpath(main_path)
380
381 return d
382
Benjamin Petersone711caf2008-06-11 16:44:04 +0000383#
384# Prepare current process
385#
386
387old_main_modules = []
388
389def prepare(data):
390 '''
391 Try to get current process ready to unpickle process object
392 '''
393 old_main_modules.append(sys.modules['__main__'])
394
395 if 'name' in data:
Benjamin Peterson58ea9fe2008-08-19 19:17:39 +0000396 process.current_process().name = data['name']
Benjamin Petersone711caf2008-06-11 16:44:04 +0000397
398 if 'authkey' in data:
399 process.current_process()._authkey = data['authkey']
400
401 if 'log_to_stderr' in data and data['log_to_stderr']:
402 util.log_to_stderr()
403
404 if 'log_level' in data:
405 util.get_logger().setLevel(data['log_level'])
406
407 if 'sys_path' in data:
408 sys.path = data['sys_path']
409
410 if 'sys_argv' in data:
411 sys.argv = data['sys_argv']
412
413 if 'dir' in data:
414 os.chdir(data['dir'])
415
416 if 'orig_dir' in data:
417 process.ORIGINAL_DIR = data['orig_dir']
418
419 if 'main_path' in data:
Nick Coghlan793ee1f2011-01-30 01:24:08 +0000420 # XXX (ncoghlan): The following code makes several bogus
421 # assumptions regarding the relationship between __file__
422 # and a module's real name. See PEP 302 and issue #10845
Benjamin Petersone711caf2008-06-11 16:44:04 +0000423 main_path = data['main_path']
424 main_name = os.path.splitext(os.path.basename(main_path))[0]
425 if main_name == '__init__':
426 main_name = os.path.basename(os.path.dirname(main_path))
427
Nick Coghlan793ee1f2011-01-30 01:24:08 +0000428 if main_name == '__main__':
429 main_module = sys.modules['__main__']
430 main_module.__file__ = main_path
431 elif main_name != 'ipython':
432 # Main modules not actually called __main__.py may
433 # contain additional code that should still be executed
Benjamin Petersone711caf2008-06-11 16:44:04 +0000434 import imp
435
436 if main_path is None:
437 dirs = None
438 elif os.path.basename(main_path).startswith('__init__.py'):
439 dirs = [os.path.dirname(os.path.dirname(main_path))]
440 else:
441 dirs = [os.path.dirname(main_path)]
442
443 assert main_name not in sys.modules, main_name
444 file, path_name, etc = imp.find_module(main_name, dirs)
445 try:
446 # We would like to do "imp.load_module('__main__', ...)"
447 # here. However, that would cause 'if __name__ ==
448 # "__main__"' clauses to be executed.
449 main_module = imp.load_module(
450 '__parents_main__', file, path_name, etc
451 )
452 finally:
453 if file:
454 file.close()
455
456 sys.modules['__main__'] = main_module
457 main_module.__name__ = '__main__'
458
459 # Try to make the potentially picklable objects in
460 # sys.modules['__main__'] realize they are in the main
461 # module -- somewhat ugly.
462 for obj in list(main_module.__dict__.values()):
463 try:
464 if obj.__module__ == '__parents_main__':
465 obj.__module__ = '__main__'
466 except Exception:
467 pass