| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Module for starting a process object using os.fork() or CreateProcess() | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # multiprocessing/forking.py | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2010-12-14 01:38:16 +00:00
										 |  |  | # Copyright (c) 2006-2008, R Oudkerk | 
					
						
							|  |  |  | # All rights reserved. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  | # modification, are permitted provided that the following conditions | 
					
						
							|  |  |  | # are met: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # 1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  | #    notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  | # 2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  | #    notice, this list of conditions and the following disclaimer in the | 
					
						
							|  |  |  | #    documentation and/or other materials provided with the distribution. | 
					
						
							|  |  |  | # 3. Neither the name of author nor the names of any contributors may be | 
					
						
							|  |  |  | #    used to endorse or promote products derived from this software | 
					
						
							|  |  |  | #    without specific prior written permission. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND | 
					
						
							|  |  |  | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
					
						
							|  |  |  | # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
					
						
							|  |  |  | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
					
						
							|  |  |  | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
					
						
							|  |  |  | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
					
						
							|  |  |  | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
					
						
							|  |  |  | # SUCH DAMAGE. | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import signal | 
					
						
							| 
									
										
										
										
											2013-02-26 12:39:57 +00:00
										 |  |  | import errno | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | from multiprocessing import util, process | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-19 21:30:55 +00:00
										 |  |  | __all__ = ['Popen', 'assert_spawning', 'exit', 'duplicate', 'close', 'ForkingPickler'] | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Check that the current thread is spawning a child process | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def assert_spawning(self): | 
					
						
							|  |  |  |     if not Popen.thread_is_spawning(): | 
					
						
							|  |  |  |         raise RuntimeError( | 
					
						
							|  |  |  |             '%s objects should only be shared between processes' | 
					
						
							|  |  |  |             ' through inheritance' % type(self).__name__ | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-19 21:30:55 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Try making some callable types picklable | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from pickle import _Pickler as Pickler | 
					
						
							|  |  |  | class ForkingPickler(Pickler): | 
					
						
							|  |  |  |     dispatch = Pickler.dispatch.copy() | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def register(cls, type, reduce): | 
					
						
							|  |  |  |         def dispatcher(self, obj): | 
					
						
							|  |  |  |             rv = reduce(obj) | 
					
						
							|  |  |  |             if isinstance(rv, str): | 
					
						
							|  |  |  |                 self.save_global(obj, rv) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.save_reduce(obj=obj, *rv) | 
					
						
							|  |  |  |         cls.dispatch[type] = dispatcher | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _reduce_method(m): | 
					
						
							|  |  |  |     if m.__self__ is None: | 
					
						
							|  |  |  |         return getattr, (m.__class__, m.__func__.__name__) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return getattr, (m.__self__, m.__func__.__name__) | 
					
						
							|  |  |  | class _C: | 
					
						
							|  |  |  |     def f(self): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | ForkingPickler.register(type(_C().f), _reduce_method) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _reduce_method_descriptor(m): | 
					
						
							|  |  |  |     return getattr, (m.__objclass__, m.__name__) | 
					
						
							|  |  |  | ForkingPickler.register(type(list.append), _reduce_method_descriptor) | 
					
						
							|  |  |  | ForkingPickler.register(type(int.__add__), _reduce_method_descriptor) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     from functools import partial | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     def _reduce_partial(p): | 
					
						
							|  |  |  |         return _rebuild_partial, (p.func, p.args, p.keywords or {}) | 
					
						
							|  |  |  |     def _rebuild_partial(func, args, keywords): | 
					
						
							|  |  |  |         return partial(func, *args, **keywords) | 
					
						
							|  |  |  |     ForkingPickler.register(partial, _reduce_partial) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Unix | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if sys.platform != 'win32': | 
					
						
							|  |  |  |     import time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     exit = os._exit | 
					
						
							|  |  |  |     duplicate = os.dup | 
					
						
							|  |  |  |     close = os.close | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # We define a Popen class similar to the one from subprocess, but | 
					
						
							|  |  |  |     # whose constructor takes a process object as its argument. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Popen(object): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, process_obj): | 
					
						
							|  |  |  |             sys.stdout.flush() | 
					
						
							|  |  |  |             sys.stderr.flush() | 
					
						
							|  |  |  |             self.returncode = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.pid = os.fork() | 
					
						
							|  |  |  |             if self.pid == 0: | 
					
						
							|  |  |  |                 if 'random' in sys.modules: | 
					
						
							|  |  |  |                     import random | 
					
						
							|  |  |  |                     random.seed() | 
					
						
							|  |  |  |                 code = process_obj._bootstrap() | 
					
						
							|  |  |  |                 os._exit(code) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def poll(self, flag=os.WNOHANG): | 
					
						
							|  |  |  |             if self.returncode is None: | 
					
						
							| 
									
										
										
										
											2013-02-26 12:39:57 +00:00
										 |  |  |                 while True: | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         pid, sts = os.waitpid(self.pid, flag) | 
					
						
							|  |  |  |                     except os.error as e: | 
					
						
							|  |  |  |                         if e.errno == errno.EINTR: | 
					
						
							|  |  |  |                             continue | 
					
						
							|  |  |  |                         # Child process not yet created. See #1731717 | 
					
						
							|  |  |  |                         # e.errno == errno.ECHILD == 10 | 
					
						
							|  |  |  |                         return None | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         break | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |                 if pid == self.pid: | 
					
						
							|  |  |  |                     if os.WIFSIGNALED(sts): | 
					
						
							|  |  |  |                         self.returncode = -os.WTERMSIG(sts) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         assert os.WIFEXITED(sts) | 
					
						
							|  |  |  |                         self.returncode = os.WEXITSTATUS(sts) | 
					
						
							|  |  |  |             return self.returncode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def wait(self, timeout=None): | 
					
						
							|  |  |  |             if timeout is None: | 
					
						
							|  |  |  |                 return self.poll(0) | 
					
						
							|  |  |  |             deadline = time.time() + timeout | 
					
						
							|  |  |  |             delay = 0.0005 | 
					
						
							|  |  |  |             while 1: | 
					
						
							|  |  |  |                 res = self.poll() | 
					
						
							|  |  |  |                 if res is not None: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |                 remaining = deadline - time.time() | 
					
						
							|  |  |  |                 if remaining <= 0: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |                 delay = min(delay * 2, remaining, 0.05) | 
					
						
							|  |  |  |                 time.sleep(delay) | 
					
						
							|  |  |  |             return res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def terminate(self): | 
					
						
							|  |  |  |             if self.returncode is None: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.kill(self.pid, signal.SIGTERM) | 
					
						
							|  |  |  |                 except OSError as e: | 
					
						
							|  |  |  |                     if self.wait(timeout=0.1) is None: | 
					
						
							|  |  |  |                         raise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @staticmethod | 
					
						
							|  |  |  |         def thread_is_spawning(): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Windows | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     import _thread | 
					
						
							|  |  |  |     import msvcrt | 
					
						
							|  |  |  |     import _subprocess | 
					
						
							|  |  |  |     import time | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-18 19:44:02 +00:00
										 |  |  |     from pickle import dump, load, HIGHEST_PROTOCOL | 
					
						
							| 
									
										
										
										
											2010-08-04 15:47:24 +00:00
										 |  |  |     from _multiprocessing import win32, Connection, PipeConnection | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     from .util import Finalize | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-19 21:30:55 +00:00
										 |  |  |     def dump(obj, file, protocol=None): | 
					
						
							|  |  |  |         ForkingPickler(file, protocol).dump(obj) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TERMINATE = 0x10000 | 
					
						
							|  |  |  |     WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) | 
					
						
							| 
									
										
										
										
											2011-04-11 17:56:23 -05:00
										 |  |  |     WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     exit = win32.ExitProcess | 
					
						
							|  |  |  |     close = win32.CloseHandle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # _python_exe is the assumed path to the python executable. | 
					
						
							|  |  |  |     # People embedding Python want to modify it. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-11 17:56:23 -05:00
										 |  |  |     if WINSERVICE: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         _python_exe = os.path.join(sys.exec_prefix, 'python.exe') | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         _python_exe = sys.executable | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_executable(exe): | 
					
						
							|  |  |  |         global _python_exe | 
					
						
							|  |  |  |         _python_exe = exe | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def duplicate(handle, target_process=None, inheritable=False): | 
					
						
							|  |  |  |         if target_process is None: | 
					
						
							|  |  |  |             target_process = _subprocess.GetCurrentProcess() | 
					
						
							|  |  |  |         return _subprocess.DuplicateHandle( | 
					
						
							|  |  |  |             _subprocess.GetCurrentProcess(), handle, target_process, | 
					
						
							|  |  |  |             0, inheritable, _subprocess.DUPLICATE_SAME_ACCESS | 
					
						
							|  |  |  |             ).Detach() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # We define a Popen class similar to the one from subprocess, but | 
					
						
							|  |  |  |     # whose constructor takes a process object as its argument. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Popen(object): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Start a subprocess to run the code of a process object | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         _tls = _thread._local() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self, process_obj): | 
					
						
							|  |  |  |             # create pipe for communication with child | 
					
						
							|  |  |  |             rfd, wfd = os.pipe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # get handle for read end of the pipe and make it inheritable | 
					
						
							|  |  |  |             rhandle = duplicate(msvcrt.get_osfhandle(rfd), inheritable=True) | 
					
						
							|  |  |  |             os.close(rfd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # start process | 
					
						
							|  |  |  |             cmd = get_command_line() + [rhandle] | 
					
						
							|  |  |  |             cmd = ' '.join('"%s"' % x for x in cmd) | 
					
						
							|  |  |  |             hp, ht, pid, tid = _subprocess.CreateProcess( | 
					
						
							|  |  |  |                 _python_exe, cmd, None, None, 1, 0, None, None, None | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ht.Close() | 
					
						
							|  |  |  |             close(rhandle) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # set attributes of self | 
					
						
							|  |  |  |             self.pid = pid | 
					
						
							|  |  |  |             self.returncode = None | 
					
						
							|  |  |  |             self._handle = hp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # send information to child | 
					
						
							|  |  |  |             prep_data = get_preparation_data(process_obj._name) | 
					
						
							|  |  |  |             to_child = os.fdopen(wfd, 'wb') | 
					
						
							|  |  |  |             Popen._tls.process_handle = int(hp) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 dump(prep_data, to_child, HIGHEST_PROTOCOL) | 
					
						
							|  |  |  |                 dump(process_obj, to_child, HIGHEST_PROTOCOL) | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 del Popen._tls.process_handle | 
					
						
							|  |  |  |                 to_child.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @staticmethod | 
					
						
							|  |  |  |         def thread_is_spawning(): | 
					
						
							|  |  |  |             return getattr(Popen._tls, 'process_handle', None) is not None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @staticmethod | 
					
						
							|  |  |  |         def duplicate_for_child(handle): | 
					
						
							|  |  |  |             return duplicate(handle, Popen._tls.process_handle) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def wait(self, timeout=None): | 
					
						
							|  |  |  |             if self.returncode is None: | 
					
						
							|  |  |  |                 if timeout is None: | 
					
						
							|  |  |  |                     msecs = _subprocess.INFINITE | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     msecs = max(0, int(timeout * 1000 + 0.5)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 res = _subprocess.WaitForSingleObject(int(self._handle), msecs) | 
					
						
							|  |  |  |                 if res == _subprocess.WAIT_OBJECT_0: | 
					
						
							|  |  |  |                     code = _subprocess.GetExitCodeProcess(self._handle) | 
					
						
							|  |  |  |                     if code == TERMINATE: | 
					
						
							|  |  |  |                         code = -signal.SIGTERM | 
					
						
							|  |  |  |                     self.returncode = code | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return self.returncode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def poll(self): | 
					
						
							|  |  |  |             return self.wait(timeout=0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def terminate(self): | 
					
						
							|  |  |  |             if self.returncode is None: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     _subprocess.TerminateProcess(int(self._handle), TERMINATE) | 
					
						
							|  |  |  |                 except WindowsError: | 
					
						
							|  |  |  |                     if self.wait(timeout=0.1) is None: | 
					
						
							|  |  |  |                         raise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_forking(argv): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Return whether commandline indicates we are forking | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         if len(argv) >= 2 and argv[1] == '--multiprocessing-fork': | 
					
						
							|  |  |  |             assert len(argv) == 3 | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def freeze_support(): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Run code for process object if this in not the main process | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         if is_forking(sys.argv): | 
					
						
							|  |  |  |             main() | 
					
						
							|  |  |  |             sys.exit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_command_line(): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Returns prefix of command line used for spawning a child process | 
					
						
							|  |  |  |         '''
 | 
					
						
							| 
									
										
										
										
											2012-08-14 11:41:32 +01:00
										 |  |  |         if getattr(process.current_process(), '_inheriting', False): | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             raise RuntimeError('''
 | 
					
						
							|  |  |  |             Attempt to start a new process before the current process | 
					
						
							|  |  |  |             has finished its bootstrapping phase. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             This probably means that you are on Windows and you have | 
					
						
							|  |  |  |             forgotten to use the proper idiom in the main module: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if __name__ == '__main__': | 
					
						
							|  |  |  |                     freeze_support() | 
					
						
							|  |  |  |                     ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             The "freeze_support()" line can be omitted if the program | 
					
						
							|  |  |  |             is not going to be frozen to produce a Windows executable.''')
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if getattr(sys, 'frozen', False): | 
					
						
							|  |  |  |             return [sys.executable, '--multiprocessing-fork'] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             prog = 'from multiprocessing.forking import main; main()' | 
					
						
							|  |  |  |             return [_python_exe, '-c', prog, '--multiprocessing-fork'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def main(): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Run code specifed by data received over pipe | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         assert is_forking(sys.argv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         handle = int(sys.argv[-1]) | 
					
						
							|  |  |  |         fd = msvcrt.open_osfhandle(handle, os.O_RDONLY) | 
					
						
							|  |  |  |         from_parent = os.fdopen(fd, 'rb') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         process.current_process()._inheriting = True | 
					
						
							|  |  |  |         preparation_data = load(from_parent) | 
					
						
							|  |  |  |         prepare(preparation_data) | 
					
						
							|  |  |  |         self = load(from_parent) | 
					
						
							|  |  |  |         process.current_process()._inheriting = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         from_parent.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         exitcode = self._bootstrap() | 
					
						
							|  |  |  |         exit(exitcode) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_preparation_data(name): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Return info about parent needed by child to unpickle process object | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         from .util import _logger, _log_to_stderr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         d = dict( | 
					
						
							|  |  |  |             name=name, | 
					
						
							|  |  |  |             sys_path=sys.path, | 
					
						
							|  |  |  |             sys_argv=sys.argv, | 
					
						
							|  |  |  |             log_to_stderr=_log_to_stderr, | 
					
						
							|  |  |  |             orig_dir=process.ORIGINAL_DIR, | 
					
						
							| 
									
										
										
										
											2008-08-19 19:17:39 +00:00
										 |  |  |             authkey=process.current_process().authkey, | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if _logger is not None: | 
					
						
							|  |  |  |             d['log_level'] = _logger.getEffectiveLevel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-11 17:56:23 -05:00
										 |  |  |         if not WINEXE and not WINSERVICE: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             main_path = getattr(sys.modules['__main__'], '__file__', None) | 
					
						
							|  |  |  |             if not main_path and sys.argv[0] not in ('', '-c'): | 
					
						
							|  |  |  |                 main_path = sys.argv[0] | 
					
						
							|  |  |  |             if main_path is not None: | 
					
						
							|  |  |  |                 if not os.path.isabs(main_path) and \ | 
					
						
							|  |  |  |                                           process.ORIGINAL_DIR is not None: | 
					
						
							|  |  |  |                     main_path = os.path.join(process.ORIGINAL_DIR, main_path) | 
					
						
							|  |  |  |                 d['main_path'] = os.path.normpath(main_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # Make (Pipe)Connection picklable | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def reduce_connection(conn): | 
					
						
							|  |  |  |         if not Popen.thread_is_spawning(): | 
					
						
							|  |  |  |             raise RuntimeError( | 
					
						
							|  |  |  |                 'By default %s objects can only be shared between processes\n' | 
					
						
							|  |  |  |                 'using inheritance' % type(conn).__name__ | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |         return type(conn), (Popen.duplicate_for_child(conn.fileno()), | 
					
						
							|  |  |  |                             conn.readable, conn.writable) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-19 21:30:55 +00:00
										 |  |  |     ForkingPickler.register(Connection, reduce_connection) | 
					
						
							|  |  |  |     ForkingPickler.register(PipeConnection, reduce_connection) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Prepare current process | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | old_main_modules = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def prepare(data): | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     Try to get current process ready to unpickle process object | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     old_main_modules.append(sys.modules['__main__']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'name' in data: | 
					
						
							| 
									
										
										
										
											2008-08-19 19:17:39 +00:00
										 |  |  |         process.current_process().name = data['name'] | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if 'authkey' in data: | 
					
						
							|  |  |  |         process.current_process()._authkey = data['authkey'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'log_to_stderr' in data and data['log_to_stderr']: | 
					
						
							|  |  |  |         util.log_to_stderr() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'log_level' in data: | 
					
						
							|  |  |  |         util.get_logger().setLevel(data['log_level']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'sys_path' in data: | 
					
						
							|  |  |  |         sys.path = data['sys_path'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'sys_argv' in data: | 
					
						
							|  |  |  |         sys.argv = data['sys_argv'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'dir' in data: | 
					
						
							|  |  |  |         os.chdir(data['dir']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'orig_dir' in data: | 
					
						
							|  |  |  |         process.ORIGINAL_DIR = data['orig_dir'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'main_path' in data: | 
					
						
							| 
									
										
										
										
											2011-01-30 01:24:08 +00:00
										 |  |  |         # XXX (ncoghlan): The following code makes several bogus | 
					
						
							|  |  |  |         # assumptions regarding the relationship between __file__ | 
					
						
							|  |  |  |         # and a module's real name. See PEP 302 and issue #10845 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         main_path = data['main_path'] | 
					
						
							|  |  |  |         main_name = os.path.splitext(os.path.basename(main_path))[0] | 
					
						
							|  |  |  |         if main_name == '__init__': | 
					
						
							|  |  |  |             main_name = os.path.basename(os.path.dirname(main_path)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-30 01:24:08 +00:00
										 |  |  |         if main_name == '__main__': | 
					
						
							|  |  |  |             main_module = sys.modules['__main__'] | 
					
						
							|  |  |  |             main_module.__file__ = main_path | 
					
						
							|  |  |  |         elif main_name != 'ipython': | 
					
						
							|  |  |  |             # Main modules not actually called __main__.py may | 
					
						
							|  |  |  |             # contain additional code that should still be executed | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             import imp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if main_path is None: | 
					
						
							|  |  |  |                 dirs = None | 
					
						
							|  |  |  |             elif os.path.basename(main_path).startswith('__init__.py'): | 
					
						
							|  |  |  |                 dirs = [os.path.dirname(os.path.dirname(main_path))] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 dirs = [os.path.dirname(main_path)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             assert main_name not in sys.modules, main_name | 
					
						
							|  |  |  |             file, path_name, etc = imp.find_module(main_name, dirs) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 # We would like to do "imp.load_module('__main__', ...)" | 
					
						
							|  |  |  |                 # here.  However, that would cause 'if __name__ == | 
					
						
							|  |  |  |                 # "__main__"' clauses to be executed. | 
					
						
							|  |  |  |                 main_module = imp.load_module( | 
					
						
							|  |  |  |                     '__parents_main__', file, path_name, etc | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 if file: | 
					
						
							|  |  |  |                     file.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             sys.modules['__main__'] = main_module | 
					
						
							|  |  |  |             main_module.__name__ = '__main__' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Try to make the potentially picklable objects in | 
					
						
							|  |  |  |             # sys.modules['__main__'] realize they are in the main | 
					
						
							|  |  |  |             # module -- somewhat ugly. | 
					
						
							|  |  |  |             for obj in list(main_module.__dict__.values()): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     if obj.__module__ == '__parents_main__': | 
					
						
							|  |  |  |                         obj.__module__ = '__main__' | 
					
						
							|  |  |  |                 except Exception: | 
					
						
							|  |  |  |                     pass |