Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/multiprocessing/spawn.py @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
1 # | |
2 # Code used to start processes when using the spawn or forkserver | |
3 # start methods. | |
4 # | |
5 # multiprocessing/spawn.py | |
6 # | |
7 # Copyright (c) 2006-2008, R Oudkerk | |
8 # Licensed to PSF under a Contributor Agreement. | |
9 # | |
10 | |
11 import os | |
12 import sys | |
13 import runpy | |
14 import types | |
15 | |
16 from . import get_start_method, set_start_method | |
17 from . import process | |
18 from .context import reduction | |
19 from . import util | |
20 | |
21 __all__ = ['_main', 'freeze_support', 'set_executable', 'get_executable', | |
22 'get_preparation_data', 'get_command_line', 'import_main_path'] | |
23 | |
24 # | |
25 # _python_exe is the assumed path to the python executable. | |
26 # People embedding Python want to modify it. | |
27 # | |
28 | |
29 if sys.platform != 'win32': | |
30 WINEXE = False | |
31 WINSERVICE = False | |
32 else: | |
33 WINEXE = getattr(sys, 'frozen', False) | |
34 WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") | |
35 | |
36 if WINSERVICE: | |
37 _python_exe = os.path.join(sys.exec_prefix, 'python.exe') | |
38 else: | |
39 _python_exe = sys._base_executable | |
40 | |
41 def set_executable(exe): | |
42 global _python_exe | |
43 _python_exe = exe | |
44 | |
45 def get_executable(): | |
46 return _python_exe | |
47 | |
48 # | |
49 # | |
50 # | |
51 | |
52 def is_forking(argv): | |
53 ''' | |
54 Return whether commandline indicates we are forking | |
55 ''' | |
56 if len(argv) >= 2 and argv[1] == '--multiprocessing-fork': | |
57 return True | |
58 else: | |
59 return False | |
60 | |
61 | |
62 def freeze_support(): | |
63 ''' | |
64 Run code for process object if this in not the main process | |
65 ''' | |
66 if is_forking(sys.argv): | |
67 kwds = {} | |
68 for arg in sys.argv[2:]: | |
69 name, value = arg.split('=') | |
70 if value == 'None': | |
71 kwds[name] = None | |
72 else: | |
73 kwds[name] = int(value) | |
74 spawn_main(**kwds) | |
75 sys.exit() | |
76 | |
77 | |
78 def get_command_line(**kwds): | |
79 ''' | |
80 Returns prefix of command line used for spawning a child process | |
81 ''' | |
82 if getattr(sys, 'frozen', False): | |
83 return ([sys.executable, '--multiprocessing-fork'] + | |
84 ['%s=%r' % item for item in kwds.items()]) | |
85 else: | |
86 prog = 'from multiprocessing.spawn import spawn_main; spawn_main(%s)' | |
87 prog %= ', '.join('%s=%r' % item for item in kwds.items()) | |
88 opts = util._args_from_interpreter_flags() | |
89 return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork'] | |
90 | |
91 | |
92 def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None): | |
93 ''' | |
94 Run code specified by data received over pipe | |
95 ''' | |
96 assert is_forking(sys.argv), "Not forking" | |
97 if sys.platform == 'win32': | |
98 import msvcrt | |
99 import _winapi | |
100 | |
101 if parent_pid is not None: | |
102 source_process = _winapi.OpenProcess( | |
103 _winapi.SYNCHRONIZE | _winapi.PROCESS_DUP_HANDLE, | |
104 False, parent_pid) | |
105 else: | |
106 source_process = None | |
107 new_handle = reduction.duplicate(pipe_handle, | |
108 source_process=source_process) | |
109 fd = msvcrt.open_osfhandle(new_handle, os.O_RDONLY) | |
110 parent_sentinel = source_process | |
111 else: | |
112 from . import resource_tracker | |
113 resource_tracker._resource_tracker._fd = tracker_fd | |
114 fd = pipe_handle | |
115 parent_sentinel = os.dup(pipe_handle) | |
116 exitcode = _main(fd, parent_sentinel) | |
117 sys.exit(exitcode) | |
118 | |
119 | |
120 def _main(fd, parent_sentinel): | |
121 with os.fdopen(fd, 'rb', closefd=True) as from_parent: | |
122 process.current_process()._inheriting = True | |
123 try: | |
124 preparation_data = reduction.pickle.load(from_parent) | |
125 prepare(preparation_data) | |
126 self = reduction.pickle.load(from_parent) | |
127 finally: | |
128 del process.current_process()._inheriting | |
129 return self._bootstrap(parent_sentinel) | |
130 | |
131 | |
132 def _check_not_importing_main(): | |
133 if getattr(process.current_process(), '_inheriting', False): | |
134 raise RuntimeError(''' | |
135 An attempt has been made to start a new process before the | |
136 current process has finished its bootstrapping phase. | |
137 | |
138 This probably means that you are not using fork to start your | |
139 child processes and you have forgotten to use the proper idiom | |
140 in the main module: | |
141 | |
142 if __name__ == '__main__': | |
143 freeze_support() | |
144 ... | |
145 | |
146 The "freeze_support()" line can be omitted if the program | |
147 is not going to be frozen to produce an executable.''') | |
148 | |
149 | |
150 def get_preparation_data(name): | |
151 ''' | |
152 Return info about parent needed by child to unpickle process object | |
153 ''' | |
154 _check_not_importing_main() | |
155 d = dict( | |
156 log_to_stderr=util._log_to_stderr, | |
157 authkey=process.current_process().authkey, | |
158 ) | |
159 | |
160 if util._logger is not None: | |
161 d['log_level'] = util._logger.getEffectiveLevel() | |
162 | |
163 sys_path=sys.path.copy() | |
164 try: | |
165 i = sys_path.index('') | |
166 except ValueError: | |
167 pass | |
168 else: | |
169 sys_path[i] = process.ORIGINAL_DIR | |
170 | |
171 d.update( | |
172 name=name, | |
173 sys_path=sys_path, | |
174 sys_argv=sys.argv, | |
175 orig_dir=process.ORIGINAL_DIR, | |
176 dir=os.getcwd(), | |
177 start_method=get_start_method(), | |
178 ) | |
179 | |
180 # Figure out whether to initialise main in the subprocess as a module | |
181 # or through direct execution (or to leave it alone entirely) | |
182 main_module = sys.modules['__main__'] | |
183 main_mod_name = getattr(main_module.__spec__, "name", None) | |
184 if main_mod_name is not None: | |
185 d['init_main_from_name'] = main_mod_name | |
186 elif sys.platform != 'win32' or (not WINEXE and not WINSERVICE): | |
187 main_path = getattr(main_module, '__file__', None) | |
188 if main_path is not None: | |
189 if (not os.path.isabs(main_path) and | |
190 process.ORIGINAL_DIR is not None): | |
191 main_path = os.path.join(process.ORIGINAL_DIR, main_path) | |
192 d['init_main_from_path'] = os.path.normpath(main_path) | |
193 | |
194 return d | |
195 | |
196 # | |
197 # Prepare current process | |
198 # | |
199 | |
200 old_main_modules = [] | |
201 | |
202 def prepare(data): | |
203 ''' | |
204 Try to get current process ready to unpickle process object | |
205 ''' | |
206 if 'name' in data: | |
207 process.current_process().name = data['name'] | |
208 | |
209 if 'authkey' in data: | |
210 process.current_process().authkey = data['authkey'] | |
211 | |
212 if 'log_to_stderr' in data and data['log_to_stderr']: | |
213 util.log_to_stderr() | |
214 | |
215 if 'log_level' in data: | |
216 util.get_logger().setLevel(data['log_level']) | |
217 | |
218 if 'sys_path' in data: | |
219 sys.path = data['sys_path'] | |
220 | |
221 if 'sys_argv' in data: | |
222 sys.argv = data['sys_argv'] | |
223 | |
224 if 'dir' in data: | |
225 os.chdir(data['dir']) | |
226 | |
227 if 'orig_dir' in data: | |
228 process.ORIGINAL_DIR = data['orig_dir'] | |
229 | |
230 if 'start_method' in data: | |
231 set_start_method(data['start_method'], force=True) | |
232 | |
233 if 'init_main_from_name' in data: | |
234 _fixup_main_from_name(data['init_main_from_name']) | |
235 elif 'init_main_from_path' in data: | |
236 _fixup_main_from_path(data['init_main_from_path']) | |
237 | |
238 # Multiprocessing module helpers to fix up the main module in | |
239 # spawned subprocesses | |
240 def _fixup_main_from_name(mod_name): | |
241 # __main__.py files for packages, directories, zip archives, etc, run | |
242 # their "main only" code unconditionally, so we don't even try to | |
243 # populate anything in __main__, nor do we make any changes to | |
244 # __main__ attributes | |
245 current_main = sys.modules['__main__'] | |
246 if mod_name == "__main__" or mod_name.endswith(".__main__"): | |
247 return | |
248 | |
249 # If this process was forked, __main__ may already be populated | |
250 if getattr(current_main.__spec__, "name", None) == mod_name: | |
251 return | |
252 | |
253 # Otherwise, __main__ may contain some non-main code where we need to | |
254 # support unpickling it properly. We rerun it as __mp_main__ and make | |
255 # the normal __main__ an alias to that | |
256 old_main_modules.append(current_main) | |
257 main_module = types.ModuleType("__mp_main__") | |
258 main_content = runpy.run_module(mod_name, | |
259 run_name="__mp_main__", | |
260 alter_sys=True) | |
261 main_module.__dict__.update(main_content) | |
262 sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module | |
263 | |
264 | |
265 def _fixup_main_from_path(main_path): | |
266 # If this process was forked, __main__ may already be populated | |
267 current_main = sys.modules['__main__'] | |
268 | |
269 # Unfortunately, the main ipython launch script historically had no | |
270 # "if __name__ == '__main__'" guard, so we work around that | |
271 # by treating it like a __main__.py file | |
272 # See https://github.com/ipython/ipython/issues/4698 | |
273 main_name = os.path.splitext(os.path.basename(main_path))[0] | |
274 if main_name == 'ipython': | |
275 return | |
276 | |
277 # Otherwise, if __file__ already has the setting we expect, | |
278 # there's nothing more to do | |
279 if getattr(current_main, '__file__', None) == main_path: | |
280 return | |
281 | |
282 # If the parent process has sent a path through rather than a module | |
283 # name we assume it is an executable script that may contain | |
284 # non-main code that needs to be executed | |
285 old_main_modules.append(current_main) | |
286 main_module = types.ModuleType("__mp_main__") | |
287 main_content = runpy.run_path(main_path, | |
288 run_name="__mp_main__") | |
289 main_module.__dict__.update(main_content) | |
290 sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module | |
291 | |
292 | |
293 def import_main_path(main_path): | |
294 ''' | |
295 Set sys.modules['__main__'] to module at main_path | |
296 ''' | |
297 _fixup_main_from_path(main_path) |