17db96d56Sopenharmony_ci#
27db96d56Sopenharmony_ci# Module providing various facilities to other parts of the package
37db96d56Sopenharmony_ci#
47db96d56Sopenharmony_ci# multiprocessing/util.py
57db96d56Sopenharmony_ci#
67db96d56Sopenharmony_ci# Copyright (c) 2006-2008, R Oudkerk
77db96d56Sopenharmony_ci# Licensed to PSF under a Contributor Agreement.
87db96d56Sopenharmony_ci#
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ciimport os
117db96d56Sopenharmony_ciimport itertools
127db96d56Sopenharmony_ciimport sys
137db96d56Sopenharmony_ciimport weakref
147db96d56Sopenharmony_ciimport atexit
157db96d56Sopenharmony_ciimport threading        # we want threading to install it's
167db96d56Sopenharmony_ci                        # cleanup function before multiprocessing does
177db96d56Sopenharmony_cifrom subprocess import _args_from_interpreter_flags
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_cifrom . import process
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci__all__ = [
227db96d56Sopenharmony_ci    'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger',
237db96d56Sopenharmony_ci    'log_to_stderr', 'get_temp_dir', 'register_after_fork',
247db96d56Sopenharmony_ci    'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal',
257db96d56Sopenharmony_ci    'close_all_fds_except', 'SUBDEBUG', 'SUBWARNING',
267db96d56Sopenharmony_ci    ]
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci#
297db96d56Sopenharmony_ci# Logging
307db96d56Sopenharmony_ci#
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ciNOTSET = 0
337db96d56Sopenharmony_ciSUBDEBUG = 5
347db96d56Sopenharmony_ciDEBUG = 10
357db96d56Sopenharmony_ciINFO = 20
367db96d56Sopenharmony_ciSUBWARNING = 25
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ciLOGGER_NAME = 'multiprocessing'
397db96d56Sopenharmony_ciDEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s'
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci_logger = None
427db96d56Sopenharmony_ci_log_to_stderr = False
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_cidef sub_debug(msg, *args):
457db96d56Sopenharmony_ci    if _logger:
467db96d56Sopenharmony_ci        _logger.log(SUBDEBUG, msg, *args)
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_cidef debug(msg, *args):
497db96d56Sopenharmony_ci    if _logger:
507db96d56Sopenharmony_ci        _logger.log(DEBUG, msg, *args)
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_cidef info(msg, *args):
537db96d56Sopenharmony_ci    if _logger:
547db96d56Sopenharmony_ci        _logger.log(INFO, msg, *args)
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_cidef sub_warning(msg, *args):
577db96d56Sopenharmony_ci    if _logger:
587db96d56Sopenharmony_ci        _logger.log(SUBWARNING, msg, *args)
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_cidef get_logger():
617db96d56Sopenharmony_ci    '''
627db96d56Sopenharmony_ci    Returns logger used by multiprocessing
637db96d56Sopenharmony_ci    '''
647db96d56Sopenharmony_ci    global _logger
657db96d56Sopenharmony_ci    import logging
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci    logging._acquireLock()
687db96d56Sopenharmony_ci    try:
697db96d56Sopenharmony_ci        if not _logger:
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci            _logger = logging.getLogger(LOGGER_NAME)
727db96d56Sopenharmony_ci            _logger.propagate = 0
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci            # XXX multiprocessing should cleanup before logging
757db96d56Sopenharmony_ci            if hasattr(atexit, 'unregister'):
767db96d56Sopenharmony_ci                atexit.unregister(_exit_function)
777db96d56Sopenharmony_ci                atexit.register(_exit_function)
787db96d56Sopenharmony_ci            else:
797db96d56Sopenharmony_ci                atexit._exithandlers.remove((_exit_function, (), {}))
807db96d56Sopenharmony_ci                atexit._exithandlers.append((_exit_function, (), {}))
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci    finally:
837db96d56Sopenharmony_ci        logging._releaseLock()
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci    return _logger
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_cidef log_to_stderr(level=None):
887db96d56Sopenharmony_ci    '''
897db96d56Sopenharmony_ci    Turn on logging and add a handler which prints to stderr
907db96d56Sopenharmony_ci    '''
917db96d56Sopenharmony_ci    global _log_to_stderr
927db96d56Sopenharmony_ci    import logging
937db96d56Sopenharmony_ci
947db96d56Sopenharmony_ci    logger = get_logger()
957db96d56Sopenharmony_ci    formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT)
967db96d56Sopenharmony_ci    handler = logging.StreamHandler()
977db96d56Sopenharmony_ci    handler.setFormatter(formatter)
987db96d56Sopenharmony_ci    logger.addHandler(handler)
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci    if level:
1017db96d56Sopenharmony_ci        logger.setLevel(level)
1027db96d56Sopenharmony_ci    _log_to_stderr = True
1037db96d56Sopenharmony_ci    return _logger
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci# Abstract socket support
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_cidef _platform_supports_abstract_sockets():
1097db96d56Sopenharmony_ci    if sys.platform == "linux":
1107db96d56Sopenharmony_ci        return True
1117db96d56Sopenharmony_ci    if hasattr(sys, 'getandroidapilevel'):
1127db96d56Sopenharmony_ci        return True
1137db96d56Sopenharmony_ci    return False
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_cidef is_abstract_socket_namespace(address):
1177db96d56Sopenharmony_ci    if not address:
1187db96d56Sopenharmony_ci        return False
1197db96d56Sopenharmony_ci    if isinstance(address, bytes):
1207db96d56Sopenharmony_ci        return address[0] == 0
1217db96d56Sopenharmony_ci    elif isinstance(address, str):
1227db96d56Sopenharmony_ci        return address[0] == "\0"
1237db96d56Sopenharmony_ci    raise TypeError(f'address type of {address!r} unrecognized')
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ciabstract_sockets_supported = _platform_supports_abstract_sockets()
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci#
1297db96d56Sopenharmony_ci# Function returning a temp directory which will be removed on exit
1307db96d56Sopenharmony_ci#
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_cidef _remove_temp_dir(rmtree, tempdir):
1337db96d56Sopenharmony_ci    rmtree(tempdir)
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci    current_process = process.current_process()
1367db96d56Sopenharmony_ci    # current_process() can be None if the finalizer is called
1377db96d56Sopenharmony_ci    # late during Python finalization
1387db96d56Sopenharmony_ci    if current_process is not None:
1397db96d56Sopenharmony_ci        current_process._config['tempdir'] = None
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_cidef get_temp_dir():
1427db96d56Sopenharmony_ci    # get name of a temp directory which will be automatically cleaned up
1437db96d56Sopenharmony_ci    tempdir = process.current_process()._config.get('tempdir')
1447db96d56Sopenharmony_ci    if tempdir is None:
1457db96d56Sopenharmony_ci        import shutil, tempfile
1467db96d56Sopenharmony_ci        tempdir = tempfile.mkdtemp(prefix='pymp-')
1477db96d56Sopenharmony_ci        info('created temp directory %s', tempdir)
1487db96d56Sopenharmony_ci        # keep a strong reference to shutil.rmtree(), since the finalizer
1497db96d56Sopenharmony_ci        # can be called late during Python shutdown
1507db96d56Sopenharmony_ci        Finalize(None, _remove_temp_dir, args=(shutil.rmtree, tempdir),
1517db96d56Sopenharmony_ci                 exitpriority=-100)
1527db96d56Sopenharmony_ci        process.current_process()._config['tempdir'] = tempdir
1537db96d56Sopenharmony_ci    return tempdir
1547db96d56Sopenharmony_ci
1557db96d56Sopenharmony_ci#
1567db96d56Sopenharmony_ci# Support for reinitialization of objects when bootstrapping a child process
1577db96d56Sopenharmony_ci#
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_ci_afterfork_registry = weakref.WeakValueDictionary()
1607db96d56Sopenharmony_ci_afterfork_counter = itertools.count()
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_cidef _run_after_forkers():
1637db96d56Sopenharmony_ci    items = list(_afterfork_registry.items())
1647db96d56Sopenharmony_ci    items.sort()
1657db96d56Sopenharmony_ci    for (index, ident, func), obj in items:
1667db96d56Sopenharmony_ci        try:
1677db96d56Sopenharmony_ci            func(obj)
1687db96d56Sopenharmony_ci        except Exception as e:
1697db96d56Sopenharmony_ci            info('after forker raised exception %s', e)
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_cidef register_after_fork(obj, func):
1727db96d56Sopenharmony_ci    _afterfork_registry[(next(_afterfork_counter), id(obj), func)] = obj
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci#
1757db96d56Sopenharmony_ci# Finalization using weakrefs
1767db96d56Sopenharmony_ci#
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci_finalizer_registry = {}
1797db96d56Sopenharmony_ci_finalizer_counter = itertools.count()
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ciclass Finalize(object):
1837db96d56Sopenharmony_ci    '''
1847db96d56Sopenharmony_ci    Class which supports object finalization using weakrefs
1857db96d56Sopenharmony_ci    '''
1867db96d56Sopenharmony_ci    def __init__(self, obj, callback, args=(), kwargs=None, exitpriority=None):
1877db96d56Sopenharmony_ci        if (exitpriority is not None) and not isinstance(exitpriority,int):
1887db96d56Sopenharmony_ci            raise TypeError(
1897db96d56Sopenharmony_ci                "Exitpriority ({0!r}) must be None or int, not {1!s}".format(
1907db96d56Sopenharmony_ci                    exitpriority, type(exitpriority)))
1917db96d56Sopenharmony_ci
1927db96d56Sopenharmony_ci        if obj is not None:
1937db96d56Sopenharmony_ci            self._weakref = weakref.ref(obj, self)
1947db96d56Sopenharmony_ci        elif exitpriority is None:
1957db96d56Sopenharmony_ci            raise ValueError("Without object, exitpriority cannot be None")
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ci        self._callback = callback
1987db96d56Sopenharmony_ci        self._args = args
1997db96d56Sopenharmony_ci        self._kwargs = kwargs or {}
2007db96d56Sopenharmony_ci        self._key = (exitpriority, next(_finalizer_counter))
2017db96d56Sopenharmony_ci        self._pid = os.getpid()
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci        _finalizer_registry[self._key] = self
2047db96d56Sopenharmony_ci
2057db96d56Sopenharmony_ci    def __call__(self, wr=None,
2067db96d56Sopenharmony_ci                 # Need to bind these locally because the globals can have
2077db96d56Sopenharmony_ci                 # been cleared at shutdown
2087db96d56Sopenharmony_ci                 _finalizer_registry=_finalizer_registry,
2097db96d56Sopenharmony_ci                 sub_debug=sub_debug, getpid=os.getpid):
2107db96d56Sopenharmony_ci        '''
2117db96d56Sopenharmony_ci        Run the callback unless it has already been called or cancelled
2127db96d56Sopenharmony_ci        '''
2137db96d56Sopenharmony_ci        try:
2147db96d56Sopenharmony_ci            del _finalizer_registry[self._key]
2157db96d56Sopenharmony_ci        except KeyError:
2167db96d56Sopenharmony_ci            sub_debug('finalizer no longer registered')
2177db96d56Sopenharmony_ci        else:
2187db96d56Sopenharmony_ci            if self._pid != getpid():
2197db96d56Sopenharmony_ci                sub_debug('finalizer ignored because different process')
2207db96d56Sopenharmony_ci                res = None
2217db96d56Sopenharmony_ci            else:
2227db96d56Sopenharmony_ci                sub_debug('finalizer calling %s with args %s and kwargs %s',
2237db96d56Sopenharmony_ci                          self._callback, self._args, self._kwargs)
2247db96d56Sopenharmony_ci                res = self._callback(*self._args, **self._kwargs)
2257db96d56Sopenharmony_ci            self._weakref = self._callback = self._args = \
2267db96d56Sopenharmony_ci                            self._kwargs = self._key = None
2277db96d56Sopenharmony_ci            return res
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci    def cancel(self):
2307db96d56Sopenharmony_ci        '''
2317db96d56Sopenharmony_ci        Cancel finalization of the object
2327db96d56Sopenharmony_ci        '''
2337db96d56Sopenharmony_ci        try:
2347db96d56Sopenharmony_ci            del _finalizer_registry[self._key]
2357db96d56Sopenharmony_ci        except KeyError:
2367db96d56Sopenharmony_ci            pass
2377db96d56Sopenharmony_ci        else:
2387db96d56Sopenharmony_ci            self._weakref = self._callback = self._args = \
2397db96d56Sopenharmony_ci                            self._kwargs = self._key = None
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_ci    def still_active(self):
2427db96d56Sopenharmony_ci        '''
2437db96d56Sopenharmony_ci        Return whether this finalizer is still waiting to invoke callback
2447db96d56Sopenharmony_ci        '''
2457db96d56Sopenharmony_ci        return self._key in _finalizer_registry
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ci    def __repr__(self):
2487db96d56Sopenharmony_ci        try:
2497db96d56Sopenharmony_ci            obj = self._weakref()
2507db96d56Sopenharmony_ci        except (AttributeError, TypeError):
2517db96d56Sopenharmony_ci            obj = None
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ci        if obj is None:
2547db96d56Sopenharmony_ci            return '<%s object, dead>' % self.__class__.__name__
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci        x = '<%s object, callback=%s' % (
2577db96d56Sopenharmony_ci                self.__class__.__name__,
2587db96d56Sopenharmony_ci                getattr(self._callback, '__name__', self._callback))
2597db96d56Sopenharmony_ci        if self._args:
2607db96d56Sopenharmony_ci            x += ', args=' + str(self._args)
2617db96d56Sopenharmony_ci        if self._kwargs:
2627db96d56Sopenharmony_ci            x += ', kwargs=' + str(self._kwargs)
2637db96d56Sopenharmony_ci        if self._key[0] is not None:
2647db96d56Sopenharmony_ci            x += ', exitpriority=' + str(self._key[0])
2657db96d56Sopenharmony_ci        return x + '>'
2667db96d56Sopenharmony_ci
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_cidef _run_finalizers(minpriority=None):
2697db96d56Sopenharmony_ci    '''
2707db96d56Sopenharmony_ci    Run all finalizers whose exit priority is not None and at least minpriority
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_ci    Finalizers with highest priority are called first; finalizers with
2737db96d56Sopenharmony_ci    the same priority will be called in reverse order of creation.
2747db96d56Sopenharmony_ci    '''
2757db96d56Sopenharmony_ci    if _finalizer_registry is None:
2767db96d56Sopenharmony_ci        # This function may be called after this module's globals are
2777db96d56Sopenharmony_ci        # destroyed.  See the _exit_function function in this module for more
2787db96d56Sopenharmony_ci        # notes.
2797db96d56Sopenharmony_ci        return
2807db96d56Sopenharmony_ci
2817db96d56Sopenharmony_ci    if minpriority is None:
2827db96d56Sopenharmony_ci        f = lambda p : p[0] is not None
2837db96d56Sopenharmony_ci    else:
2847db96d56Sopenharmony_ci        f = lambda p : p[0] is not None and p[0] >= minpriority
2857db96d56Sopenharmony_ci
2867db96d56Sopenharmony_ci    # Careful: _finalizer_registry may be mutated while this function
2877db96d56Sopenharmony_ci    # is running (either by a GC run or by another thread).
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_ci    # list(_finalizer_registry) should be atomic, while
2907db96d56Sopenharmony_ci    # list(_finalizer_registry.items()) is not.
2917db96d56Sopenharmony_ci    keys = [key for key in list(_finalizer_registry) if f(key)]
2927db96d56Sopenharmony_ci    keys.sort(reverse=True)
2937db96d56Sopenharmony_ci
2947db96d56Sopenharmony_ci    for key in keys:
2957db96d56Sopenharmony_ci        finalizer = _finalizer_registry.get(key)
2967db96d56Sopenharmony_ci        # key may have been removed from the registry
2977db96d56Sopenharmony_ci        if finalizer is not None:
2987db96d56Sopenharmony_ci            sub_debug('calling %s', finalizer)
2997db96d56Sopenharmony_ci            try:
3007db96d56Sopenharmony_ci                finalizer()
3017db96d56Sopenharmony_ci            except Exception:
3027db96d56Sopenharmony_ci                import traceback
3037db96d56Sopenharmony_ci                traceback.print_exc()
3047db96d56Sopenharmony_ci
3057db96d56Sopenharmony_ci    if minpriority is None:
3067db96d56Sopenharmony_ci        _finalizer_registry.clear()
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ci#
3097db96d56Sopenharmony_ci# Clean up on exit
3107db96d56Sopenharmony_ci#
3117db96d56Sopenharmony_ci
3127db96d56Sopenharmony_cidef is_exiting():
3137db96d56Sopenharmony_ci    '''
3147db96d56Sopenharmony_ci    Returns true if the process is shutting down
3157db96d56Sopenharmony_ci    '''
3167db96d56Sopenharmony_ci    return _exiting or _exiting is None
3177db96d56Sopenharmony_ci
3187db96d56Sopenharmony_ci_exiting = False
3197db96d56Sopenharmony_ci
3207db96d56Sopenharmony_cidef _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
3217db96d56Sopenharmony_ci                   active_children=process.active_children,
3227db96d56Sopenharmony_ci                   current_process=process.current_process):
3237db96d56Sopenharmony_ci    # We hold on to references to functions in the arglist due to the
3247db96d56Sopenharmony_ci    # situation described below, where this function is called after this
3257db96d56Sopenharmony_ci    # module's globals are destroyed.
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci    global _exiting
3287db96d56Sopenharmony_ci
3297db96d56Sopenharmony_ci    if not _exiting:
3307db96d56Sopenharmony_ci        _exiting = True
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_ci        info('process shutting down')
3337db96d56Sopenharmony_ci        debug('running all "atexit" finalizers with priority >= 0')
3347db96d56Sopenharmony_ci        _run_finalizers(0)
3357db96d56Sopenharmony_ci
3367db96d56Sopenharmony_ci        if current_process() is not None:
3377db96d56Sopenharmony_ci            # We check if the current process is None here because if
3387db96d56Sopenharmony_ci            # it's None, any call to ``active_children()`` will raise
3397db96d56Sopenharmony_ci            # an AttributeError (active_children winds up trying to
3407db96d56Sopenharmony_ci            # get attributes from util._current_process).  One
3417db96d56Sopenharmony_ci            # situation where this can happen is if someone has
3427db96d56Sopenharmony_ci            # manipulated sys.modules, causing this module to be
3437db96d56Sopenharmony_ci            # garbage collected.  The destructor for the module type
3447db96d56Sopenharmony_ci            # then replaces all values in the module dict with None.
3457db96d56Sopenharmony_ci            # For instance, after setuptools runs a test it replaces
3467db96d56Sopenharmony_ci            # sys.modules with a copy created earlier.  See issues
3477db96d56Sopenharmony_ci            # #9775 and #15881.  Also related: #4106, #9205, and
3487db96d56Sopenharmony_ci            # #9207.
3497db96d56Sopenharmony_ci
3507db96d56Sopenharmony_ci            for p in active_children():
3517db96d56Sopenharmony_ci                if p.daemon:
3527db96d56Sopenharmony_ci                    info('calling terminate() for daemon %s', p.name)
3537db96d56Sopenharmony_ci                    p._popen.terminate()
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci            for p in active_children():
3567db96d56Sopenharmony_ci                info('calling join() for process %s', p.name)
3577db96d56Sopenharmony_ci                p.join()
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci        debug('running the remaining "atexit" finalizers')
3607db96d56Sopenharmony_ci        _run_finalizers()
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ciatexit.register(_exit_function)
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_ci#
3657db96d56Sopenharmony_ci# Some fork aware types
3667db96d56Sopenharmony_ci#
3677db96d56Sopenharmony_ci
3687db96d56Sopenharmony_ciclass ForkAwareThreadLock(object):
3697db96d56Sopenharmony_ci    def __init__(self):
3707db96d56Sopenharmony_ci        self._lock = threading.Lock()
3717db96d56Sopenharmony_ci        self.acquire = self._lock.acquire
3727db96d56Sopenharmony_ci        self.release = self._lock.release
3737db96d56Sopenharmony_ci        register_after_fork(self, ForkAwareThreadLock._at_fork_reinit)
3747db96d56Sopenharmony_ci
3757db96d56Sopenharmony_ci    def _at_fork_reinit(self):
3767db96d56Sopenharmony_ci        self._lock._at_fork_reinit()
3777db96d56Sopenharmony_ci
3787db96d56Sopenharmony_ci    def __enter__(self):
3797db96d56Sopenharmony_ci        return self._lock.__enter__()
3807db96d56Sopenharmony_ci
3817db96d56Sopenharmony_ci    def __exit__(self, *args):
3827db96d56Sopenharmony_ci        return self._lock.__exit__(*args)
3837db96d56Sopenharmony_ci
3847db96d56Sopenharmony_ci
3857db96d56Sopenharmony_ciclass ForkAwareLocal(threading.local):
3867db96d56Sopenharmony_ci    def __init__(self):
3877db96d56Sopenharmony_ci        register_after_fork(self, lambda obj : obj.__dict__.clear())
3887db96d56Sopenharmony_ci    def __reduce__(self):
3897db96d56Sopenharmony_ci        return type(self), ()
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_ci#
3927db96d56Sopenharmony_ci# Close fds except those specified
3937db96d56Sopenharmony_ci#
3947db96d56Sopenharmony_ci
3957db96d56Sopenharmony_citry:
3967db96d56Sopenharmony_ci    MAXFD = os.sysconf("SC_OPEN_MAX")
3977db96d56Sopenharmony_ciexcept Exception:
3987db96d56Sopenharmony_ci    MAXFD = 256
3997db96d56Sopenharmony_ci
4007db96d56Sopenharmony_cidef close_all_fds_except(fds):
4017db96d56Sopenharmony_ci    fds = list(fds) + [-1, MAXFD]
4027db96d56Sopenharmony_ci    fds.sort()
4037db96d56Sopenharmony_ci    assert fds[-1] == MAXFD, 'fd too large'
4047db96d56Sopenharmony_ci    for i in range(len(fds) - 1):
4057db96d56Sopenharmony_ci        os.closerange(fds[i]+1, fds[i+1])
4067db96d56Sopenharmony_ci#
4077db96d56Sopenharmony_ci# Close sys.stdin and replace stdin with os.devnull
4087db96d56Sopenharmony_ci#
4097db96d56Sopenharmony_ci
4107db96d56Sopenharmony_cidef _close_stdin():
4117db96d56Sopenharmony_ci    if sys.stdin is None:
4127db96d56Sopenharmony_ci        return
4137db96d56Sopenharmony_ci
4147db96d56Sopenharmony_ci    try:
4157db96d56Sopenharmony_ci        sys.stdin.close()
4167db96d56Sopenharmony_ci    except (OSError, ValueError):
4177db96d56Sopenharmony_ci        pass
4187db96d56Sopenharmony_ci
4197db96d56Sopenharmony_ci    try:
4207db96d56Sopenharmony_ci        fd = os.open(os.devnull, os.O_RDONLY)
4217db96d56Sopenharmony_ci        try:
4227db96d56Sopenharmony_ci            sys.stdin = open(fd, encoding="utf-8", closefd=False)
4237db96d56Sopenharmony_ci        except:
4247db96d56Sopenharmony_ci            os.close(fd)
4257db96d56Sopenharmony_ci            raise
4267db96d56Sopenharmony_ci    except (OSError, ValueError):
4277db96d56Sopenharmony_ci        pass
4287db96d56Sopenharmony_ci
4297db96d56Sopenharmony_ci#
4307db96d56Sopenharmony_ci# Flush standard streams, if any
4317db96d56Sopenharmony_ci#
4327db96d56Sopenharmony_ci
4337db96d56Sopenharmony_cidef _flush_std_streams():
4347db96d56Sopenharmony_ci    try:
4357db96d56Sopenharmony_ci        sys.stdout.flush()
4367db96d56Sopenharmony_ci    except (AttributeError, ValueError):
4377db96d56Sopenharmony_ci        pass
4387db96d56Sopenharmony_ci    try:
4397db96d56Sopenharmony_ci        sys.stderr.flush()
4407db96d56Sopenharmony_ci    except (AttributeError, ValueError):
4417db96d56Sopenharmony_ci        pass
4427db96d56Sopenharmony_ci
4437db96d56Sopenharmony_ci#
4447db96d56Sopenharmony_ci# Start a program with only specified fds kept open
4457db96d56Sopenharmony_ci#
4467db96d56Sopenharmony_ci
4477db96d56Sopenharmony_cidef spawnv_passfds(path, args, passfds):
4487db96d56Sopenharmony_ci    import _posixsubprocess
4497db96d56Sopenharmony_ci    import subprocess
4507db96d56Sopenharmony_ci    passfds = tuple(sorted(map(int, passfds)))
4517db96d56Sopenharmony_ci    errpipe_read, errpipe_write = os.pipe()
4527db96d56Sopenharmony_ci    try:
4537db96d56Sopenharmony_ci        return _posixsubprocess.fork_exec(
4547db96d56Sopenharmony_ci            args, [path], True, passfds, None, None,
4557db96d56Sopenharmony_ci            -1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
4567db96d56Sopenharmony_ci            False, False, -1, None, None, None, -1, None,
4577db96d56Sopenharmony_ci            subprocess._USE_VFORK)
4587db96d56Sopenharmony_ci    finally:
4597db96d56Sopenharmony_ci        os.close(errpipe_read)
4607db96d56Sopenharmony_ci        os.close(errpipe_write)
4617db96d56Sopenharmony_ci
4627db96d56Sopenharmony_ci
4637db96d56Sopenharmony_cidef close_fds(*fds):
4647db96d56Sopenharmony_ci    """Close each file descriptor given as an argument"""
4657db96d56Sopenharmony_ci    for fd in fds:
4667db96d56Sopenharmony_ci        os.close(fd)
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_cidef _cleanup_tests():
4707db96d56Sopenharmony_ci    """Cleanup multiprocessing resources when multiprocessing tests
4717db96d56Sopenharmony_ci    completed."""
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ci    from test import support
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci    # cleanup multiprocessing
4767db96d56Sopenharmony_ci    process._cleanup()
4777db96d56Sopenharmony_ci
4787db96d56Sopenharmony_ci    # Stop the ForkServer process if it's running
4797db96d56Sopenharmony_ci    from multiprocessing import forkserver
4807db96d56Sopenharmony_ci    forkserver._forkserver._stop()
4817db96d56Sopenharmony_ci
4827db96d56Sopenharmony_ci    # Stop the ResourceTracker process if it's running
4837db96d56Sopenharmony_ci    from multiprocessing import resource_tracker
4847db96d56Sopenharmony_ci    resource_tracker._resource_tracker._stop()
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_ci    # bpo-37421: Explicitly call _run_finalizers() to remove immediately
4877db96d56Sopenharmony_ci    # temporary directories created by multiprocessing.util.get_temp_dir().
4887db96d56Sopenharmony_ci    _run_finalizers()
4897db96d56Sopenharmony_ci    support.gc_collect()
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_ci    support.reap_children()
492