17db96d56Sopenharmony_ciimport os
27db96d56Sopenharmony_ciimport sys
37db96d56Sopenharmony_ciimport threading
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_cifrom . import process
67db96d56Sopenharmony_cifrom . import reduction
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci__all__ = ()
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci#
117db96d56Sopenharmony_ci# Exceptions
127db96d56Sopenharmony_ci#
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciclass ProcessError(Exception):
157db96d56Sopenharmony_ci    pass
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciclass BufferTooShort(ProcessError):
187db96d56Sopenharmony_ci    pass
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ciclass TimeoutError(ProcessError):
217db96d56Sopenharmony_ci    pass
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ciclass AuthenticationError(ProcessError):
247db96d56Sopenharmony_ci    pass
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci#
277db96d56Sopenharmony_ci# Base type for contexts. Bound methods of an instance of this type are included in __all__ of __init__.py
287db96d56Sopenharmony_ci#
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ciclass BaseContext(object):
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci    ProcessError = ProcessError
337db96d56Sopenharmony_ci    BufferTooShort = BufferTooShort
347db96d56Sopenharmony_ci    TimeoutError = TimeoutError
357db96d56Sopenharmony_ci    AuthenticationError = AuthenticationError
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci    current_process = staticmethod(process.current_process)
387db96d56Sopenharmony_ci    parent_process = staticmethod(process.parent_process)
397db96d56Sopenharmony_ci    active_children = staticmethod(process.active_children)
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci    def cpu_count(self):
427db96d56Sopenharmony_ci        '''Returns the number of CPUs in the system'''
437db96d56Sopenharmony_ci        num = os.cpu_count()
447db96d56Sopenharmony_ci        if num is None:
457db96d56Sopenharmony_ci            raise NotImplementedError('cannot determine number of cpus')
467db96d56Sopenharmony_ci        else:
477db96d56Sopenharmony_ci            return num
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci    def Manager(self):
507db96d56Sopenharmony_ci        '''Returns a manager associated with a running server process
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci        The managers methods such as `Lock()`, `Condition()` and `Queue()`
537db96d56Sopenharmony_ci        can be used to create shared objects.
547db96d56Sopenharmony_ci        '''
557db96d56Sopenharmony_ci        from .managers import SyncManager
567db96d56Sopenharmony_ci        m = SyncManager(ctx=self.get_context())
577db96d56Sopenharmony_ci        m.start()
587db96d56Sopenharmony_ci        return m
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci    def Pipe(self, duplex=True):
617db96d56Sopenharmony_ci        '''Returns two connection object connected by a pipe'''
627db96d56Sopenharmony_ci        from .connection import Pipe
637db96d56Sopenharmony_ci        return Pipe(duplex)
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci    def Lock(self):
667db96d56Sopenharmony_ci        '''Returns a non-recursive lock object'''
677db96d56Sopenharmony_ci        from .synchronize import Lock
687db96d56Sopenharmony_ci        return Lock(ctx=self.get_context())
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci    def RLock(self):
717db96d56Sopenharmony_ci        '''Returns a recursive lock object'''
727db96d56Sopenharmony_ci        from .synchronize import RLock
737db96d56Sopenharmony_ci        return RLock(ctx=self.get_context())
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci    def Condition(self, lock=None):
767db96d56Sopenharmony_ci        '''Returns a condition object'''
777db96d56Sopenharmony_ci        from .synchronize import Condition
787db96d56Sopenharmony_ci        return Condition(lock, ctx=self.get_context())
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ci    def Semaphore(self, value=1):
817db96d56Sopenharmony_ci        '''Returns a semaphore object'''
827db96d56Sopenharmony_ci        from .synchronize import Semaphore
837db96d56Sopenharmony_ci        return Semaphore(value, ctx=self.get_context())
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci    def BoundedSemaphore(self, value=1):
867db96d56Sopenharmony_ci        '''Returns a bounded semaphore object'''
877db96d56Sopenharmony_ci        from .synchronize import BoundedSemaphore
887db96d56Sopenharmony_ci        return BoundedSemaphore(value, ctx=self.get_context())
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci    def Event(self):
917db96d56Sopenharmony_ci        '''Returns an event object'''
927db96d56Sopenharmony_ci        from .synchronize import Event
937db96d56Sopenharmony_ci        return Event(ctx=self.get_context())
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci    def Barrier(self, parties, action=None, timeout=None):
967db96d56Sopenharmony_ci        '''Returns a barrier object'''
977db96d56Sopenharmony_ci        from .synchronize import Barrier
987db96d56Sopenharmony_ci        return Barrier(parties, action, timeout, ctx=self.get_context())
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci    def Queue(self, maxsize=0):
1017db96d56Sopenharmony_ci        '''Returns a queue object'''
1027db96d56Sopenharmony_ci        from .queues import Queue
1037db96d56Sopenharmony_ci        return Queue(maxsize, ctx=self.get_context())
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci    def JoinableQueue(self, maxsize=0):
1067db96d56Sopenharmony_ci        '''Returns a queue object'''
1077db96d56Sopenharmony_ci        from .queues import JoinableQueue
1087db96d56Sopenharmony_ci        return JoinableQueue(maxsize, ctx=self.get_context())
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci    def SimpleQueue(self):
1117db96d56Sopenharmony_ci        '''Returns a queue object'''
1127db96d56Sopenharmony_ci        from .queues import SimpleQueue
1137db96d56Sopenharmony_ci        return SimpleQueue(ctx=self.get_context())
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci    def Pool(self, processes=None, initializer=None, initargs=(),
1167db96d56Sopenharmony_ci             maxtasksperchild=None):
1177db96d56Sopenharmony_ci        '''Returns a process pool object'''
1187db96d56Sopenharmony_ci        from .pool import Pool
1197db96d56Sopenharmony_ci        return Pool(processes, initializer, initargs, maxtasksperchild,
1207db96d56Sopenharmony_ci                    context=self.get_context())
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci    def RawValue(self, typecode_or_type, *args):
1237db96d56Sopenharmony_ci        '''Returns a shared object'''
1247db96d56Sopenharmony_ci        from .sharedctypes import RawValue
1257db96d56Sopenharmony_ci        return RawValue(typecode_or_type, *args)
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_ci    def RawArray(self, typecode_or_type, size_or_initializer):
1287db96d56Sopenharmony_ci        '''Returns a shared array'''
1297db96d56Sopenharmony_ci        from .sharedctypes import RawArray
1307db96d56Sopenharmony_ci        return RawArray(typecode_or_type, size_or_initializer)
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_ci    def Value(self, typecode_or_type, *args, lock=True):
1337db96d56Sopenharmony_ci        '''Returns a synchronized shared object'''
1347db96d56Sopenharmony_ci        from .sharedctypes import Value
1357db96d56Sopenharmony_ci        return Value(typecode_or_type, *args, lock=lock,
1367db96d56Sopenharmony_ci                     ctx=self.get_context())
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci    def Array(self, typecode_or_type, size_or_initializer, *, lock=True):
1397db96d56Sopenharmony_ci        '''Returns a synchronized shared array'''
1407db96d56Sopenharmony_ci        from .sharedctypes import Array
1417db96d56Sopenharmony_ci        return Array(typecode_or_type, size_or_initializer, lock=lock,
1427db96d56Sopenharmony_ci                     ctx=self.get_context())
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci    def freeze_support(self):
1457db96d56Sopenharmony_ci        '''Check whether this is a fake forked process in a frozen executable.
1467db96d56Sopenharmony_ci        If so then run code specified by commandline and exit.
1477db96d56Sopenharmony_ci        '''
1487db96d56Sopenharmony_ci        if sys.platform == 'win32' and getattr(sys, 'frozen', False):
1497db96d56Sopenharmony_ci            from .spawn import freeze_support
1507db96d56Sopenharmony_ci            freeze_support()
1517db96d56Sopenharmony_ci
1527db96d56Sopenharmony_ci    def get_logger(self):
1537db96d56Sopenharmony_ci        '''Return package logger -- if it does not already exist then
1547db96d56Sopenharmony_ci        it is created.
1557db96d56Sopenharmony_ci        '''
1567db96d56Sopenharmony_ci        from .util import get_logger
1577db96d56Sopenharmony_ci        return get_logger()
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_ci    def log_to_stderr(self, level=None):
1607db96d56Sopenharmony_ci        '''Turn on logging and add a handler which prints to stderr'''
1617db96d56Sopenharmony_ci        from .util import log_to_stderr
1627db96d56Sopenharmony_ci        return log_to_stderr(level)
1637db96d56Sopenharmony_ci
1647db96d56Sopenharmony_ci    def allow_connection_pickling(self):
1657db96d56Sopenharmony_ci        '''Install support for sending connections and sockets
1667db96d56Sopenharmony_ci        between processes
1677db96d56Sopenharmony_ci        '''
1687db96d56Sopenharmony_ci        # This is undocumented.  In previous versions of multiprocessing
1697db96d56Sopenharmony_ci        # its only effect was to make socket objects inheritable on Windows.
1707db96d56Sopenharmony_ci        from . import connection
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci    def set_executable(self, executable):
1737db96d56Sopenharmony_ci        '''Sets the path to a python.exe or pythonw.exe binary used to run
1747db96d56Sopenharmony_ci        child processes instead of sys.executable when using the 'spawn'
1757db96d56Sopenharmony_ci        start method.  Useful for people embedding Python.
1767db96d56Sopenharmony_ci        '''
1777db96d56Sopenharmony_ci        from .spawn import set_executable
1787db96d56Sopenharmony_ci        set_executable(executable)
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci    def set_forkserver_preload(self, module_names):
1817db96d56Sopenharmony_ci        '''Set list of module names to try to load in forkserver process.
1827db96d56Sopenharmony_ci        This is really just a hint.
1837db96d56Sopenharmony_ci        '''
1847db96d56Sopenharmony_ci        from .forkserver import set_forkserver_preload
1857db96d56Sopenharmony_ci        set_forkserver_preload(module_names)
1867db96d56Sopenharmony_ci
1877db96d56Sopenharmony_ci    def get_context(self, method=None):
1887db96d56Sopenharmony_ci        if method is None:
1897db96d56Sopenharmony_ci            return self
1907db96d56Sopenharmony_ci        try:
1917db96d56Sopenharmony_ci            ctx = _concrete_contexts[method]
1927db96d56Sopenharmony_ci        except KeyError:
1937db96d56Sopenharmony_ci            raise ValueError('cannot find context for %r' % method) from None
1947db96d56Sopenharmony_ci        ctx._check_available()
1957db96d56Sopenharmony_ci        return ctx
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ci    def get_start_method(self, allow_none=False):
1987db96d56Sopenharmony_ci        return self._name
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci    def set_start_method(self, method, force=False):
2017db96d56Sopenharmony_ci        raise ValueError('cannot set start method of concrete context')
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci    @property
2047db96d56Sopenharmony_ci    def reducer(self):
2057db96d56Sopenharmony_ci        '''Controls how objects will be reduced to a form that can be
2067db96d56Sopenharmony_ci        shared with other processes.'''
2077db96d56Sopenharmony_ci        return globals().get('reduction')
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    @reducer.setter
2107db96d56Sopenharmony_ci    def reducer(self, reduction):
2117db96d56Sopenharmony_ci        globals()['reduction'] = reduction
2127db96d56Sopenharmony_ci
2137db96d56Sopenharmony_ci    def _check_available(self):
2147db96d56Sopenharmony_ci        pass
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ci#
2177db96d56Sopenharmony_ci# Type of default context -- underlying context can be set at most once
2187db96d56Sopenharmony_ci#
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ciclass Process(process.BaseProcess):
2217db96d56Sopenharmony_ci    _start_method = None
2227db96d56Sopenharmony_ci    @staticmethod
2237db96d56Sopenharmony_ci    def _Popen(process_obj):
2247db96d56Sopenharmony_ci        return _default_context.get_context().Process._Popen(process_obj)
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci    @staticmethod
2277db96d56Sopenharmony_ci    def _after_fork():
2287db96d56Sopenharmony_ci        return _default_context.get_context().Process._after_fork()
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_ciclass DefaultContext(BaseContext):
2317db96d56Sopenharmony_ci    Process = Process
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci    def __init__(self, context):
2347db96d56Sopenharmony_ci        self._default_context = context
2357db96d56Sopenharmony_ci        self._actual_context = None
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci    def get_context(self, method=None):
2387db96d56Sopenharmony_ci        if method is None:
2397db96d56Sopenharmony_ci            if self._actual_context is None:
2407db96d56Sopenharmony_ci                self._actual_context = self._default_context
2417db96d56Sopenharmony_ci            return self._actual_context
2427db96d56Sopenharmony_ci        else:
2437db96d56Sopenharmony_ci            return super().get_context(method)
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci    def set_start_method(self, method, force=False):
2467db96d56Sopenharmony_ci        if self._actual_context is not None and not force:
2477db96d56Sopenharmony_ci            raise RuntimeError('context has already been set')
2487db96d56Sopenharmony_ci        if method is None and force:
2497db96d56Sopenharmony_ci            self._actual_context = None
2507db96d56Sopenharmony_ci            return
2517db96d56Sopenharmony_ci        self._actual_context = self.get_context(method)
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ci    def get_start_method(self, allow_none=False):
2547db96d56Sopenharmony_ci        if self._actual_context is None:
2557db96d56Sopenharmony_ci            if allow_none:
2567db96d56Sopenharmony_ci                return None
2577db96d56Sopenharmony_ci            self._actual_context = self._default_context
2587db96d56Sopenharmony_ci        return self._actual_context._name
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ci    def get_all_start_methods(self):
2617db96d56Sopenharmony_ci        if sys.platform == 'win32':
2627db96d56Sopenharmony_ci            return ['spawn']
2637db96d56Sopenharmony_ci        else:
2647db96d56Sopenharmony_ci            methods = ['spawn', 'fork'] if sys.platform == 'darwin' else ['fork', 'spawn']
2657db96d56Sopenharmony_ci            if reduction.HAVE_SEND_HANDLE:
2667db96d56Sopenharmony_ci                methods.append('forkserver')
2677db96d56Sopenharmony_ci            return methods
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_ci#
2717db96d56Sopenharmony_ci# Context types for fixed start method
2727db96d56Sopenharmony_ci#
2737db96d56Sopenharmony_ci
2747db96d56Sopenharmony_ciif sys.platform != 'win32':
2757db96d56Sopenharmony_ci
2767db96d56Sopenharmony_ci    class ForkProcess(process.BaseProcess):
2777db96d56Sopenharmony_ci        _start_method = 'fork'
2787db96d56Sopenharmony_ci        @staticmethod
2797db96d56Sopenharmony_ci        def _Popen(process_obj):
2807db96d56Sopenharmony_ci            from .popen_fork import Popen
2817db96d56Sopenharmony_ci            return Popen(process_obj)
2827db96d56Sopenharmony_ci
2837db96d56Sopenharmony_ci    class SpawnProcess(process.BaseProcess):
2847db96d56Sopenharmony_ci        _start_method = 'spawn'
2857db96d56Sopenharmony_ci        @staticmethod
2867db96d56Sopenharmony_ci        def _Popen(process_obj):
2877db96d56Sopenharmony_ci            from .popen_spawn_posix import Popen
2887db96d56Sopenharmony_ci            return Popen(process_obj)
2897db96d56Sopenharmony_ci
2907db96d56Sopenharmony_ci        @staticmethod
2917db96d56Sopenharmony_ci        def _after_fork():
2927db96d56Sopenharmony_ci            # process is spawned, nothing to do
2937db96d56Sopenharmony_ci            pass
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci    class ForkServerProcess(process.BaseProcess):
2967db96d56Sopenharmony_ci        _start_method = 'forkserver'
2977db96d56Sopenharmony_ci        @staticmethod
2987db96d56Sopenharmony_ci        def _Popen(process_obj):
2997db96d56Sopenharmony_ci            from .popen_forkserver import Popen
3007db96d56Sopenharmony_ci            return Popen(process_obj)
3017db96d56Sopenharmony_ci
3027db96d56Sopenharmony_ci    class ForkContext(BaseContext):
3037db96d56Sopenharmony_ci        _name = 'fork'
3047db96d56Sopenharmony_ci        Process = ForkProcess
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ci    class SpawnContext(BaseContext):
3077db96d56Sopenharmony_ci        _name = 'spawn'
3087db96d56Sopenharmony_ci        Process = SpawnProcess
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ci    class ForkServerContext(BaseContext):
3117db96d56Sopenharmony_ci        _name = 'forkserver'
3127db96d56Sopenharmony_ci        Process = ForkServerProcess
3137db96d56Sopenharmony_ci        def _check_available(self):
3147db96d56Sopenharmony_ci            if not reduction.HAVE_SEND_HANDLE:
3157db96d56Sopenharmony_ci                raise ValueError('forkserver start method not available')
3167db96d56Sopenharmony_ci
3177db96d56Sopenharmony_ci    _concrete_contexts = {
3187db96d56Sopenharmony_ci        'fork': ForkContext(),
3197db96d56Sopenharmony_ci        'spawn': SpawnContext(),
3207db96d56Sopenharmony_ci        'forkserver': ForkServerContext(),
3217db96d56Sopenharmony_ci    }
3227db96d56Sopenharmony_ci    if sys.platform == 'darwin':
3237db96d56Sopenharmony_ci        # bpo-33725: running arbitrary code after fork() is no longer reliable
3247db96d56Sopenharmony_ci        # on macOS since macOS 10.14 (Mojave). Use spawn by default instead.
3257db96d56Sopenharmony_ci        _default_context = DefaultContext(_concrete_contexts['spawn'])
3267db96d56Sopenharmony_ci    else:
3277db96d56Sopenharmony_ci        _default_context = DefaultContext(_concrete_contexts['fork'])
3287db96d56Sopenharmony_ci
3297db96d56Sopenharmony_cielse:
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci    class SpawnProcess(process.BaseProcess):
3327db96d56Sopenharmony_ci        _start_method = 'spawn'
3337db96d56Sopenharmony_ci        @staticmethod
3347db96d56Sopenharmony_ci        def _Popen(process_obj):
3357db96d56Sopenharmony_ci            from .popen_spawn_win32 import Popen
3367db96d56Sopenharmony_ci            return Popen(process_obj)
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_ci        @staticmethod
3397db96d56Sopenharmony_ci        def _after_fork():
3407db96d56Sopenharmony_ci            # process is spawned, nothing to do
3417db96d56Sopenharmony_ci            pass
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_ci    class SpawnContext(BaseContext):
3447db96d56Sopenharmony_ci        _name = 'spawn'
3457db96d56Sopenharmony_ci        Process = SpawnProcess
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ci    _concrete_contexts = {
3487db96d56Sopenharmony_ci        'spawn': SpawnContext(),
3497db96d56Sopenharmony_ci    }
3507db96d56Sopenharmony_ci    _default_context = DefaultContext(_concrete_contexts['spawn'])
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ci#
3537db96d56Sopenharmony_ci# Force the start method
3547db96d56Sopenharmony_ci#
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_cidef _force_start_method(method):
3577db96d56Sopenharmony_ci    _default_context._actual_context = _concrete_contexts[method]
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci#
3607db96d56Sopenharmony_ci# Check that the current thread is spawning a child process
3617db96d56Sopenharmony_ci#
3627db96d56Sopenharmony_ci
3637db96d56Sopenharmony_ci_tls = threading.local()
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_cidef get_spawning_popen():
3667db96d56Sopenharmony_ci    return getattr(_tls, 'spawning_popen', None)
3677db96d56Sopenharmony_ci
3687db96d56Sopenharmony_cidef set_spawning_popen(popen):
3697db96d56Sopenharmony_ci    _tls.spawning_popen = popen
3707db96d56Sopenharmony_ci
3717db96d56Sopenharmony_cidef assert_spawning(obj):
3727db96d56Sopenharmony_ci    if get_spawning_popen() is None:
3737db96d56Sopenharmony_ci        raise RuntimeError(
3747db96d56Sopenharmony_ci            '%s objects should only be shared between processes'
3757db96d56Sopenharmony_ci            ' through inheritance' % type(obj).__name__
3767db96d56Sopenharmony_ci            )
377