| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Module providing various facilities to other parts of the package | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # multiprocessing/util.py | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2010-12-14 01:38:16 +00:00
										 |  |  | # Copyright (c) 2006-2008, R Oudkerk | 
					
						
							| 
									
										
										
										
											2012-04-30 12:13:55 +01:00
										 |  |  | # Licensed to PSF under a Contributor Agreement. | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-25 13:54:53 +01:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | import itertools | 
					
						
							| 
									
										
										
										
											2016-03-25 09:29:50 +01:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | import weakref | 
					
						
							|  |  |  | import atexit | 
					
						
							|  |  |  | import threading        # we want threading to install it's | 
					
						
							|  |  |  |                         # cleanup function before multiprocessing does | 
					
						
							| 
									
										
										
										
											2012-05-18 18:33:07 +02:00
										 |  |  | from subprocess import _args_from_interpreter_flags | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | from . import process | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | __all__ = [ | 
					
						
							|  |  |  |     'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger', | 
					
						
							|  |  |  |     'log_to_stderr', 'get_temp_dir', 'register_after_fork', | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  |     'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal', | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     'close_all_fds_except', 'SUBDEBUG', 'SUBWARNING', | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Logging | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NOTSET = 0 | 
					
						
							|  |  |  | SUBDEBUG = 5 | 
					
						
							|  |  |  | DEBUG = 10 | 
					
						
							|  |  |  | INFO = 20 | 
					
						
							|  |  |  | SUBWARNING = 25 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LOGGER_NAME = 'multiprocessing' | 
					
						
							|  |  |  | DEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _logger = None | 
					
						
							|  |  |  | _log_to_stderr = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sub_debug(msg, *args): | 
					
						
							|  |  |  |     if _logger: | 
					
						
							| 
									
										
										
										
											2023-12-24 18:04:12 +08:00
										 |  |  |         _logger.log(SUBDEBUG, msg, *args, stacklevel=2) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def debug(msg, *args): | 
					
						
							|  |  |  |     if _logger: | 
					
						
							| 
									
										
										
										
											2023-12-24 18:04:12 +08:00
										 |  |  |         _logger.log(DEBUG, msg, *args, stacklevel=2) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def info(msg, *args): | 
					
						
							|  |  |  |     if _logger: | 
					
						
							| 
									
										
										
										
											2023-12-24 18:04:12 +08:00
										 |  |  |         _logger.log(INFO, msg, *args, stacklevel=2) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sub_warning(msg, *args): | 
					
						
							|  |  |  |     if _logger: | 
					
						
							| 
									
										
										
										
											2023-12-24 18:04:12 +08:00
										 |  |  |         _logger.log(SUBWARNING, msg, *args, stacklevel=2) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def get_logger(): | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     Returns logger used by multiprocessing | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     global _logger | 
					
						
							| 
									
										
										
										
											2011-11-11 20:05:50 +01:00
										 |  |  |     import logging | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-27 17:26:41 +01:00
										 |  |  |     with logging._lock: | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  |         if not _logger: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  |             _logger = logging.getLogger(LOGGER_NAME) | 
					
						
							|  |  |  |             _logger.propagate = 0 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  |             # XXX multiprocessing should cleanup before logging | 
					
						
							|  |  |  |             if hasattr(atexit, 'unregister'): | 
					
						
							|  |  |  |                 atexit.unregister(_exit_function) | 
					
						
							|  |  |  |                 atexit.register(_exit_function) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 atexit._exithandlers.remove((_exit_function, (), {})) | 
					
						
							|  |  |  |                 atexit._exithandlers.append((_exit_function, (), {})) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     return _logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def log_to_stderr(level=None): | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     Turn on logging and add a handler which prints to stderr | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     global _log_to_stderr | 
					
						
							|  |  |  |     import logging | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     logger = get_logger() | 
					
						
							|  |  |  |     formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT) | 
					
						
							|  |  |  |     handler = logging.StreamHandler() | 
					
						
							|  |  |  |     handler.setFormatter(formatter) | 
					
						
							|  |  |  |     logger.addHandler(handler) | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if level: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         logger.setLevel(level) | 
					
						
							|  |  |  |     _log_to_stderr = True | 
					
						
							| 
									
										
										
										
											2009-01-25 03:45:53 +00:00
										 |  |  |     return _logger | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 13:48:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Abstract socket support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _platform_supports_abstract_sockets(): | 
					
						
							| 
									
										
										
										
											2024-03-11 19:25:39 +00:00
										 |  |  |     return sys.platform in ("linux", "android") | 
					
						
							| 
									
										
										
										
											2020-03-09 13:48:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def is_abstract_socket_namespace(address): | 
					
						
							|  |  |  |     if not address: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if isinstance(address, bytes): | 
					
						
							|  |  |  |         return address[0] == 0 | 
					
						
							|  |  |  |     elif isinstance(address, str): | 
					
						
							|  |  |  |         return address[0] == "\0" | 
					
						
							| 
									
										
										
										
											2022-04-27 09:30:54 +03:00
										 |  |  |     raise TypeError(f'address type of {address!r} unrecognized') | 
					
						
							| 
									
										
										
										
											2020-03-09 13:48:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | abstract_sockets_supported = _platform_supports_abstract_sockets() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # Function returning a temp directory which will be removed on exit | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-04 12:28:55 +02:00
										 |  |  | def _remove_temp_dir(rmtree, tempdir): | 
					
						
							|  |  |  |     rmtree(tempdir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     current_process = process.current_process() | 
					
						
							|  |  |  |     # current_process() can be None if the finalizer is called | 
					
						
							|  |  |  |     # late during Python finalization | 
					
						
							|  |  |  |     if current_process is not None: | 
					
						
							|  |  |  |         current_process._config['tempdir'] = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | def get_temp_dir(): | 
					
						
							|  |  |  |     # get name of a temp directory which will be automatically cleaned up | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     tempdir = process.current_process()._config.get('tempdir') | 
					
						
							|  |  |  |     if tempdir is None: | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         import shutil, tempfile | 
					
						
							|  |  |  |         tempdir = tempfile.mkdtemp(prefix='pymp-') | 
					
						
							|  |  |  |         info('created temp directory %s', tempdir) | 
					
						
							| 
									
										
										
										
											2019-07-04 12:28:55 +02:00
										 |  |  |         # keep a strong reference to shutil.rmtree(), since the finalizer | 
					
						
							|  |  |  |         # can be called late during Python shutdown | 
					
						
							|  |  |  |         Finalize(None, _remove_temp_dir, args=(shutil.rmtree, tempdir), | 
					
						
							|  |  |  |                  exitpriority=-100) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         process.current_process()._config['tempdir'] = tempdir | 
					
						
							|  |  |  |     return tempdir | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Support for reinitialization of objects when bootstrapping a child process | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _afterfork_registry = weakref.WeakValueDictionary() | 
					
						
							|  |  |  | _afterfork_counter = itertools.count() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _run_after_forkers(): | 
					
						
							|  |  |  |     items = list(_afterfork_registry.items()) | 
					
						
							|  |  |  |     items.sort() | 
					
						
							|  |  |  |     for (index, ident, func), obj in items: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             func(obj) | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             info('after forker raised exception %s', e) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def register_after_fork(obj, func): | 
					
						
							|  |  |  |     _afterfork_registry[(next(_afterfork_counter), id(obj), func)] = obj | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Finalization using weakrefs | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _finalizer_registry = {} | 
					
						
							|  |  |  | _finalizer_counter = itertools.count() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Finalize(object): | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     Class which supports object finalization using weakrefs | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     def __init__(self, obj, callback, args=(), kwargs=None, exitpriority=None): | 
					
						
							| 
									
										
										
										
											2017-08-29 17:52:18 -05:00
										 |  |  |         if (exitpriority is not None) and not isinstance(exitpriority,int): | 
					
						
							|  |  |  |             raise TypeError( | 
					
						
							|  |  |  |                 "Exitpriority ({0!r}) must be None or int, not {1!s}".format( | 
					
						
							|  |  |  |                     exitpriority, type(exitpriority))) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if obj is not None: | 
					
						
							|  |  |  |             self._weakref = weakref.ref(obj, self) | 
					
						
							| 
									
										
										
										
											2017-08-29 17:52:18 -05:00
										 |  |  |         elif exitpriority is None: | 
					
						
							|  |  |  |             raise ValueError("Without object, exitpriority cannot be None") | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self._callback = callback | 
					
						
							|  |  |  |         self._args = args | 
					
						
							|  |  |  |         self._kwargs = kwargs or {} | 
					
						
							|  |  |  |         self._key = (exitpriority, next(_finalizer_counter)) | 
					
						
							| 
									
										
										
										
											2012-05-25 13:54:53 +01:00
										 |  |  |         self._pid = os.getpid() | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         _finalizer_registry[self._key] = self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-09 01:03:00 +02:00
										 |  |  |     def __call__(self, wr=None, | 
					
						
							|  |  |  |                  # Need to bind these locally because the globals can have | 
					
						
							|  |  |  |                  # been cleared at shutdown | 
					
						
							|  |  |  |                  _finalizer_registry=_finalizer_registry, | 
					
						
							| 
									
										
										
										
											2012-06-04 18:58:59 +01:00
										 |  |  |                  sub_debug=sub_debug, getpid=os.getpid): | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         '''
 | 
					
						
							|  |  |  |         Run the callback unless it has already been called or cancelled | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             del _finalizer_registry[self._key] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             sub_debug('finalizer no longer registered') | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2012-06-04 18:58:59 +01:00
										 |  |  |             if self._pid != getpid(): | 
					
						
							| 
									
										
										
										
											2012-05-25 13:54:53 +01:00
										 |  |  |                 sub_debug('finalizer ignored because different process') | 
					
						
							|  |  |  |                 res = None | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 sub_debug('finalizer calling %s with args %s and kwargs %s', | 
					
						
							|  |  |  |                           self._callback, self._args, self._kwargs) | 
					
						
							|  |  |  |                 res = self._callback(*self._args, **self._kwargs) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |             self._weakref = self._callback = self._args = \ | 
					
						
							|  |  |  |                             self._kwargs = self._key = None | 
					
						
							|  |  |  |             return res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def cancel(self): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Cancel finalization of the object | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             del _finalizer_registry[self._key] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self._weakref = self._callback = self._args = \ | 
					
						
							|  |  |  |                             self._kwargs = self._key = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def still_active(self): | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         Return whether this finalizer is still waiting to invoke callback | 
					
						
							|  |  |  |         '''
 | 
					
						
							|  |  |  |         return self._key in _finalizer_registry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             obj = self._weakref() | 
					
						
							|  |  |  |         except (AttributeError, TypeError): | 
					
						
							|  |  |  |             obj = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if obj is None: | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |             return '<%s object, dead>' % self.__class__.__name__ | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-25 23:36:00 +03:00
										 |  |  |         x = '<%s object, callback=%s' % ( | 
					
						
							|  |  |  |                 self.__class__.__name__, | 
					
						
							|  |  |  |                 getattr(self._callback, '__name__', self._callback)) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         if self._args: | 
					
						
							|  |  |  |             x += ', args=' + str(self._args) | 
					
						
							|  |  |  |         if self._kwargs: | 
					
						
							|  |  |  |             x += ', kwargs=' + str(self._kwargs) | 
					
						
							|  |  |  |         if self._key[0] is not None: | 
					
						
							| 
									
										
										
										
											2019-08-31 06:21:19 +10:00
										 |  |  |             x += ', exitpriority=' + str(self._key[0]) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |         return x + '>' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _run_finalizers(minpriority=None): | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     Run all finalizers whose exit priority is not None and at least minpriority | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Finalizers with highest priority are called first; finalizers with | 
					
						
							|  |  |  |     the same priority will be called in reverse order of creation. | 
					
						
							|  |  |  |     '''
 | 
					
						
							| 
									
										
										
										
											2012-09-09 13:20:58 -04:00
										 |  |  |     if _finalizer_registry is None: | 
					
						
							|  |  |  |         # This function may be called after this module's globals are | 
					
						
							|  |  |  |         # destroyed.  See the _exit_function function in this module for more | 
					
						
							|  |  |  |         # notes. | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2012-09-09 13:25:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     if minpriority is None: | 
					
						
							| 
									
										
										
										
											2017-06-13 17:10:39 +02:00
										 |  |  |         f = lambda p : p[0] is not None | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2017-06-13 17:10:39 +02:00
										 |  |  |         f = lambda p : p[0] is not None and p[0] >= minpriority | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Careful: _finalizer_registry may be mutated while this function | 
					
						
							|  |  |  |     # is running (either by a GC run or by another thread). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # list(_finalizer_registry) should be atomic, while | 
					
						
							|  |  |  |     # list(_finalizer_registry.items()) is not. | 
					
						
							|  |  |  |     keys = [key for key in list(_finalizer_registry) if f(key)] | 
					
						
							|  |  |  |     keys.sort(reverse=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for key in keys: | 
					
						
							|  |  |  |         finalizer = _finalizer_registry.get(key) | 
					
						
							|  |  |  |         # key may have been removed from the registry | 
					
						
							|  |  |  |         if finalizer is not None: | 
					
						
							|  |  |  |             sub_debug('calling %s', finalizer) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 finalizer() | 
					
						
							|  |  |  |             except Exception: | 
					
						
							|  |  |  |                 import traceback | 
					
						
							|  |  |  |                 traceback.print_exc() | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if minpriority is None: | 
					
						
							|  |  |  |         _finalizer_registry.clear() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Clean up on exit | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def is_exiting(): | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     Returns true if the process is shutting down | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  |     return _exiting or _exiting is None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _exiting = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-09 13:20:58 -04:00
										 |  |  | def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers, | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |                    active_children=process.active_children, | 
					
						
							|  |  |  |                    current_process=process.current_process): | 
					
						
							| 
									
										
										
										
											2012-09-09 13:20:58 -04:00
										 |  |  |     # We hold on to references to functions in the arglist due to the | 
					
						
							|  |  |  |     # situation described below, where this function is called after this | 
					
						
							|  |  |  |     # module's globals are destroyed. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  |     global _exiting | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-14 15:30:10 +01:00
										 |  |  |     if not _exiting: | 
					
						
							|  |  |  |         _exiting = True | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-14 15:30:10 +01:00
										 |  |  |         info('process shutting down') | 
					
						
							|  |  |  |         debug('running all "atexit" finalizers with priority >= 0') | 
					
						
							|  |  |  |         _run_finalizers(0) | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-09 13:20:58 -04:00
										 |  |  |         if current_process() is not None: | 
					
						
							|  |  |  |             # We check if the current process is None here because if | 
					
						
							| 
									
										
										
										
											2012-12-18 21:26:36 +02:00
										 |  |  |             # it's None, any call to ``active_children()`` will raise | 
					
						
							| 
									
										
										
										
											2012-09-13 17:27:15 +01:00
										 |  |  |             # an AttributeError (active_children winds up trying to | 
					
						
							|  |  |  |             # get attributes from util._current_process).  One | 
					
						
							|  |  |  |             # situation where this can happen is if someone has | 
					
						
							|  |  |  |             # manipulated sys.modules, causing this module to be | 
					
						
							|  |  |  |             # garbage collected.  The destructor for the module type | 
					
						
							|  |  |  |             # then replaces all values in the module dict with None. | 
					
						
							|  |  |  |             # For instance, after setuptools runs a test it replaces | 
					
						
							|  |  |  |             # sys.modules with a copy created earlier.  See issues | 
					
						
							|  |  |  |             # #9775 and #15881.  Also related: #4106, #9205, and | 
					
						
							|  |  |  |             # #9207. | 
					
						
							| 
									
										
										
										
											2012-09-09 13:20:58 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |             for p in active_children(): | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |                 if p.daemon: | 
					
						
							| 
									
										
										
										
											2012-09-09 13:20:58 -04:00
										 |  |  |                     info('calling terminate() for daemon %s', p.name) | 
					
						
							|  |  |  |                     p._popen.terminate() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for p in active_children(): | 
					
						
							|  |  |  |                 info('calling join() for process %s', p.name) | 
					
						
							|  |  |  |                 p.join() | 
					
						
							| 
									
										
										
										
											2012-06-14 15:30:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         debug('running the remaining "atexit" finalizers') | 
					
						
							|  |  |  |         _run_finalizers() | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | atexit.register(_exit_function) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Some fork aware types | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ForkAwareThreadLock(object): | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self._lock = threading.Lock() | 
					
						
							|  |  |  |         self.acquire = self._lock.acquire | 
					
						
							|  |  |  |         self.release = self._lock.release | 
					
						
							| 
									
										
										
										
											2020-04-14 22:15:52 +09:00
										 |  |  |         register_after_fork(self, ForkAwareThreadLock._at_fork_reinit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _at_fork_reinit(self): | 
					
						
							|  |  |  |         self._lock._at_fork_reinit() | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-25 14:12:12 +01:00
										 |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         return self._lock.__enter__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, *args): | 
					
						
							|  |  |  |         return self._lock.__exit__(*args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-11 16:44:04 +00:00
										 |  |  | class ForkAwareLocal(threading.local): | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         register_after_fork(self, lambda obj : obj.__dict__.clear()) | 
					
						
							|  |  |  |     def __reduce__(self): | 
					
						
							|  |  |  |         return type(self), () | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Close fds except those specified | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     MAXFD = os.sysconf("SC_OPEN_MAX") | 
					
						
							|  |  |  | except Exception: | 
					
						
							|  |  |  |     MAXFD = 256 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def close_all_fds_except(fds): | 
					
						
							|  |  |  |     fds = list(fds) + [-1, MAXFD] | 
					
						
							|  |  |  |     fds.sort() | 
					
						
							|  |  |  |     assert fds[-1] == MAXFD, 'fd too large' | 
					
						
							|  |  |  |     for i in range(len(fds) - 1): | 
					
						
							|  |  |  |         os.closerange(fds[i]+1, fds[i+1]) | 
					
						
							| 
									
										
										
										
											2016-03-25 09:29:50 +01:00
										 |  |  | # | 
					
						
							|  |  |  | # Close sys.stdin and replace stdin with os.devnull | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _close_stdin(): | 
					
						
							|  |  |  |     if sys.stdin is None: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         sys.stdin.close() | 
					
						
							|  |  |  |     except (OSError, ValueError): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         fd = os.open(os.devnull, os.O_RDONLY) | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2021-04-02 09:01:57 +09:00
										 |  |  |             sys.stdin = open(fd, encoding="utf-8", closefd=False) | 
					
						
							| 
									
										
										
										
											2016-03-25 09:29:50 +01:00
										 |  |  |         except: | 
					
						
							|  |  |  |             os.close(fd) | 
					
						
							|  |  |  |             raise | 
					
						
							|  |  |  |     except (OSError, ValueError): | 
					
						
							|  |  |  |         pass | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-11 19:21:38 +01:00
										 |  |  | # | 
					
						
							|  |  |  | # Flush standard streams, if any | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _flush_std_streams(): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         sys.stdout.flush() | 
					
						
							|  |  |  |     except (AttributeError, ValueError): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         sys.stderr.flush() | 
					
						
							|  |  |  |     except (AttributeError, ValueError): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | # | 
					
						
							|  |  |  | # Start a program with only specified fds kept open | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def spawnv_passfds(path, args, passfds): | 
					
						
							| 
									
										
										
										
											2013-08-28 12:21:47 +02:00
										 |  |  |     import _posixsubprocess | 
					
						
							| 
									
										
										
										
											2022-04-25 16:19:39 -07:00
										 |  |  |     import subprocess | 
					
						
							| 
									
										
										
										
											2017-04-19 21:12:46 +03:00
										 |  |  |     passfds = tuple(sorted(map(int, passfds))) | 
					
						
							| 
									
										
										
										
											2013-08-28 00:53:59 +02:00
										 |  |  |     errpipe_read, errpipe_write = os.pipe() | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     try: | 
					
						
							|  |  |  |         return _posixsubprocess.fork_exec( | 
					
						
							| 
									
										
										
										
											2022-04-23 00:47:09 +02:00
										 |  |  |             args, [path], True, passfds, None, None, | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             -1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write, | 
					
						
							| 
									
										
										
										
											2022-05-05 16:22:32 -07:00
										 |  |  |             False, False, -1, None, None, None, -1, None, | 
					
						
							| 
									
										
										
										
											2022-04-25 16:19:39 -07:00
										 |  |  |             subprocess._USE_VFORK) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     finally: | 
					
						
							|  |  |  |         os.close(errpipe_read) | 
					
						
							|  |  |  |         os.close(errpipe_write) | 
					
						
							| 
									
										
										
										
											2019-05-20 21:37:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def close_fds(*fds): | 
					
						
							|  |  |  |     """Close each file descriptor given as an argument""" | 
					
						
							|  |  |  |     for fd in fds: | 
					
						
							|  |  |  |         os.close(fd) | 
					
						
							| 
									
										
										
										
											2019-12-17 18:37:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cleanup_tests(): | 
					
						
							|  |  |  |     """Cleanup multiprocessing resources when multiprocessing tests
 | 
					
						
							|  |  |  |     completed."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     from test import support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # cleanup multiprocessing | 
					
						
							|  |  |  |     process._cleanup() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Stop the ForkServer process if it's running | 
					
						
							|  |  |  |     from multiprocessing import forkserver | 
					
						
							|  |  |  |     forkserver._forkserver._stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Stop the ResourceTracker process if it's running | 
					
						
							|  |  |  |     from multiprocessing import resource_tracker | 
					
						
							|  |  |  |     resource_tracker._resource_tracker._stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # bpo-37421: Explicitly call _run_finalizers() to remove immediately | 
					
						
							|  |  |  |     # temporary directories created by multiprocessing.util.get_temp_dir(). | 
					
						
							|  |  |  |     _run_finalizers() | 
					
						
							|  |  |  |     support.gc_collect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     support.reap_children() |