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