1*cda5da8dSAndroid Build Coastguard Worker"""Selector event loop for Unix with signal handling.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Workerimport errno 4*cda5da8dSAndroid Build Coastguard Workerimport io 5*cda5da8dSAndroid Build Coastguard Workerimport itertools 6*cda5da8dSAndroid Build Coastguard Workerimport os 7*cda5da8dSAndroid Build Coastguard Workerimport selectors 8*cda5da8dSAndroid Build Coastguard Workerimport signal 9*cda5da8dSAndroid Build Coastguard Workerimport socket 10*cda5da8dSAndroid Build Coastguard Workerimport stat 11*cda5da8dSAndroid Build Coastguard Workerimport subprocess 12*cda5da8dSAndroid Build Coastguard Workerimport sys 13*cda5da8dSAndroid Build Coastguard Workerimport threading 14*cda5da8dSAndroid Build Coastguard Workerimport warnings 15*cda5da8dSAndroid Build Coastguard Worker 16*cda5da8dSAndroid Build Coastguard Workerfrom . import base_events 17*cda5da8dSAndroid Build Coastguard Workerfrom . import base_subprocess 18*cda5da8dSAndroid Build Coastguard Workerfrom . import constants 19*cda5da8dSAndroid Build Coastguard Workerfrom . import coroutines 20*cda5da8dSAndroid Build Coastguard Workerfrom . import events 21*cda5da8dSAndroid Build Coastguard Workerfrom . import exceptions 22*cda5da8dSAndroid Build Coastguard Workerfrom . import futures 23*cda5da8dSAndroid Build Coastguard Workerfrom . import selector_events 24*cda5da8dSAndroid Build Coastguard Workerfrom . import tasks 25*cda5da8dSAndroid Build Coastguard Workerfrom . import transports 26*cda5da8dSAndroid Build Coastguard Workerfrom .log import logger 27*cda5da8dSAndroid Build Coastguard Worker 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker__all__ = ( 30*cda5da8dSAndroid Build Coastguard Worker 'SelectorEventLoop', 31*cda5da8dSAndroid Build Coastguard Worker 'AbstractChildWatcher', 'SafeChildWatcher', 32*cda5da8dSAndroid Build Coastguard Worker 'FastChildWatcher', 'PidfdChildWatcher', 33*cda5da8dSAndroid Build Coastguard Worker 'MultiLoopChildWatcher', 'ThreadedChildWatcher', 34*cda5da8dSAndroid Build Coastguard Worker 'DefaultEventLoopPolicy', 35*cda5da8dSAndroid Build Coastguard Worker) 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Worker 38*cda5da8dSAndroid Build Coastguard Workerif sys.platform == 'win32': # pragma: no cover 39*cda5da8dSAndroid Build Coastguard Worker raise ImportError('Signals are not really supported on Windows') 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Worker 42*cda5da8dSAndroid Build Coastguard Workerdef _sighandler_noop(signum, frame): 43*cda5da8dSAndroid Build Coastguard Worker """Dummy signal handler.""" 44*cda5da8dSAndroid Build Coastguard Worker pass 45*cda5da8dSAndroid Build Coastguard Worker 46*cda5da8dSAndroid Build Coastguard Worker 47*cda5da8dSAndroid Build Coastguard Workerdef waitstatus_to_exitcode(status): 48*cda5da8dSAndroid Build Coastguard Worker try: 49*cda5da8dSAndroid Build Coastguard Worker return os.waitstatus_to_exitcode(status) 50*cda5da8dSAndroid Build Coastguard Worker except ValueError: 51*cda5da8dSAndroid Build Coastguard Worker # The child exited, but we don't understand its status. 52*cda5da8dSAndroid Build Coastguard Worker # This shouldn't happen, but if it does, let's just 53*cda5da8dSAndroid Build Coastguard Worker # return that status; perhaps that helps debug it. 54*cda5da8dSAndroid Build Coastguard Worker return status 55*cda5da8dSAndroid Build Coastguard Worker 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Workerclass _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): 58*cda5da8dSAndroid Build Coastguard Worker """Unix event loop. 59*cda5da8dSAndroid Build Coastguard Worker 60*cda5da8dSAndroid Build Coastguard Worker Adds signal handling and UNIX Domain Socket support to SelectorEventLoop. 61*cda5da8dSAndroid Build Coastguard Worker """ 62*cda5da8dSAndroid Build Coastguard Worker 63*cda5da8dSAndroid Build Coastguard Worker def __init__(self, selector=None): 64*cda5da8dSAndroid Build Coastguard Worker super().__init__(selector) 65*cda5da8dSAndroid Build Coastguard Worker self._signal_handlers = {} 66*cda5da8dSAndroid Build Coastguard Worker 67*cda5da8dSAndroid Build Coastguard Worker def close(self): 68*cda5da8dSAndroid Build Coastguard Worker super().close() 69*cda5da8dSAndroid Build Coastguard Worker if not sys.is_finalizing(): 70*cda5da8dSAndroid Build Coastguard Worker for sig in list(self._signal_handlers): 71*cda5da8dSAndroid Build Coastguard Worker self.remove_signal_handler(sig) 72*cda5da8dSAndroid Build Coastguard Worker else: 73*cda5da8dSAndroid Build Coastguard Worker if self._signal_handlers: 74*cda5da8dSAndroid Build Coastguard Worker warnings.warn(f"Closing the loop {self!r} " 75*cda5da8dSAndroid Build Coastguard Worker f"on interpreter shutdown " 76*cda5da8dSAndroid Build Coastguard Worker f"stage, skipping signal handlers removal", 77*cda5da8dSAndroid Build Coastguard Worker ResourceWarning, 78*cda5da8dSAndroid Build Coastguard Worker source=self) 79*cda5da8dSAndroid Build Coastguard Worker self._signal_handlers.clear() 80*cda5da8dSAndroid Build Coastguard Worker 81*cda5da8dSAndroid Build Coastguard Worker def _process_self_data(self, data): 82*cda5da8dSAndroid Build Coastguard Worker for signum in data: 83*cda5da8dSAndroid Build Coastguard Worker if not signum: 84*cda5da8dSAndroid Build Coastguard Worker # ignore null bytes written by _write_to_self() 85*cda5da8dSAndroid Build Coastguard Worker continue 86*cda5da8dSAndroid Build Coastguard Worker self._handle_signal(signum) 87*cda5da8dSAndroid Build Coastguard Worker 88*cda5da8dSAndroid Build Coastguard Worker def add_signal_handler(self, sig, callback, *args): 89*cda5da8dSAndroid Build Coastguard Worker """Add a handler for a signal. UNIX only. 90*cda5da8dSAndroid Build Coastguard Worker 91*cda5da8dSAndroid Build Coastguard Worker Raise ValueError if the signal number is invalid or uncatchable. 92*cda5da8dSAndroid Build Coastguard Worker Raise RuntimeError if there is a problem setting up the handler. 93*cda5da8dSAndroid Build Coastguard Worker """ 94*cda5da8dSAndroid Build Coastguard Worker if (coroutines.iscoroutine(callback) or 95*cda5da8dSAndroid Build Coastguard Worker coroutines.iscoroutinefunction(callback)): 96*cda5da8dSAndroid Build Coastguard Worker raise TypeError("coroutines cannot be used " 97*cda5da8dSAndroid Build Coastguard Worker "with add_signal_handler()") 98*cda5da8dSAndroid Build Coastguard Worker self._check_signal(sig) 99*cda5da8dSAndroid Build Coastguard Worker self._check_closed() 100*cda5da8dSAndroid Build Coastguard Worker try: 101*cda5da8dSAndroid Build Coastguard Worker # set_wakeup_fd() raises ValueError if this is not the 102*cda5da8dSAndroid Build Coastguard Worker # main thread. By calling it early we ensure that an 103*cda5da8dSAndroid Build Coastguard Worker # event loop running in another thread cannot add a signal 104*cda5da8dSAndroid Build Coastguard Worker # handler. 105*cda5da8dSAndroid Build Coastguard Worker signal.set_wakeup_fd(self._csock.fileno()) 106*cda5da8dSAndroid Build Coastguard Worker except (ValueError, OSError) as exc: 107*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError(str(exc)) 108*cda5da8dSAndroid Build Coastguard Worker 109*cda5da8dSAndroid Build Coastguard Worker handle = events.Handle(callback, args, self, None) 110*cda5da8dSAndroid Build Coastguard Worker self._signal_handlers[sig] = handle 111*cda5da8dSAndroid Build Coastguard Worker 112*cda5da8dSAndroid Build Coastguard Worker try: 113*cda5da8dSAndroid Build Coastguard Worker # Register a dummy signal handler to ask Python to write the signal 114*cda5da8dSAndroid Build Coastguard Worker # number in the wakeup file descriptor. _process_self_data() will 115*cda5da8dSAndroid Build Coastguard Worker # read signal numbers from this file descriptor to handle signals. 116*cda5da8dSAndroid Build Coastguard Worker signal.signal(sig, _sighandler_noop) 117*cda5da8dSAndroid Build Coastguard Worker 118*cda5da8dSAndroid Build Coastguard Worker # Set SA_RESTART to limit EINTR occurrences. 119*cda5da8dSAndroid Build Coastguard Worker signal.siginterrupt(sig, False) 120*cda5da8dSAndroid Build Coastguard Worker except OSError as exc: 121*cda5da8dSAndroid Build Coastguard Worker del self._signal_handlers[sig] 122*cda5da8dSAndroid Build Coastguard Worker if not self._signal_handlers: 123*cda5da8dSAndroid Build Coastguard Worker try: 124*cda5da8dSAndroid Build Coastguard Worker signal.set_wakeup_fd(-1) 125*cda5da8dSAndroid Build Coastguard Worker except (ValueError, OSError) as nexc: 126*cda5da8dSAndroid Build Coastguard Worker logger.info('set_wakeup_fd(-1) failed: %s', nexc) 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker if exc.errno == errno.EINVAL: 129*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError(f'sig {sig} cannot be caught') 130*cda5da8dSAndroid Build Coastguard Worker else: 131*cda5da8dSAndroid Build Coastguard Worker raise 132*cda5da8dSAndroid Build Coastguard Worker 133*cda5da8dSAndroid Build Coastguard Worker def _handle_signal(self, sig): 134*cda5da8dSAndroid Build Coastguard Worker """Internal helper that is the actual signal handler.""" 135*cda5da8dSAndroid Build Coastguard Worker handle = self._signal_handlers.get(sig) 136*cda5da8dSAndroid Build Coastguard Worker if handle is None: 137*cda5da8dSAndroid Build Coastguard Worker return # Assume it's some race condition. 138*cda5da8dSAndroid Build Coastguard Worker if handle._cancelled: 139*cda5da8dSAndroid Build Coastguard Worker self.remove_signal_handler(sig) # Remove it properly. 140*cda5da8dSAndroid Build Coastguard Worker else: 141*cda5da8dSAndroid Build Coastguard Worker self._add_callback_signalsafe(handle) 142*cda5da8dSAndroid Build Coastguard Worker 143*cda5da8dSAndroid Build Coastguard Worker def remove_signal_handler(self, sig): 144*cda5da8dSAndroid Build Coastguard Worker """Remove a handler for a signal. UNIX only. 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker Return True if a signal handler was removed, False if not. 147*cda5da8dSAndroid Build Coastguard Worker """ 148*cda5da8dSAndroid Build Coastguard Worker self._check_signal(sig) 149*cda5da8dSAndroid Build Coastguard Worker try: 150*cda5da8dSAndroid Build Coastguard Worker del self._signal_handlers[sig] 151*cda5da8dSAndroid Build Coastguard Worker except KeyError: 152*cda5da8dSAndroid Build Coastguard Worker return False 153*cda5da8dSAndroid Build Coastguard Worker 154*cda5da8dSAndroid Build Coastguard Worker if sig == signal.SIGINT: 155*cda5da8dSAndroid Build Coastguard Worker handler = signal.default_int_handler 156*cda5da8dSAndroid Build Coastguard Worker else: 157*cda5da8dSAndroid Build Coastguard Worker handler = signal.SIG_DFL 158*cda5da8dSAndroid Build Coastguard Worker 159*cda5da8dSAndroid Build Coastguard Worker try: 160*cda5da8dSAndroid Build Coastguard Worker signal.signal(sig, handler) 161*cda5da8dSAndroid Build Coastguard Worker except OSError as exc: 162*cda5da8dSAndroid Build Coastguard Worker if exc.errno == errno.EINVAL: 163*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError(f'sig {sig} cannot be caught') 164*cda5da8dSAndroid Build Coastguard Worker else: 165*cda5da8dSAndroid Build Coastguard Worker raise 166*cda5da8dSAndroid Build Coastguard Worker 167*cda5da8dSAndroid Build Coastguard Worker if not self._signal_handlers: 168*cda5da8dSAndroid Build Coastguard Worker try: 169*cda5da8dSAndroid Build Coastguard Worker signal.set_wakeup_fd(-1) 170*cda5da8dSAndroid Build Coastguard Worker except (ValueError, OSError) as exc: 171*cda5da8dSAndroid Build Coastguard Worker logger.info('set_wakeup_fd(-1) failed: %s', exc) 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Worker return True 174*cda5da8dSAndroid Build Coastguard Worker 175*cda5da8dSAndroid Build Coastguard Worker def _check_signal(self, sig): 176*cda5da8dSAndroid Build Coastguard Worker """Internal helper to validate a signal. 177*cda5da8dSAndroid Build Coastguard Worker 178*cda5da8dSAndroid Build Coastguard Worker Raise ValueError if the signal number is invalid or uncatchable. 179*cda5da8dSAndroid Build Coastguard Worker Raise RuntimeError if there is a problem setting up the handler. 180*cda5da8dSAndroid Build Coastguard Worker """ 181*cda5da8dSAndroid Build Coastguard Worker if not isinstance(sig, int): 182*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'sig must be an int, not {sig!r}') 183*cda5da8dSAndroid Build Coastguard Worker 184*cda5da8dSAndroid Build Coastguard Worker if sig not in signal.valid_signals(): 185*cda5da8dSAndroid Build Coastguard Worker raise ValueError(f'invalid signal number {sig}') 186*cda5da8dSAndroid Build Coastguard Worker 187*cda5da8dSAndroid Build Coastguard Worker def _make_read_pipe_transport(self, pipe, protocol, waiter=None, 188*cda5da8dSAndroid Build Coastguard Worker extra=None): 189*cda5da8dSAndroid Build Coastguard Worker return _UnixReadPipeTransport(self, pipe, protocol, waiter, extra) 190*cda5da8dSAndroid Build Coastguard Worker 191*cda5da8dSAndroid Build Coastguard Worker def _make_write_pipe_transport(self, pipe, protocol, waiter=None, 192*cda5da8dSAndroid Build Coastguard Worker extra=None): 193*cda5da8dSAndroid Build Coastguard Worker return _UnixWritePipeTransport(self, pipe, protocol, waiter, extra) 194*cda5da8dSAndroid Build Coastguard Worker 195*cda5da8dSAndroid Build Coastguard Worker async def _make_subprocess_transport(self, protocol, args, shell, 196*cda5da8dSAndroid Build Coastguard Worker stdin, stdout, stderr, bufsize, 197*cda5da8dSAndroid Build Coastguard Worker extra=None, **kwargs): 198*cda5da8dSAndroid Build Coastguard Worker with events.get_child_watcher() as watcher: 199*cda5da8dSAndroid Build Coastguard Worker if not watcher.is_active(): 200*cda5da8dSAndroid Build Coastguard Worker # Check early. 201*cda5da8dSAndroid Build Coastguard Worker # Raising exception before process creation 202*cda5da8dSAndroid Build Coastguard Worker # prevents subprocess execution if the watcher 203*cda5da8dSAndroid Build Coastguard Worker # is not ready to handle it. 204*cda5da8dSAndroid Build Coastguard Worker raise RuntimeError("asyncio.get_child_watcher() is not activated, " 205*cda5da8dSAndroid Build Coastguard Worker "subprocess support is not installed.") 206*cda5da8dSAndroid Build Coastguard Worker waiter = self.create_future() 207*cda5da8dSAndroid Build Coastguard Worker transp = _UnixSubprocessTransport(self, protocol, args, shell, 208*cda5da8dSAndroid Build Coastguard Worker stdin, stdout, stderr, bufsize, 209*cda5da8dSAndroid Build Coastguard Worker waiter=waiter, extra=extra, 210*cda5da8dSAndroid Build Coastguard Worker **kwargs) 211*cda5da8dSAndroid Build Coastguard Worker 212*cda5da8dSAndroid Build Coastguard Worker watcher.add_child_handler(transp.get_pid(), 213*cda5da8dSAndroid Build Coastguard Worker self._child_watcher_callback, transp) 214*cda5da8dSAndroid Build Coastguard Worker try: 215*cda5da8dSAndroid Build Coastguard Worker await waiter 216*cda5da8dSAndroid Build Coastguard Worker except (SystemExit, KeyboardInterrupt): 217*cda5da8dSAndroid Build Coastguard Worker raise 218*cda5da8dSAndroid Build Coastguard Worker except BaseException: 219*cda5da8dSAndroid Build Coastguard Worker transp.close() 220*cda5da8dSAndroid Build Coastguard Worker await transp._wait() 221*cda5da8dSAndroid Build Coastguard Worker raise 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker return transp 224*cda5da8dSAndroid Build Coastguard Worker 225*cda5da8dSAndroid Build Coastguard Worker def _child_watcher_callback(self, pid, returncode, transp): 226*cda5da8dSAndroid Build Coastguard Worker # Skip one iteration for callbacks to be executed 227*cda5da8dSAndroid Build Coastguard Worker self.call_soon_threadsafe(self.call_soon, transp._process_exited, returncode) 228*cda5da8dSAndroid Build Coastguard Worker 229*cda5da8dSAndroid Build Coastguard Worker async def create_unix_connection( 230*cda5da8dSAndroid Build Coastguard Worker self, protocol_factory, path=None, *, 231*cda5da8dSAndroid Build Coastguard Worker ssl=None, sock=None, 232*cda5da8dSAndroid Build Coastguard Worker server_hostname=None, 233*cda5da8dSAndroid Build Coastguard Worker ssl_handshake_timeout=None, 234*cda5da8dSAndroid Build Coastguard Worker ssl_shutdown_timeout=None): 235*cda5da8dSAndroid Build Coastguard Worker assert server_hostname is None or isinstance(server_hostname, str) 236*cda5da8dSAndroid Build Coastguard Worker if ssl: 237*cda5da8dSAndroid Build Coastguard Worker if server_hostname is None: 238*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 239*cda5da8dSAndroid Build Coastguard Worker 'you have to pass server_hostname when using ssl') 240*cda5da8dSAndroid Build Coastguard Worker else: 241*cda5da8dSAndroid Build Coastguard Worker if server_hostname is not None: 242*cda5da8dSAndroid Build Coastguard Worker raise ValueError('server_hostname is only meaningful with ssl') 243*cda5da8dSAndroid Build Coastguard Worker if ssl_handshake_timeout is not None: 244*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 245*cda5da8dSAndroid Build Coastguard Worker 'ssl_handshake_timeout is only meaningful with ssl') 246*cda5da8dSAndroid Build Coastguard Worker if ssl_shutdown_timeout is not None: 247*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 248*cda5da8dSAndroid Build Coastguard Worker 'ssl_shutdown_timeout is only meaningful with ssl') 249*cda5da8dSAndroid Build Coastguard Worker 250*cda5da8dSAndroid Build Coastguard Worker if path is not None: 251*cda5da8dSAndroid Build Coastguard Worker if sock is not None: 252*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 253*cda5da8dSAndroid Build Coastguard Worker 'path and sock can not be specified at the same time') 254*cda5da8dSAndroid Build Coastguard Worker 255*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 256*cda5da8dSAndroid Build Coastguard Worker sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) 257*cda5da8dSAndroid Build Coastguard Worker try: 258*cda5da8dSAndroid Build Coastguard Worker sock.setblocking(False) 259*cda5da8dSAndroid Build Coastguard Worker await self.sock_connect(sock, path) 260*cda5da8dSAndroid Build Coastguard Worker except: 261*cda5da8dSAndroid Build Coastguard Worker sock.close() 262*cda5da8dSAndroid Build Coastguard Worker raise 263*cda5da8dSAndroid Build Coastguard Worker 264*cda5da8dSAndroid Build Coastguard Worker else: 265*cda5da8dSAndroid Build Coastguard Worker if sock is None: 266*cda5da8dSAndroid Build Coastguard Worker raise ValueError('no path and sock were specified') 267*cda5da8dSAndroid Build Coastguard Worker if (sock.family != socket.AF_UNIX or 268*cda5da8dSAndroid Build Coastguard Worker sock.type != socket.SOCK_STREAM): 269*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 270*cda5da8dSAndroid Build Coastguard Worker f'A UNIX Domain Stream Socket was expected, got {sock!r}') 271*cda5da8dSAndroid Build Coastguard Worker sock.setblocking(False) 272*cda5da8dSAndroid Build Coastguard Worker 273*cda5da8dSAndroid Build Coastguard Worker transport, protocol = await self._create_connection_transport( 274*cda5da8dSAndroid Build Coastguard Worker sock, protocol_factory, ssl, server_hostname, 275*cda5da8dSAndroid Build Coastguard Worker ssl_handshake_timeout=ssl_handshake_timeout, 276*cda5da8dSAndroid Build Coastguard Worker ssl_shutdown_timeout=ssl_shutdown_timeout) 277*cda5da8dSAndroid Build Coastguard Worker return transport, protocol 278*cda5da8dSAndroid Build Coastguard Worker 279*cda5da8dSAndroid Build Coastguard Worker async def create_unix_server( 280*cda5da8dSAndroid Build Coastguard Worker self, protocol_factory, path=None, *, 281*cda5da8dSAndroid Build Coastguard Worker sock=None, backlog=100, ssl=None, 282*cda5da8dSAndroid Build Coastguard Worker ssl_handshake_timeout=None, 283*cda5da8dSAndroid Build Coastguard Worker ssl_shutdown_timeout=None, 284*cda5da8dSAndroid Build Coastguard Worker start_serving=True): 285*cda5da8dSAndroid Build Coastguard Worker if isinstance(ssl, bool): 286*cda5da8dSAndroid Build Coastguard Worker raise TypeError('ssl argument must be an SSLContext or None') 287*cda5da8dSAndroid Build Coastguard Worker 288*cda5da8dSAndroid Build Coastguard Worker if ssl_handshake_timeout is not None and not ssl: 289*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 290*cda5da8dSAndroid Build Coastguard Worker 'ssl_handshake_timeout is only meaningful with ssl') 291*cda5da8dSAndroid Build Coastguard Worker 292*cda5da8dSAndroid Build Coastguard Worker if ssl_shutdown_timeout is not None and not ssl: 293*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 294*cda5da8dSAndroid Build Coastguard Worker 'ssl_shutdown_timeout is only meaningful with ssl') 295*cda5da8dSAndroid Build Coastguard Worker 296*cda5da8dSAndroid Build Coastguard Worker if path is not None: 297*cda5da8dSAndroid Build Coastguard Worker if sock is not None: 298*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 299*cda5da8dSAndroid Build Coastguard Worker 'path and sock can not be specified at the same time') 300*cda5da8dSAndroid Build Coastguard Worker 301*cda5da8dSAndroid Build Coastguard Worker path = os.fspath(path) 302*cda5da8dSAndroid Build Coastguard Worker sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 303*cda5da8dSAndroid Build Coastguard Worker 304*cda5da8dSAndroid Build Coastguard Worker # Check for abstract socket. `str` and `bytes` paths are supported. 305*cda5da8dSAndroid Build Coastguard Worker if path[0] not in (0, '\x00'): 306*cda5da8dSAndroid Build Coastguard Worker try: 307*cda5da8dSAndroid Build Coastguard Worker if stat.S_ISSOCK(os.stat(path).st_mode): 308*cda5da8dSAndroid Build Coastguard Worker os.remove(path) 309*cda5da8dSAndroid Build Coastguard Worker except FileNotFoundError: 310*cda5da8dSAndroid Build Coastguard Worker pass 311*cda5da8dSAndroid Build Coastguard Worker except OSError as err: 312*cda5da8dSAndroid Build Coastguard Worker # Directory may have permissions only to create socket. 313*cda5da8dSAndroid Build Coastguard Worker logger.error('Unable to check or remove stale UNIX socket ' 314*cda5da8dSAndroid Build Coastguard Worker '%r: %r', path, err) 315*cda5da8dSAndroid Build Coastguard Worker 316*cda5da8dSAndroid Build Coastguard Worker try: 317*cda5da8dSAndroid Build Coastguard Worker sock.bind(path) 318*cda5da8dSAndroid Build Coastguard Worker except OSError as exc: 319*cda5da8dSAndroid Build Coastguard Worker sock.close() 320*cda5da8dSAndroid Build Coastguard Worker if exc.errno == errno.EADDRINUSE: 321*cda5da8dSAndroid Build Coastguard Worker # Let's improve the error message by adding 322*cda5da8dSAndroid Build Coastguard Worker # with what exact address it occurs. 323*cda5da8dSAndroid Build Coastguard Worker msg = f'Address {path!r} is already in use' 324*cda5da8dSAndroid Build Coastguard Worker raise OSError(errno.EADDRINUSE, msg) from None 325*cda5da8dSAndroid Build Coastguard Worker else: 326*cda5da8dSAndroid Build Coastguard Worker raise 327*cda5da8dSAndroid Build Coastguard Worker except: 328*cda5da8dSAndroid Build Coastguard Worker sock.close() 329*cda5da8dSAndroid Build Coastguard Worker raise 330*cda5da8dSAndroid Build Coastguard Worker else: 331*cda5da8dSAndroid Build Coastguard Worker if sock is None: 332*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 333*cda5da8dSAndroid Build Coastguard Worker 'path was not specified, and no sock specified') 334*cda5da8dSAndroid Build Coastguard Worker 335*cda5da8dSAndroid Build Coastguard Worker if (sock.family != socket.AF_UNIX or 336*cda5da8dSAndroid Build Coastguard Worker sock.type != socket.SOCK_STREAM): 337*cda5da8dSAndroid Build Coastguard Worker raise ValueError( 338*cda5da8dSAndroid Build Coastguard Worker f'A UNIX Domain Stream Socket was expected, got {sock!r}') 339*cda5da8dSAndroid Build Coastguard Worker 340*cda5da8dSAndroid Build Coastguard Worker sock.setblocking(False) 341*cda5da8dSAndroid Build Coastguard Worker server = base_events.Server(self, [sock], protocol_factory, 342*cda5da8dSAndroid Build Coastguard Worker ssl, backlog, ssl_handshake_timeout, 343*cda5da8dSAndroid Build Coastguard Worker ssl_shutdown_timeout) 344*cda5da8dSAndroid Build Coastguard Worker if start_serving: 345*cda5da8dSAndroid Build Coastguard Worker server._start_serving() 346*cda5da8dSAndroid Build Coastguard Worker # Skip one loop iteration so that all 'loop.add_reader' 347*cda5da8dSAndroid Build Coastguard Worker # go through. 348*cda5da8dSAndroid Build Coastguard Worker await tasks.sleep(0) 349*cda5da8dSAndroid Build Coastguard Worker 350*cda5da8dSAndroid Build Coastguard Worker return server 351*cda5da8dSAndroid Build Coastguard Worker 352*cda5da8dSAndroid Build Coastguard Worker async def _sock_sendfile_native(self, sock, file, offset, count): 353*cda5da8dSAndroid Build Coastguard Worker try: 354*cda5da8dSAndroid Build Coastguard Worker os.sendfile 355*cda5da8dSAndroid Build Coastguard Worker except AttributeError: 356*cda5da8dSAndroid Build Coastguard Worker raise exceptions.SendfileNotAvailableError( 357*cda5da8dSAndroid Build Coastguard Worker "os.sendfile() is not available") 358*cda5da8dSAndroid Build Coastguard Worker try: 359*cda5da8dSAndroid Build Coastguard Worker fileno = file.fileno() 360*cda5da8dSAndroid Build Coastguard Worker except (AttributeError, io.UnsupportedOperation) as err: 361*cda5da8dSAndroid Build Coastguard Worker raise exceptions.SendfileNotAvailableError("not a regular file") 362*cda5da8dSAndroid Build Coastguard Worker try: 363*cda5da8dSAndroid Build Coastguard Worker fsize = os.fstat(fileno).st_size 364*cda5da8dSAndroid Build Coastguard Worker except OSError: 365*cda5da8dSAndroid Build Coastguard Worker raise exceptions.SendfileNotAvailableError("not a regular file") 366*cda5da8dSAndroid Build Coastguard Worker blocksize = count if count else fsize 367*cda5da8dSAndroid Build Coastguard Worker if not blocksize: 368*cda5da8dSAndroid Build Coastguard Worker return 0 # empty file 369*cda5da8dSAndroid Build Coastguard Worker 370*cda5da8dSAndroid Build Coastguard Worker fut = self.create_future() 371*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_native_impl(fut, None, sock, fileno, 372*cda5da8dSAndroid Build Coastguard Worker offset, count, blocksize, 0) 373*cda5da8dSAndroid Build Coastguard Worker return await fut 374*cda5da8dSAndroid Build Coastguard Worker 375*cda5da8dSAndroid Build Coastguard Worker def _sock_sendfile_native_impl(self, fut, registered_fd, sock, fileno, 376*cda5da8dSAndroid Build Coastguard Worker offset, count, blocksize, total_sent): 377*cda5da8dSAndroid Build Coastguard Worker fd = sock.fileno() 378*cda5da8dSAndroid Build Coastguard Worker if registered_fd is not None: 379*cda5da8dSAndroid Build Coastguard Worker # Remove the callback early. It should be rare that the 380*cda5da8dSAndroid Build Coastguard Worker # selector says the fd is ready but the call still returns 381*cda5da8dSAndroid Build Coastguard Worker # EAGAIN, and I am willing to take a hit in that case in 382*cda5da8dSAndroid Build Coastguard Worker # order to simplify the common case. 383*cda5da8dSAndroid Build Coastguard Worker self.remove_writer(registered_fd) 384*cda5da8dSAndroid Build Coastguard Worker if fut.cancelled(): 385*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_update_filepos(fileno, offset, total_sent) 386*cda5da8dSAndroid Build Coastguard Worker return 387*cda5da8dSAndroid Build Coastguard Worker if count: 388*cda5da8dSAndroid Build Coastguard Worker blocksize = count - total_sent 389*cda5da8dSAndroid Build Coastguard Worker if blocksize <= 0: 390*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_update_filepos(fileno, offset, total_sent) 391*cda5da8dSAndroid Build Coastguard Worker fut.set_result(total_sent) 392*cda5da8dSAndroid Build Coastguard Worker return 393*cda5da8dSAndroid Build Coastguard Worker 394*cda5da8dSAndroid Build Coastguard Worker try: 395*cda5da8dSAndroid Build Coastguard Worker sent = os.sendfile(fd, fileno, offset, blocksize) 396*cda5da8dSAndroid Build Coastguard Worker except (BlockingIOError, InterruptedError): 397*cda5da8dSAndroid Build Coastguard Worker if registered_fd is None: 398*cda5da8dSAndroid Build Coastguard Worker self._sock_add_cancellation_callback(fut, sock) 399*cda5da8dSAndroid Build Coastguard Worker self.add_writer(fd, self._sock_sendfile_native_impl, fut, 400*cda5da8dSAndroid Build Coastguard Worker fd, sock, fileno, 401*cda5da8dSAndroid Build Coastguard Worker offset, count, blocksize, total_sent) 402*cda5da8dSAndroid Build Coastguard Worker except OSError as exc: 403*cda5da8dSAndroid Build Coastguard Worker if (registered_fd is not None and 404*cda5da8dSAndroid Build Coastguard Worker exc.errno == errno.ENOTCONN and 405*cda5da8dSAndroid Build Coastguard Worker type(exc) is not ConnectionError): 406*cda5da8dSAndroid Build Coastguard Worker # If we have an ENOTCONN and this isn't a first call to 407*cda5da8dSAndroid Build Coastguard Worker # sendfile(), i.e. the connection was closed in the middle 408*cda5da8dSAndroid Build Coastguard Worker # of the operation, normalize the error to ConnectionError 409*cda5da8dSAndroid Build Coastguard Worker # to make it consistent across all Posix systems. 410*cda5da8dSAndroid Build Coastguard Worker new_exc = ConnectionError( 411*cda5da8dSAndroid Build Coastguard Worker "socket is not connected", errno.ENOTCONN) 412*cda5da8dSAndroid Build Coastguard Worker new_exc.__cause__ = exc 413*cda5da8dSAndroid Build Coastguard Worker exc = new_exc 414*cda5da8dSAndroid Build Coastguard Worker if total_sent == 0: 415*cda5da8dSAndroid Build Coastguard Worker # We can get here for different reasons, the main 416*cda5da8dSAndroid Build Coastguard Worker # one being 'file' is not a regular mmap(2)-like 417*cda5da8dSAndroid Build Coastguard Worker # file, in which case we'll fall back on using 418*cda5da8dSAndroid Build Coastguard Worker # plain send(). 419*cda5da8dSAndroid Build Coastguard Worker err = exceptions.SendfileNotAvailableError( 420*cda5da8dSAndroid Build Coastguard Worker "os.sendfile call failed") 421*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_update_filepos(fileno, offset, total_sent) 422*cda5da8dSAndroid Build Coastguard Worker fut.set_exception(err) 423*cda5da8dSAndroid Build Coastguard Worker else: 424*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_update_filepos(fileno, offset, total_sent) 425*cda5da8dSAndroid Build Coastguard Worker fut.set_exception(exc) 426*cda5da8dSAndroid Build Coastguard Worker except (SystemExit, KeyboardInterrupt): 427*cda5da8dSAndroid Build Coastguard Worker raise 428*cda5da8dSAndroid Build Coastguard Worker except BaseException as exc: 429*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_update_filepos(fileno, offset, total_sent) 430*cda5da8dSAndroid Build Coastguard Worker fut.set_exception(exc) 431*cda5da8dSAndroid Build Coastguard Worker else: 432*cda5da8dSAndroid Build Coastguard Worker if sent == 0: 433*cda5da8dSAndroid Build Coastguard Worker # EOF 434*cda5da8dSAndroid Build Coastguard Worker self._sock_sendfile_update_filepos(fileno, offset, total_sent) 435*cda5da8dSAndroid Build Coastguard Worker fut.set_result(total_sent) 436*cda5da8dSAndroid Build Coastguard Worker else: 437*cda5da8dSAndroid Build Coastguard Worker offset += sent 438*cda5da8dSAndroid Build Coastguard Worker total_sent += sent 439*cda5da8dSAndroid Build Coastguard Worker if registered_fd is None: 440*cda5da8dSAndroid Build Coastguard Worker self._sock_add_cancellation_callback(fut, sock) 441*cda5da8dSAndroid Build Coastguard Worker self.add_writer(fd, self._sock_sendfile_native_impl, fut, 442*cda5da8dSAndroid Build Coastguard Worker fd, sock, fileno, 443*cda5da8dSAndroid Build Coastguard Worker offset, count, blocksize, total_sent) 444*cda5da8dSAndroid Build Coastguard Worker 445*cda5da8dSAndroid Build Coastguard Worker def _sock_sendfile_update_filepos(self, fileno, offset, total_sent): 446*cda5da8dSAndroid Build Coastguard Worker if total_sent > 0: 447*cda5da8dSAndroid Build Coastguard Worker os.lseek(fileno, offset, os.SEEK_SET) 448*cda5da8dSAndroid Build Coastguard Worker 449*cda5da8dSAndroid Build Coastguard Worker def _sock_add_cancellation_callback(self, fut, sock): 450*cda5da8dSAndroid Build Coastguard Worker def cb(fut): 451*cda5da8dSAndroid Build Coastguard Worker if fut.cancelled(): 452*cda5da8dSAndroid Build Coastguard Worker fd = sock.fileno() 453*cda5da8dSAndroid Build Coastguard Worker if fd != -1: 454*cda5da8dSAndroid Build Coastguard Worker self.remove_writer(fd) 455*cda5da8dSAndroid Build Coastguard Worker fut.add_done_callback(cb) 456*cda5da8dSAndroid Build Coastguard Worker 457*cda5da8dSAndroid Build Coastguard Worker 458*cda5da8dSAndroid Build Coastguard Workerclass _UnixReadPipeTransport(transports.ReadTransport): 459*cda5da8dSAndroid Build Coastguard Worker 460*cda5da8dSAndroid Build Coastguard Worker max_size = 256 * 1024 # max bytes we read in one event loop iteration 461*cda5da8dSAndroid Build Coastguard Worker 462*cda5da8dSAndroid Build Coastguard Worker def __init__(self, loop, pipe, protocol, waiter=None, extra=None): 463*cda5da8dSAndroid Build Coastguard Worker super().__init__(extra) 464*cda5da8dSAndroid Build Coastguard Worker self._extra['pipe'] = pipe 465*cda5da8dSAndroid Build Coastguard Worker self._loop = loop 466*cda5da8dSAndroid Build Coastguard Worker self._pipe = pipe 467*cda5da8dSAndroid Build Coastguard Worker self._fileno = pipe.fileno() 468*cda5da8dSAndroid Build Coastguard Worker self._protocol = protocol 469*cda5da8dSAndroid Build Coastguard Worker self._closing = False 470*cda5da8dSAndroid Build Coastguard Worker self._paused = False 471*cda5da8dSAndroid Build Coastguard Worker 472*cda5da8dSAndroid Build Coastguard Worker mode = os.fstat(self._fileno).st_mode 473*cda5da8dSAndroid Build Coastguard Worker if not (stat.S_ISFIFO(mode) or 474*cda5da8dSAndroid Build Coastguard Worker stat.S_ISSOCK(mode) or 475*cda5da8dSAndroid Build Coastguard Worker stat.S_ISCHR(mode)): 476*cda5da8dSAndroid Build Coastguard Worker self._pipe = None 477*cda5da8dSAndroid Build Coastguard Worker self._fileno = None 478*cda5da8dSAndroid Build Coastguard Worker self._protocol = None 479*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Pipe transport is for pipes/sockets only.") 480*cda5da8dSAndroid Build Coastguard Worker 481*cda5da8dSAndroid Build Coastguard Worker os.set_blocking(self._fileno, False) 482*cda5da8dSAndroid Build Coastguard Worker 483*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._protocol.connection_made, self) 484*cda5da8dSAndroid Build Coastguard Worker # only start reading when connection_made() has been called 485*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._add_reader, 486*cda5da8dSAndroid Build Coastguard Worker self._fileno, self._read_ready) 487*cda5da8dSAndroid Build Coastguard Worker if waiter is not None: 488*cda5da8dSAndroid Build Coastguard Worker # only wake up the waiter when connection_made() has been called 489*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(futures._set_result_unless_cancelled, 490*cda5da8dSAndroid Build Coastguard Worker waiter, None) 491*cda5da8dSAndroid Build Coastguard Worker 492*cda5da8dSAndroid Build Coastguard Worker def _add_reader(self, fd, callback): 493*cda5da8dSAndroid Build Coastguard Worker if not self.is_reading(): 494*cda5da8dSAndroid Build Coastguard Worker return 495*cda5da8dSAndroid Build Coastguard Worker self._loop._add_reader(fd, callback) 496*cda5da8dSAndroid Build Coastguard Worker 497*cda5da8dSAndroid Build Coastguard Worker def is_reading(self): 498*cda5da8dSAndroid Build Coastguard Worker return not self._paused and not self._closing 499*cda5da8dSAndroid Build Coastguard Worker 500*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 501*cda5da8dSAndroid Build Coastguard Worker info = [self.__class__.__name__] 502*cda5da8dSAndroid Build Coastguard Worker if self._pipe is None: 503*cda5da8dSAndroid Build Coastguard Worker info.append('closed') 504*cda5da8dSAndroid Build Coastguard Worker elif self._closing: 505*cda5da8dSAndroid Build Coastguard Worker info.append('closing') 506*cda5da8dSAndroid Build Coastguard Worker info.append(f'fd={self._fileno}') 507*cda5da8dSAndroid Build Coastguard Worker selector = getattr(self._loop, '_selector', None) 508*cda5da8dSAndroid Build Coastguard Worker if self._pipe is not None and selector is not None: 509*cda5da8dSAndroid Build Coastguard Worker polling = selector_events._test_selector_event( 510*cda5da8dSAndroid Build Coastguard Worker selector, self._fileno, selectors.EVENT_READ) 511*cda5da8dSAndroid Build Coastguard Worker if polling: 512*cda5da8dSAndroid Build Coastguard Worker info.append('polling') 513*cda5da8dSAndroid Build Coastguard Worker else: 514*cda5da8dSAndroid Build Coastguard Worker info.append('idle') 515*cda5da8dSAndroid Build Coastguard Worker elif self._pipe is not None: 516*cda5da8dSAndroid Build Coastguard Worker info.append('open') 517*cda5da8dSAndroid Build Coastguard Worker else: 518*cda5da8dSAndroid Build Coastguard Worker info.append('closed') 519*cda5da8dSAndroid Build Coastguard Worker return '<{}>'.format(' '.join(info)) 520*cda5da8dSAndroid Build Coastguard Worker 521*cda5da8dSAndroid Build Coastguard Worker def _read_ready(self): 522*cda5da8dSAndroid Build Coastguard Worker try: 523*cda5da8dSAndroid Build Coastguard Worker data = os.read(self._fileno, self.max_size) 524*cda5da8dSAndroid Build Coastguard Worker except (BlockingIOError, InterruptedError): 525*cda5da8dSAndroid Build Coastguard Worker pass 526*cda5da8dSAndroid Build Coastguard Worker except OSError as exc: 527*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(exc, 'Fatal read error on pipe transport') 528*cda5da8dSAndroid Build Coastguard Worker else: 529*cda5da8dSAndroid Build Coastguard Worker if data: 530*cda5da8dSAndroid Build Coastguard Worker self._protocol.data_received(data) 531*cda5da8dSAndroid Build Coastguard Worker else: 532*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 533*cda5da8dSAndroid Build Coastguard Worker logger.info("%r was closed by peer", self) 534*cda5da8dSAndroid Build Coastguard Worker self._closing = True 535*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(self._fileno) 536*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._protocol.eof_received) 537*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._call_connection_lost, None) 538*cda5da8dSAndroid Build Coastguard Worker 539*cda5da8dSAndroid Build Coastguard Worker def pause_reading(self): 540*cda5da8dSAndroid Build Coastguard Worker if not self.is_reading(): 541*cda5da8dSAndroid Build Coastguard Worker return 542*cda5da8dSAndroid Build Coastguard Worker self._paused = True 543*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(self._fileno) 544*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 545*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r pauses reading", self) 546*cda5da8dSAndroid Build Coastguard Worker 547*cda5da8dSAndroid Build Coastguard Worker def resume_reading(self): 548*cda5da8dSAndroid Build Coastguard Worker if self._closing or not self._paused: 549*cda5da8dSAndroid Build Coastguard Worker return 550*cda5da8dSAndroid Build Coastguard Worker self._paused = False 551*cda5da8dSAndroid Build Coastguard Worker self._loop._add_reader(self._fileno, self._read_ready) 552*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 553*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r resumes reading", self) 554*cda5da8dSAndroid Build Coastguard Worker 555*cda5da8dSAndroid Build Coastguard Worker def set_protocol(self, protocol): 556*cda5da8dSAndroid Build Coastguard Worker self._protocol = protocol 557*cda5da8dSAndroid Build Coastguard Worker 558*cda5da8dSAndroid Build Coastguard Worker def get_protocol(self): 559*cda5da8dSAndroid Build Coastguard Worker return self._protocol 560*cda5da8dSAndroid Build Coastguard Worker 561*cda5da8dSAndroid Build Coastguard Worker def is_closing(self): 562*cda5da8dSAndroid Build Coastguard Worker return self._closing 563*cda5da8dSAndroid Build Coastguard Worker 564*cda5da8dSAndroid Build Coastguard Worker def close(self): 565*cda5da8dSAndroid Build Coastguard Worker if not self._closing: 566*cda5da8dSAndroid Build Coastguard Worker self._close(None) 567*cda5da8dSAndroid Build Coastguard Worker 568*cda5da8dSAndroid Build Coastguard Worker def __del__(self, _warn=warnings.warn): 569*cda5da8dSAndroid Build Coastguard Worker if self._pipe is not None: 570*cda5da8dSAndroid Build Coastguard Worker _warn(f"unclosed transport {self!r}", ResourceWarning, source=self) 571*cda5da8dSAndroid Build Coastguard Worker self._pipe.close() 572*cda5da8dSAndroid Build Coastguard Worker 573*cda5da8dSAndroid Build Coastguard Worker def _fatal_error(self, exc, message='Fatal error on pipe transport'): 574*cda5da8dSAndroid Build Coastguard Worker # should be called by exception handler only 575*cda5da8dSAndroid Build Coastguard Worker if (isinstance(exc, OSError) and exc.errno == errno.EIO): 576*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 577*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r: %s", self, message, exc_info=True) 578*cda5da8dSAndroid Build Coastguard Worker else: 579*cda5da8dSAndroid Build Coastguard Worker self._loop.call_exception_handler({ 580*cda5da8dSAndroid Build Coastguard Worker 'message': message, 581*cda5da8dSAndroid Build Coastguard Worker 'exception': exc, 582*cda5da8dSAndroid Build Coastguard Worker 'transport': self, 583*cda5da8dSAndroid Build Coastguard Worker 'protocol': self._protocol, 584*cda5da8dSAndroid Build Coastguard Worker }) 585*cda5da8dSAndroid Build Coastguard Worker self._close(exc) 586*cda5da8dSAndroid Build Coastguard Worker 587*cda5da8dSAndroid Build Coastguard Worker def _close(self, exc): 588*cda5da8dSAndroid Build Coastguard Worker self._closing = True 589*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(self._fileno) 590*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._call_connection_lost, exc) 591*cda5da8dSAndroid Build Coastguard Worker 592*cda5da8dSAndroid Build Coastguard Worker def _call_connection_lost(self, exc): 593*cda5da8dSAndroid Build Coastguard Worker try: 594*cda5da8dSAndroid Build Coastguard Worker self._protocol.connection_lost(exc) 595*cda5da8dSAndroid Build Coastguard Worker finally: 596*cda5da8dSAndroid Build Coastguard Worker self._pipe.close() 597*cda5da8dSAndroid Build Coastguard Worker self._pipe = None 598*cda5da8dSAndroid Build Coastguard Worker self._protocol = None 599*cda5da8dSAndroid Build Coastguard Worker self._loop = None 600*cda5da8dSAndroid Build Coastguard Worker 601*cda5da8dSAndroid Build Coastguard Worker 602*cda5da8dSAndroid Build Coastguard Workerclass _UnixWritePipeTransport(transports._FlowControlMixin, 603*cda5da8dSAndroid Build Coastguard Worker transports.WriteTransport): 604*cda5da8dSAndroid Build Coastguard Worker 605*cda5da8dSAndroid Build Coastguard Worker def __init__(self, loop, pipe, protocol, waiter=None, extra=None): 606*cda5da8dSAndroid Build Coastguard Worker super().__init__(extra, loop) 607*cda5da8dSAndroid Build Coastguard Worker self._extra['pipe'] = pipe 608*cda5da8dSAndroid Build Coastguard Worker self._pipe = pipe 609*cda5da8dSAndroid Build Coastguard Worker self._fileno = pipe.fileno() 610*cda5da8dSAndroid Build Coastguard Worker self._protocol = protocol 611*cda5da8dSAndroid Build Coastguard Worker self._buffer = bytearray() 612*cda5da8dSAndroid Build Coastguard Worker self._conn_lost = 0 613*cda5da8dSAndroid Build Coastguard Worker self._closing = False # Set when close() or write_eof() called. 614*cda5da8dSAndroid Build Coastguard Worker 615*cda5da8dSAndroid Build Coastguard Worker mode = os.fstat(self._fileno).st_mode 616*cda5da8dSAndroid Build Coastguard Worker is_char = stat.S_ISCHR(mode) 617*cda5da8dSAndroid Build Coastguard Worker is_fifo = stat.S_ISFIFO(mode) 618*cda5da8dSAndroid Build Coastguard Worker is_socket = stat.S_ISSOCK(mode) 619*cda5da8dSAndroid Build Coastguard Worker if not (is_char or is_fifo or is_socket): 620*cda5da8dSAndroid Build Coastguard Worker self._pipe = None 621*cda5da8dSAndroid Build Coastguard Worker self._fileno = None 622*cda5da8dSAndroid Build Coastguard Worker self._protocol = None 623*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Pipe transport is only for " 624*cda5da8dSAndroid Build Coastguard Worker "pipes, sockets and character devices") 625*cda5da8dSAndroid Build Coastguard Worker 626*cda5da8dSAndroid Build Coastguard Worker os.set_blocking(self._fileno, False) 627*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._protocol.connection_made, self) 628*cda5da8dSAndroid Build Coastguard Worker 629*cda5da8dSAndroid Build Coastguard Worker # On AIX, the reader trick (to be notified when the read end of the 630*cda5da8dSAndroid Build Coastguard Worker # socket is closed) only works for sockets. On other platforms it 631*cda5da8dSAndroid Build Coastguard Worker # works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.) 632*cda5da8dSAndroid Build Coastguard Worker if is_socket or (is_fifo and not sys.platform.startswith("aix")): 633*cda5da8dSAndroid Build Coastguard Worker # only start reading when connection_made() has been called 634*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._loop._add_reader, 635*cda5da8dSAndroid Build Coastguard Worker self._fileno, self._read_ready) 636*cda5da8dSAndroid Build Coastguard Worker 637*cda5da8dSAndroid Build Coastguard Worker if waiter is not None: 638*cda5da8dSAndroid Build Coastguard Worker # only wake up the waiter when connection_made() has been called 639*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(futures._set_result_unless_cancelled, 640*cda5da8dSAndroid Build Coastguard Worker waiter, None) 641*cda5da8dSAndroid Build Coastguard Worker 642*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 643*cda5da8dSAndroid Build Coastguard Worker info = [self.__class__.__name__] 644*cda5da8dSAndroid Build Coastguard Worker if self._pipe is None: 645*cda5da8dSAndroid Build Coastguard Worker info.append('closed') 646*cda5da8dSAndroid Build Coastguard Worker elif self._closing: 647*cda5da8dSAndroid Build Coastguard Worker info.append('closing') 648*cda5da8dSAndroid Build Coastguard Worker info.append(f'fd={self._fileno}') 649*cda5da8dSAndroid Build Coastguard Worker selector = getattr(self._loop, '_selector', None) 650*cda5da8dSAndroid Build Coastguard Worker if self._pipe is not None and selector is not None: 651*cda5da8dSAndroid Build Coastguard Worker polling = selector_events._test_selector_event( 652*cda5da8dSAndroid Build Coastguard Worker selector, self._fileno, selectors.EVENT_WRITE) 653*cda5da8dSAndroid Build Coastguard Worker if polling: 654*cda5da8dSAndroid Build Coastguard Worker info.append('polling') 655*cda5da8dSAndroid Build Coastguard Worker else: 656*cda5da8dSAndroid Build Coastguard Worker info.append('idle') 657*cda5da8dSAndroid Build Coastguard Worker 658*cda5da8dSAndroid Build Coastguard Worker bufsize = self.get_write_buffer_size() 659*cda5da8dSAndroid Build Coastguard Worker info.append(f'bufsize={bufsize}') 660*cda5da8dSAndroid Build Coastguard Worker elif self._pipe is not None: 661*cda5da8dSAndroid Build Coastguard Worker info.append('open') 662*cda5da8dSAndroid Build Coastguard Worker else: 663*cda5da8dSAndroid Build Coastguard Worker info.append('closed') 664*cda5da8dSAndroid Build Coastguard Worker return '<{}>'.format(' '.join(info)) 665*cda5da8dSAndroid Build Coastguard Worker 666*cda5da8dSAndroid Build Coastguard Worker def get_write_buffer_size(self): 667*cda5da8dSAndroid Build Coastguard Worker return len(self._buffer) 668*cda5da8dSAndroid Build Coastguard Worker 669*cda5da8dSAndroid Build Coastguard Worker def _read_ready(self): 670*cda5da8dSAndroid Build Coastguard Worker # Pipe was closed by peer. 671*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 672*cda5da8dSAndroid Build Coastguard Worker logger.info("%r was closed by peer", self) 673*cda5da8dSAndroid Build Coastguard Worker if self._buffer: 674*cda5da8dSAndroid Build Coastguard Worker self._close(BrokenPipeError()) 675*cda5da8dSAndroid Build Coastguard Worker else: 676*cda5da8dSAndroid Build Coastguard Worker self._close() 677*cda5da8dSAndroid Build Coastguard Worker 678*cda5da8dSAndroid Build Coastguard Worker def write(self, data): 679*cda5da8dSAndroid Build Coastguard Worker assert isinstance(data, (bytes, bytearray, memoryview)), repr(data) 680*cda5da8dSAndroid Build Coastguard Worker if isinstance(data, bytearray): 681*cda5da8dSAndroid Build Coastguard Worker data = memoryview(data) 682*cda5da8dSAndroid Build Coastguard Worker if not data: 683*cda5da8dSAndroid Build Coastguard Worker return 684*cda5da8dSAndroid Build Coastguard Worker 685*cda5da8dSAndroid Build Coastguard Worker if self._conn_lost or self._closing: 686*cda5da8dSAndroid Build Coastguard Worker if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES: 687*cda5da8dSAndroid Build Coastguard Worker logger.warning('pipe closed by peer or ' 688*cda5da8dSAndroid Build Coastguard Worker 'os.write(pipe, data) raised exception.') 689*cda5da8dSAndroid Build Coastguard Worker self._conn_lost += 1 690*cda5da8dSAndroid Build Coastguard Worker return 691*cda5da8dSAndroid Build Coastguard Worker 692*cda5da8dSAndroid Build Coastguard Worker if not self._buffer: 693*cda5da8dSAndroid Build Coastguard Worker # Attempt to send it right away first. 694*cda5da8dSAndroid Build Coastguard Worker try: 695*cda5da8dSAndroid Build Coastguard Worker n = os.write(self._fileno, data) 696*cda5da8dSAndroid Build Coastguard Worker except (BlockingIOError, InterruptedError): 697*cda5da8dSAndroid Build Coastguard Worker n = 0 698*cda5da8dSAndroid Build Coastguard Worker except (SystemExit, KeyboardInterrupt): 699*cda5da8dSAndroid Build Coastguard Worker raise 700*cda5da8dSAndroid Build Coastguard Worker except BaseException as exc: 701*cda5da8dSAndroid Build Coastguard Worker self._conn_lost += 1 702*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(exc, 'Fatal write error on pipe transport') 703*cda5da8dSAndroid Build Coastguard Worker return 704*cda5da8dSAndroid Build Coastguard Worker if n == len(data): 705*cda5da8dSAndroid Build Coastguard Worker return 706*cda5da8dSAndroid Build Coastguard Worker elif n > 0: 707*cda5da8dSAndroid Build Coastguard Worker data = memoryview(data)[n:] 708*cda5da8dSAndroid Build Coastguard Worker self._loop._add_writer(self._fileno, self._write_ready) 709*cda5da8dSAndroid Build Coastguard Worker 710*cda5da8dSAndroid Build Coastguard Worker self._buffer += data 711*cda5da8dSAndroid Build Coastguard Worker self._maybe_pause_protocol() 712*cda5da8dSAndroid Build Coastguard Worker 713*cda5da8dSAndroid Build Coastguard Worker def _write_ready(self): 714*cda5da8dSAndroid Build Coastguard Worker assert self._buffer, 'Data should not be empty' 715*cda5da8dSAndroid Build Coastguard Worker 716*cda5da8dSAndroid Build Coastguard Worker try: 717*cda5da8dSAndroid Build Coastguard Worker n = os.write(self._fileno, self._buffer) 718*cda5da8dSAndroid Build Coastguard Worker except (BlockingIOError, InterruptedError): 719*cda5da8dSAndroid Build Coastguard Worker pass 720*cda5da8dSAndroid Build Coastguard Worker except (SystemExit, KeyboardInterrupt): 721*cda5da8dSAndroid Build Coastguard Worker raise 722*cda5da8dSAndroid Build Coastguard Worker except BaseException as exc: 723*cda5da8dSAndroid Build Coastguard Worker self._buffer.clear() 724*cda5da8dSAndroid Build Coastguard Worker self._conn_lost += 1 725*cda5da8dSAndroid Build Coastguard Worker # Remove writer here, _fatal_error() doesn't it 726*cda5da8dSAndroid Build Coastguard Worker # because _buffer is empty. 727*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_writer(self._fileno) 728*cda5da8dSAndroid Build Coastguard Worker self._fatal_error(exc, 'Fatal write error on pipe transport') 729*cda5da8dSAndroid Build Coastguard Worker else: 730*cda5da8dSAndroid Build Coastguard Worker if n == len(self._buffer): 731*cda5da8dSAndroid Build Coastguard Worker self._buffer.clear() 732*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_writer(self._fileno) 733*cda5da8dSAndroid Build Coastguard Worker self._maybe_resume_protocol() # May append to buffer. 734*cda5da8dSAndroid Build Coastguard Worker if self._closing: 735*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(self._fileno) 736*cda5da8dSAndroid Build Coastguard Worker self._call_connection_lost(None) 737*cda5da8dSAndroid Build Coastguard Worker return 738*cda5da8dSAndroid Build Coastguard Worker elif n > 0: 739*cda5da8dSAndroid Build Coastguard Worker del self._buffer[:n] 740*cda5da8dSAndroid Build Coastguard Worker 741*cda5da8dSAndroid Build Coastguard Worker def can_write_eof(self): 742*cda5da8dSAndroid Build Coastguard Worker return True 743*cda5da8dSAndroid Build Coastguard Worker 744*cda5da8dSAndroid Build Coastguard Worker def write_eof(self): 745*cda5da8dSAndroid Build Coastguard Worker if self._closing: 746*cda5da8dSAndroid Build Coastguard Worker return 747*cda5da8dSAndroid Build Coastguard Worker assert self._pipe 748*cda5da8dSAndroid Build Coastguard Worker self._closing = True 749*cda5da8dSAndroid Build Coastguard Worker if not self._buffer: 750*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(self._fileno) 751*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._call_connection_lost, None) 752*cda5da8dSAndroid Build Coastguard Worker 753*cda5da8dSAndroid Build Coastguard Worker def set_protocol(self, protocol): 754*cda5da8dSAndroid Build Coastguard Worker self._protocol = protocol 755*cda5da8dSAndroid Build Coastguard Worker 756*cda5da8dSAndroid Build Coastguard Worker def get_protocol(self): 757*cda5da8dSAndroid Build Coastguard Worker return self._protocol 758*cda5da8dSAndroid Build Coastguard Worker 759*cda5da8dSAndroid Build Coastguard Worker def is_closing(self): 760*cda5da8dSAndroid Build Coastguard Worker return self._closing 761*cda5da8dSAndroid Build Coastguard Worker 762*cda5da8dSAndroid Build Coastguard Worker def close(self): 763*cda5da8dSAndroid Build Coastguard Worker if self._pipe is not None and not self._closing: 764*cda5da8dSAndroid Build Coastguard Worker # write_eof is all what we needed to close the write pipe 765*cda5da8dSAndroid Build Coastguard Worker self.write_eof() 766*cda5da8dSAndroid Build Coastguard Worker 767*cda5da8dSAndroid Build Coastguard Worker def __del__(self, _warn=warnings.warn): 768*cda5da8dSAndroid Build Coastguard Worker if self._pipe is not None: 769*cda5da8dSAndroid Build Coastguard Worker _warn(f"unclosed transport {self!r}", ResourceWarning, source=self) 770*cda5da8dSAndroid Build Coastguard Worker self._pipe.close() 771*cda5da8dSAndroid Build Coastguard Worker 772*cda5da8dSAndroid Build Coastguard Worker def abort(self): 773*cda5da8dSAndroid Build Coastguard Worker self._close(None) 774*cda5da8dSAndroid Build Coastguard Worker 775*cda5da8dSAndroid Build Coastguard Worker def _fatal_error(self, exc, message='Fatal error on pipe transport'): 776*cda5da8dSAndroid Build Coastguard Worker # should be called by exception handler only 777*cda5da8dSAndroid Build Coastguard Worker if isinstance(exc, OSError): 778*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 779*cda5da8dSAndroid Build Coastguard Worker logger.debug("%r: %s", self, message, exc_info=True) 780*cda5da8dSAndroid Build Coastguard Worker else: 781*cda5da8dSAndroid Build Coastguard Worker self._loop.call_exception_handler({ 782*cda5da8dSAndroid Build Coastguard Worker 'message': message, 783*cda5da8dSAndroid Build Coastguard Worker 'exception': exc, 784*cda5da8dSAndroid Build Coastguard Worker 'transport': self, 785*cda5da8dSAndroid Build Coastguard Worker 'protocol': self._protocol, 786*cda5da8dSAndroid Build Coastguard Worker }) 787*cda5da8dSAndroid Build Coastguard Worker self._close(exc) 788*cda5da8dSAndroid Build Coastguard Worker 789*cda5da8dSAndroid Build Coastguard Worker def _close(self, exc=None): 790*cda5da8dSAndroid Build Coastguard Worker self._closing = True 791*cda5da8dSAndroid Build Coastguard Worker if self._buffer: 792*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_writer(self._fileno) 793*cda5da8dSAndroid Build Coastguard Worker self._buffer.clear() 794*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(self._fileno) 795*cda5da8dSAndroid Build Coastguard Worker self._loop.call_soon(self._call_connection_lost, exc) 796*cda5da8dSAndroid Build Coastguard Worker 797*cda5da8dSAndroid Build Coastguard Worker def _call_connection_lost(self, exc): 798*cda5da8dSAndroid Build Coastguard Worker try: 799*cda5da8dSAndroid Build Coastguard Worker self._protocol.connection_lost(exc) 800*cda5da8dSAndroid Build Coastguard Worker finally: 801*cda5da8dSAndroid Build Coastguard Worker self._pipe.close() 802*cda5da8dSAndroid Build Coastguard Worker self._pipe = None 803*cda5da8dSAndroid Build Coastguard Worker self._protocol = None 804*cda5da8dSAndroid Build Coastguard Worker self._loop = None 805*cda5da8dSAndroid Build Coastguard Worker 806*cda5da8dSAndroid Build Coastguard Worker 807*cda5da8dSAndroid Build Coastguard Workerclass _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport): 808*cda5da8dSAndroid Build Coastguard Worker 809*cda5da8dSAndroid Build Coastguard Worker def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): 810*cda5da8dSAndroid Build Coastguard Worker stdin_w = None 811*cda5da8dSAndroid Build Coastguard Worker if stdin == subprocess.PIPE and sys.platform.startswith('aix'): 812*cda5da8dSAndroid Build Coastguard Worker # Use a socket pair for stdin on AIX, since it does not 813*cda5da8dSAndroid Build Coastguard Worker # support selecting read events on the write end of a 814*cda5da8dSAndroid Build Coastguard Worker # socket (which we use in order to detect closing of the 815*cda5da8dSAndroid Build Coastguard Worker # other end). 816*cda5da8dSAndroid Build Coastguard Worker stdin, stdin_w = socket.socketpair() 817*cda5da8dSAndroid Build Coastguard Worker try: 818*cda5da8dSAndroid Build Coastguard Worker self._proc = subprocess.Popen( 819*cda5da8dSAndroid Build Coastguard Worker args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr, 820*cda5da8dSAndroid Build Coastguard Worker universal_newlines=False, bufsize=bufsize, **kwargs) 821*cda5da8dSAndroid Build Coastguard Worker if stdin_w is not None: 822*cda5da8dSAndroid Build Coastguard Worker stdin.close() 823*cda5da8dSAndroid Build Coastguard Worker self._proc.stdin = open(stdin_w.detach(), 'wb', buffering=bufsize) 824*cda5da8dSAndroid Build Coastguard Worker stdin_w = None 825*cda5da8dSAndroid Build Coastguard Worker finally: 826*cda5da8dSAndroid Build Coastguard Worker if stdin_w is not None: 827*cda5da8dSAndroid Build Coastguard Worker stdin.close() 828*cda5da8dSAndroid Build Coastguard Worker stdin_w.close() 829*cda5da8dSAndroid Build Coastguard Worker 830*cda5da8dSAndroid Build Coastguard Worker 831*cda5da8dSAndroid Build Coastguard Workerclass AbstractChildWatcher: 832*cda5da8dSAndroid Build Coastguard Worker """Abstract base class for monitoring child processes. 833*cda5da8dSAndroid Build Coastguard Worker 834*cda5da8dSAndroid Build Coastguard Worker Objects derived from this class monitor a collection of subprocesses and 835*cda5da8dSAndroid Build Coastguard Worker report their termination or interruption by a signal. 836*cda5da8dSAndroid Build Coastguard Worker 837*cda5da8dSAndroid Build Coastguard Worker New callbacks are registered with .add_child_handler(). Starting a new 838*cda5da8dSAndroid Build Coastguard Worker process must be done within a 'with' block to allow the watcher to suspend 839*cda5da8dSAndroid Build Coastguard Worker its activity until the new process if fully registered (this is needed to 840*cda5da8dSAndroid Build Coastguard Worker prevent a race condition in some implementations). 841*cda5da8dSAndroid Build Coastguard Worker 842*cda5da8dSAndroid Build Coastguard Worker Example: 843*cda5da8dSAndroid Build Coastguard Worker with watcher: 844*cda5da8dSAndroid Build Coastguard Worker proc = subprocess.Popen("sleep 1") 845*cda5da8dSAndroid Build Coastguard Worker watcher.add_child_handler(proc.pid, callback) 846*cda5da8dSAndroid Build Coastguard Worker 847*cda5da8dSAndroid Build Coastguard Worker Notes: 848*cda5da8dSAndroid Build Coastguard Worker Implementations of this class must be thread-safe. 849*cda5da8dSAndroid Build Coastguard Worker 850*cda5da8dSAndroid Build Coastguard Worker Since child watcher objects may catch the SIGCHLD signal and call 851*cda5da8dSAndroid Build Coastguard Worker waitpid(-1), there should be only one active object per process. 852*cda5da8dSAndroid Build Coastguard Worker """ 853*cda5da8dSAndroid Build Coastguard Worker 854*cda5da8dSAndroid Build Coastguard Worker def add_child_handler(self, pid, callback, *args): 855*cda5da8dSAndroid Build Coastguard Worker """Register a new child handler. 856*cda5da8dSAndroid Build Coastguard Worker 857*cda5da8dSAndroid Build Coastguard Worker Arrange for callback(pid, returncode, *args) to be called when 858*cda5da8dSAndroid Build Coastguard Worker process 'pid' terminates. Specifying another callback for the same 859*cda5da8dSAndroid Build Coastguard Worker process replaces the previous handler. 860*cda5da8dSAndroid Build Coastguard Worker 861*cda5da8dSAndroid Build Coastguard Worker Note: callback() must be thread-safe. 862*cda5da8dSAndroid Build Coastguard Worker """ 863*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 864*cda5da8dSAndroid Build Coastguard Worker 865*cda5da8dSAndroid Build Coastguard Worker def remove_child_handler(self, pid): 866*cda5da8dSAndroid Build Coastguard Worker """Removes the handler for process 'pid'. 867*cda5da8dSAndroid Build Coastguard Worker 868*cda5da8dSAndroid Build Coastguard Worker The function returns True if the handler was successfully removed, 869*cda5da8dSAndroid Build Coastguard Worker False if there was nothing to remove.""" 870*cda5da8dSAndroid Build Coastguard Worker 871*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 872*cda5da8dSAndroid Build Coastguard Worker 873*cda5da8dSAndroid Build Coastguard Worker def attach_loop(self, loop): 874*cda5da8dSAndroid Build Coastguard Worker """Attach the watcher to an event loop. 875*cda5da8dSAndroid Build Coastguard Worker 876*cda5da8dSAndroid Build Coastguard Worker If the watcher was previously attached to an event loop, then it is 877*cda5da8dSAndroid Build Coastguard Worker first detached before attaching to the new loop. 878*cda5da8dSAndroid Build Coastguard Worker 879*cda5da8dSAndroid Build Coastguard Worker Note: loop may be None. 880*cda5da8dSAndroid Build Coastguard Worker """ 881*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 882*cda5da8dSAndroid Build Coastguard Worker 883*cda5da8dSAndroid Build Coastguard Worker def close(self): 884*cda5da8dSAndroid Build Coastguard Worker """Close the watcher. 885*cda5da8dSAndroid Build Coastguard Worker 886*cda5da8dSAndroid Build Coastguard Worker This must be called to make sure that any underlying resource is freed. 887*cda5da8dSAndroid Build Coastguard Worker """ 888*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 889*cda5da8dSAndroid Build Coastguard Worker 890*cda5da8dSAndroid Build Coastguard Worker def is_active(self): 891*cda5da8dSAndroid Build Coastguard Worker """Return ``True`` if the watcher is active and is used by the event loop. 892*cda5da8dSAndroid Build Coastguard Worker 893*cda5da8dSAndroid Build Coastguard Worker Return True if the watcher is installed and ready to handle process exit 894*cda5da8dSAndroid Build Coastguard Worker notifications. 895*cda5da8dSAndroid Build Coastguard Worker 896*cda5da8dSAndroid Build Coastguard Worker """ 897*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 898*cda5da8dSAndroid Build Coastguard Worker 899*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 900*cda5da8dSAndroid Build Coastguard Worker """Enter the watcher's context and allow starting new processes 901*cda5da8dSAndroid Build Coastguard Worker 902*cda5da8dSAndroid Build Coastguard Worker This function must return self""" 903*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 904*cda5da8dSAndroid Build Coastguard Worker 905*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, a, b, c): 906*cda5da8dSAndroid Build Coastguard Worker """Exit the watcher's context""" 907*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 908*cda5da8dSAndroid Build Coastguard Worker 909*cda5da8dSAndroid Build Coastguard Worker 910*cda5da8dSAndroid Build Coastguard Workerclass PidfdChildWatcher(AbstractChildWatcher): 911*cda5da8dSAndroid Build Coastguard Worker """Child watcher implementation using Linux's pid file descriptors. 912*cda5da8dSAndroid Build Coastguard Worker 913*cda5da8dSAndroid Build Coastguard Worker This child watcher polls process file descriptors (pidfds) to await child 914*cda5da8dSAndroid Build Coastguard Worker process termination. In some respects, PidfdChildWatcher is a "Goldilocks" 915*cda5da8dSAndroid Build Coastguard Worker child watcher implementation. It doesn't require signals or threads, doesn't 916*cda5da8dSAndroid Build Coastguard Worker interfere with any processes launched outside the event loop, and scales 917*cda5da8dSAndroid Build Coastguard Worker linearly with the number of subprocesses launched by the event loop. The 918*cda5da8dSAndroid Build Coastguard Worker main disadvantage is that pidfds are specific to Linux, and only work on 919*cda5da8dSAndroid Build Coastguard Worker recent (5.3+) kernels. 920*cda5da8dSAndroid Build Coastguard Worker """ 921*cda5da8dSAndroid Build Coastguard Worker 922*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 923*cda5da8dSAndroid Build Coastguard Worker self._loop = None 924*cda5da8dSAndroid Build Coastguard Worker self._callbacks = {} 925*cda5da8dSAndroid Build Coastguard Worker 926*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 927*cda5da8dSAndroid Build Coastguard Worker return self 928*cda5da8dSAndroid Build Coastguard Worker 929*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, exc_type, exc_value, exc_traceback): 930*cda5da8dSAndroid Build Coastguard Worker pass 931*cda5da8dSAndroid Build Coastguard Worker 932*cda5da8dSAndroid Build Coastguard Worker def is_active(self): 933*cda5da8dSAndroid Build Coastguard Worker return self._loop is not None and self._loop.is_running() 934*cda5da8dSAndroid Build Coastguard Worker 935*cda5da8dSAndroid Build Coastguard Worker def close(self): 936*cda5da8dSAndroid Build Coastguard Worker self.attach_loop(None) 937*cda5da8dSAndroid Build Coastguard Worker 938*cda5da8dSAndroid Build Coastguard Worker def attach_loop(self, loop): 939*cda5da8dSAndroid Build Coastguard Worker if self._loop is not None and loop is None and self._callbacks: 940*cda5da8dSAndroid Build Coastguard Worker warnings.warn( 941*cda5da8dSAndroid Build Coastguard Worker 'A loop is being detached ' 942*cda5da8dSAndroid Build Coastguard Worker 'from a child watcher with pending handlers', 943*cda5da8dSAndroid Build Coastguard Worker RuntimeWarning) 944*cda5da8dSAndroid Build Coastguard Worker for pidfd, _, _ in self._callbacks.values(): 945*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(pidfd) 946*cda5da8dSAndroid Build Coastguard Worker os.close(pidfd) 947*cda5da8dSAndroid Build Coastguard Worker self._callbacks.clear() 948*cda5da8dSAndroid Build Coastguard Worker self._loop = loop 949*cda5da8dSAndroid Build Coastguard Worker 950*cda5da8dSAndroid Build Coastguard Worker def add_child_handler(self, pid, callback, *args): 951*cda5da8dSAndroid Build Coastguard Worker existing = self._callbacks.get(pid) 952*cda5da8dSAndroid Build Coastguard Worker if existing is not None: 953*cda5da8dSAndroid Build Coastguard Worker self._callbacks[pid] = existing[0], callback, args 954*cda5da8dSAndroid Build Coastguard Worker else: 955*cda5da8dSAndroid Build Coastguard Worker pidfd = os.pidfd_open(pid) 956*cda5da8dSAndroid Build Coastguard Worker self._loop._add_reader(pidfd, self._do_wait, pid) 957*cda5da8dSAndroid Build Coastguard Worker self._callbacks[pid] = pidfd, callback, args 958*cda5da8dSAndroid Build Coastguard Worker 959*cda5da8dSAndroid Build Coastguard Worker def _do_wait(self, pid): 960*cda5da8dSAndroid Build Coastguard Worker pidfd, callback, args = self._callbacks.pop(pid) 961*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(pidfd) 962*cda5da8dSAndroid Build Coastguard Worker try: 963*cda5da8dSAndroid Build Coastguard Worker _, status = os.waitpid(pid, 0) 964*cda5da8dSAndroid Build Coastguard Worker except ChildProcessError: 965*cda5da8dSAndroid Build Coastguard Worker # The child process is already reaped 966*cda5da8dSAndroid Build Coastguard Worker # (may happen if waitpid() is called elsewhere). 967*cda5da8dSAndroid Build Coastguard Worker returncode = 255 968*cda5da8dSAndroid Build Coastguard Worker logger.warning( 969*cda5da8dSAndroid Build Coastguard Worker "child process pid %d exit status already read: " 970*cda5da8dSAndroid Build Coastguard Worker " will report returncode 255", 971*cda5da8dSAndroid Build Coastguard Worker pid) 972*cda5da8dSAndroid Build Coastguard Worker else: 973*cda5da8dSAndroid Build Coastguard Worker returncode = waitstatus_to_exitcode(status) 974*cda5da8dSAndroid Build Coastguard Worker 975*cda5da8dSAndroid Build Coastguard Worker os.close(pidfd) 976*cda5da8dSAndroid Build Coastguard Worker callback(pid, returncode, *args) 977*cda5da8dSAndroid Build Coastguard Worker 978*cda5da8dSAndroid Build Coastguard Worker def remove_child_handler(self, pid): 979*cda5da8dSAndroid Build Coastguard Worker try: 980*cda5da8dSAndroid Build Coastguard Worker pidfd, _, _ = self._callbacks.pop(pid) 981*cda5da8dSAndroid Build Coastguard Worker except KeyError: 982*cda5da8dSAndroid Build Coastguard Worker return False 983*cda5da8dSAndroid Build Coastguard Worker self._loop._remove_reader(pidfd) 984*cda5da8dSAndroid Build Coastguard Worker os.close(pidfd) 985*cda5da8dSAndroid Build Coastguard Worker return True 986*cda5da8dSAndroid Build Coastguard Worker 987*cda5da8dSAndroid Build Coastguard Worker 988*cda5da8dSAndroid Build Coastguard Workerclass BaseChildWatcher(AbstractChildWatcher): 989*cda5da8dSAndroid Build Coastguard Worker 990*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 991*cda5da8dSAndroid Build Coastguard Worker self._loop = None 992*cda5da8dSAndroid Build Coastguard Worker self._callbacks = {} 993*cda5da8dSAndroid Build Coastguard Worker 994*cda5da8dSAndroid Build Coastguard Worker def close(self): 995*cda5da8dSAndroid Build Coastguard Worker self.attach_loop(None) 996*cda5da8dSAndroid Build Coastguard Worker 997*cda5da8dSAndroid Build Coastguard Worker def is_active(self): 998*cda5da8dSAndroid Build Coastguard Worker return self._loop is not None and self._loop.is_running() 999*cda5da8dSAndroid Build Coastguard Worker 1000*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid(self, expected_pid): 1001*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 1002*cda5da8dSAndroid Build Coastguard Worker 1003*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid_all(self): 1004*cda5da8dSAndroid Build Coastguard Worker raise NotImplementedError() 1005*cda5da8dSAndroid Build Coastguard Worker 1006*cda5da8dSAndroid Build Coastguard Worker def attach_loop(self, loop): 1007*cda5da8dSAndroid Build Coastguard Worker assert loop is None or isinstance(loop, events.AbstractEventLoop) 1008*cda5da8dSAndroid Build Coastguard Worker 1009*cda5da8dSAndroid Build Coastguard Worker if self._loop is not None and loop is None and self._callbacks: 1010*cda5da8dSAndroid Build Coastguard Worker warnings.warn( 1011*cda5da8dSAndroid Build Coastguard Worker 'A loop is being detached ' 1012*cda5da8dSAndroid Build Coastguard Worker 'from a child watcher with pending handlers', 1013*cda5da8dSAndroid Build Coastguard Worker RuntimeWarning) 1014*cda5da8dSAndroid Build Coastguard Worker 1015*cda5da8dSAndroid Build Coastguard Worker if self._loop is not None: 1016*cda5da8dSAndroid Build Coastguard Worker self._loop.remove_signal_handler(signal.SIGCHLD) 1017*cda5da8dSAndroid Build Coastguard Worker 1018*cda5da8dSAndroid Build Coastguard Worker self._loop = loop 1019*cda5da8dSAndroid Build Coastguard Worker if loop is not None: 1020*cda5da8dSAndroid Build Coastguard Worker loop.add_signal_handler(signal.SIGCHLD, self._sig_chld) 1021*cda5da8dSAndroid Build Coastguard Worker 1022*cda5da8dSAndroid Build Coastguard Worker # Prevent a race condition in case a child terminated 1023*cda5da8dSAndroid Build Coastguard Worker # during the switch. 1024*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid_all() 1025*cda5da8dSAndroid Build Coastguard Worker 1026*cda5da8dSAndroid Build Coastguard Worker def _sig_chld(self): 1027*cda5da8dSAndroid Build Coastguard Worker try: 1028*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid_all() 1029*cda5da8dSAndroid Build Coastguard Worker except (SystemExit, KeyboardInterrupt): 1030*cda5da8dSAndroid Build Coastguard Worker raise 1031*cda5da8dSAndroid Build Coastguard Worker except BaseException as exc: 1032*cda5da8dSAndroid Build Coastguard Worker # self._loop should always be available here 1033*cda5da8dSAndroid Build Coastguard Worker # as '_sig_chld' is added as a signal handler 1034*cda5da8dSAndroid Build Coastguard Worker # in 'attach_loop' 1035*cda5da8dSAndroid Build Coastguard Worker self._loop.call_exception_handler({ 1036*cda5da8dSAndroid Build Coastguard Worker 'message': 'Unknown exception in SIGCHLD handler', 1037*cda5da8dSAndroid Build Coastguard Worker 'exception': exc, 1038*cda5da8dSAndroid Build Coastguard Worker }) 1039*cda5da8dSAndroid Build Coastguard Worker 1040*cda5da8dSAndroid Build Coastguard Worker 1041*cda5da8dSAndroid Build Coastguard Workerclass SafeChildWatcher(BaseChildWatcher): 1042*cda5da8dSAndroid Build Coastguard Worker """'Safe' child watcher implementation. 1043*cda5da8dSAndroid Build Coastguard Worker 1044*cda5da8dSAndroid Build Coastguard Worker This implementation avoids disrupting other code spawning processes by 1045*cda5da8dSAndroid Build Coastguard Worker polling explicitly each process in the SIGCHLD handler instead of calling 1046*cda5da8dSAndroid Build Coastguard Worker os.waitpid(-1). 1047*cda5da8dSAndroid Build Coastguard Worker 1048*cda5da8dSAndroid Build Coastguard Worker This is a safe solution but it has a significant overhead when handling a 1049*cda5da8dSAndroid Build Coastguard Worker big number of children (O(n) each time SIGCHLD is raised) 1050*cda5da8dSAndroid Build Coastguard Worker """ 1051*cda5da8dSAndroid Build Coastguard Worker 1052*cda5da8dSAndroid Build Coastguard Worker def close(self): 1053*cda5da8dSAndroid Build Coastguard Worker self._callbacks.clear() 1054*cda5da8dSAndroid Build Coastguard Worker super().close() 1055*cda5da8dSAndroid Build Coastguard Worker 1056*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 1057*cda5da8dSAndroid Build Coastguard Worker return self 1058*cda5da8dSAndroid Build Coastguard Worker 1059*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, a, b, c): 1060*cda5da8dSAndroid Build Coastguard Worker pass 1061*cda5da8dSAndroid Build Coastguard Worker 1062*cda5da8dSAndroid Build Coastguard Worker def add_child_handler(self, pid, callback, *args): 1063*cda5da8dSAndroid Build Coastguard Worker self._callbacks[pid] = (callback, args) 1064*cda5da8dSAndroid Build Coastguard Worker 1065*cda5da8dSAndroid Build Coastguard Worker # Prevent a race condition in case the child is already terminated. 1066*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid(pid) 1067*cda5da8dSAndroid Build Coastguard Worker 1068*cda5da8dSAndroid Build Coastguard Worker def remove_child_handler(self, pid): 1069*cda5da8dSAndroid Build Coastguard Worker try: 1070*cda5da8dSAndroid Build Coastguard Worker del self._callbacks[pid] 1071*cda5da8dSAndroid Build Coastguard Worker return True 1072*cda5da8dSAndroid Build Coastguard Worker except KeyError: 1073*cda5da8dSAndroid Build Coastguard Worker return False 1074*cda5da8dSAndroid Build Coastguard Worker 1075*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid_all(self): 1076*cda5da8dSAndroid Build Coastguard Worker 1077*cda5da8dSAndroid Build Coastguard Worker for pid in list(self._callbacks): 1078*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid(pid) 1079*cda5da8dSAndroid Build Coastguard Worker 1080*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid(self, expected_pid): 1081*cda5da8dSAndroid Build Coastguard Worker assert expected_pid > 0 1082*cda5da8dSAndroid Build Coastguard Worker 1083*cda5da8dSAndroid Build Coastguard Worker try: 1084*cda5da8dSAndroid Build Coastguard Worker pid, status = os.waitpid(expected_pid, os.WNOHANG) 1085*cda5da8dSAndroid Build Coastguard Worker except ChildProcessError: 1086*cda5da8dSAndroid Build Coastguard Worker # The child process is already reaped 1087*cda5da8dSAndroid Build Coastguard Worker # (may happen if waitpid() is called elsewhere). 1088*cda5da8dSAndroid Build Coastguard Worker pid = expected_pid 1089*cda5da8dSAndroid Build Coastguard Worker returncode = 255 1090*cda5da8dSAndroid Build Coastguard Worker logger.warning( 1091*cda5da8dSAndroid Build Coastguard Worker "Unknown child process pid %d, will report returncode 255", 1092*cda5da8dSAndroid Build Coastguard Worker pid) 1093*cda5da8dSAndroid Build Coastguard Worker else: 1094*cda5da8dSAndroid Build Coastguard Worker if pid == 0: 1095*cda5da8dSAndroid Build Coastguard Worker # The child process is still alive. 1096*cda5da8dSAndroid Build Coastguard Worker return 1097*cda5da8dSAndroid Build Coastguard Worker 1098*cda5da8dSAndroid Build Coastguard Worker returncode = waitstatus_to_exitcode(status) 1099*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 1100*cda5da8dSAndroid Build Coastguard Worker logger.debug('process %s exited with returncode %s', 1101*cda5da8dSAndroid Build Coastguard Worker expected_pid, returncode) 1102*cda5da8dSAndroid Build Coastguard Worker 1103*cda5da8dSAndroid Build Coastguard Worker try: 1104*cda5da8dSAndroid Build Coastguard Worker callback, args = self._callbacks.pop(pid) 1105*cda5da8dSAndroid Build Coastguard Worker except KeyError: # pragma: no cover 1106*cda5da8dSAndroid Build Coastguard Worker # May happen if .remove_child_handler() is called 1107*cda5da8dSAndroid Build Coastguard Worker # after os.waitpid() returns. 1108*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 1109*cda5da8dSAndroid Build Coastguard Worker logger.warning("Child watcher got an unexpected pid: %r", 1110*cda5da8dSAndroid Build Coastguard Worker pid, exc_info=True) 1111*cda5da8dSAndroid Build Coastguard Worker else: 1112*cda5da8dSAndroid Build Coastguard Worker callback(pid, returncode, *args) 1113*cda5da8dSAndroid Build Coastguard Worker 1114*cda5da8dSAndroid Build Coastguard Worker 1115*cda5da8dSAndroid Build Coastguard Workerclass FastChildWatcher(BaseChildWatcher): 1116*cda5da8dSAndroid Build Coastguard Worker """'Fast' child watcher implementation. 1117*cda5da8dSAndroid Build Coastguard Worker 1118*cda5da8dSAndroid Build Coastguard Worker This implementation reaps every terminated processes by calling 1119*cda5da8dSAndroid Build Coastguard Worker os.waitpid(-1) directly, possibly breaking other code spawning processes 1120*cda5da8dSAndroid Build Coastguard Worker and waiting for their termination. 1121*cda5da8dSAndroid Build Coastguard Worker 1122*cda5da8dSAndroid Build Coastguard Worker There is no noticeable overhead when handling a big number of children 1123*cda5da8dSAndroid Build Coastguard Worker (O(1) each time a child terminates). 1124*cda5da8dSAndroid Build Coastguard Worker """ 1125*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 1126*cda5da8dSAndroid Build Coastguard Worker super().__init__() 1127*cda5da8dSAndroid Build Coastguard Worker self._lock = threading.Lock() 1128*cda5da8dSAndroid Build Coastguard Worker self._zombies = {} 1129*cda5da8dSAndroid Build Coastguard Worker self._forks = 0 1130*cda5da8dSAndroid Build Coastguard Worker 1131*cda5da8dSAndroid Build Coastguard Worker def close(self): 1132*cda5da8dSAndroid Build Coastguard Worker self._callbacks.clear() 1133*cda5da8dSAndroid Build Coastguard Worker self._zombies.clear() 1134*cda5da8dSAndroid Build Coastguard Worker super().close() 1135*cda5da8dSAndroid Build Coastguard Worker 1136*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 1137*cda5da8dSAndroid Build Coastguard Worker with self._lock: 1138*cda5da8dSAndroid Build Coastguard Worker self._forks += 1 1139*cda5da8dSAndroid Build Coastguard Worker 1140*cda5da8dSAndroid Build Coastguard Worker return self 1141*cda5da8dSAndroid Build Coastguard Worker 1142*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, a, b, c): 1143*cda5da8dSAndroid Build Coastguard Worker with self._lock: 1144*cda5da8dSAndroid Build Coastguard Worker self._forks -= 1 1145*cda5da8dSAndroid Build Coastguard Worker 1146*cda5da8dSAndroid Build Coastguard Worker if self._forks or not self._zombies: 1147*cda5da8dSAndroid Build Coastguard Worker return 1148*cda5da8dSAndroid Build Coastguard Worker 1149*cda5da8dSAndroid Build Coastguard Worker collateral_victims = str(self._zombies) 1150*cda5da8dSAndroid Build Coastguard Worker self._zombies.clear() 1151*cda5da8dSAndroid Build Coastguard Worker 1152*cda5da8dSAndroid Build Coastguard Worker logger.warning( 1153*cda5da8dSAndroid Build Coastguard Worker "Caught subprocesses termination from unknown pids: %s", 1154*cda5da8dSAndroid Build Coastguard Worker collateral_victims) 1155*cda5da8dSAndroid Build Coastguard Worker 1156*cda5da8dSAndroid Build Coastguard Worker def add_child_handler(self, pid, callback, *args): 1157*cda5da8dSAndroid Build Coastguard Worker assert self._forks, "Must use the context manager" 1158*cda5da8dSAndroid Build Coastguard Worker 1159*cda5da8dSAndroid Build Coastguard Worker with self._lock: 1160*cda5da8dSAndroid Build Coastguard Worker try: 1161*cda5da8dSAndroid Build Coastguard Worker returncode = self._zombies.pop(pid) 1162*cda5da8dSAndroid Build Coastguard Worker except KeyError: 1163*cda5da8dSAndroid Build Coastguard Worker # The child is running. 1164*cda5da8dSAndroid Build Coastguard Worker self._callbacks[pid] = callback, args 1165*cda5da8dSAndroid Build Coastguard Worker return 1166*cda5da8dSAndroid Build Coastguard Worker 1167*cda5da8dSAndroid Build Coastguard Worker # The child is dead already. We can fire the callback. 1168*cda5da8dSAndroid Build Coastguard Worker callback(pid, returncode, *args) 1169*cda5da8dSAndroid Build Coastguard Worker 1170*cda5da8dSAndroid Build Coastguard Worker def remove_child_handler(self, pid): 1171*cda5da8dSAndroid Build Coastguard Worker try: 1172*cda5da8dSAndroid Build Coastguard Worker del self._callbacks[pid] 1173*cda5da8dSAndroid Build Coastguard Worker return True 1174*cda5da8dSAndroid Build Coastguard Worker except KeyError: 1175*cda5da8dSAndroid Build Coastguard Worker return False 1176*cda5da8dSAndroid Build Coastguard Worker 1177*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid_all(self): 1178*cda5da8dSAndroid Build Coastguard Worker # Because of signal coalescing, we must keep calling waitpid() as 1179*cda5da8dSAndroid Build Coastguard Worker # long as we're able to reap a child. 1180*cda5da8dSAndroid Build Coastguard Worker while True: 1181*cda5da8dSAndroid Build Coastguard Worker try: 1182*cda5da8dSAndroid Build Coastguard Worker pid, status = os.waitpid(-1, os.WNOHANG) 1183*cda5da8dSAndroid Build Coastguard Worker except ChildProcessError: 1184*cda5da8dSAndroid Build Coastguard Worker # No more child processes exist. 1185*cda5da8dSAndroid Build Coastguard Worker return 1186*cda5da8dSAndroid Build Coastguard Worker else: 1187*cda5da8dSAndroid Build Coastguard Worker if pid == 0: 1188*cda5da8dSAndroid Build Coastguard Worker # A child process is still alive. 1189*cda5da8dSAndroid Build Coastguard Worker return 1190*cda5da8dSAndroid Build Coastguard Worker 1191*cda5da8dSAndroid Build Coastguard Worker returncode = waitstatus_to_exitcode(status) 1192*cda5da8dSAndroid Build Coastguard Worker 1193*cda5da8dSAndroid Build Coastguard Worker with self._lock: 1194*cda5da8dSAndroid Build Coastguard Worker try: 1195*cda5da8dSAndroid Build Coastguard Worker callback, args = self._callbacks.pop(pid) 1196*cda5da8dSAndroid Build Coastguard Worker except KeyError: 1197*cda5da8dSAndroid Build Coastguard Worker # unknown child 1198*cda5da8dSAndroid Build Coastguard Worker if self._forks: 1199*cda5da8dSAndroid Build Coastguard Worker # It may not be registered yet. 1200*cda5da8dSAndroid Build Coastguard Worker self._zombies[pid] = returncode 1201*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 1202*cda5da8dSAndroid Build Coastguard Worker logger.debug('unknown process %s exited ' 1203*cda5da8dSAndroid Build Coastguard Worker 'with returncode %s', 1204*cda5da8dSAndroid Build Coastguard Worker pid, returncode) 1205*cda5da8dSAndroid Build Coastguard Worker continue 1206*cda5da8dSAndroid Build Coastguard Worker callback = None 1207*cda5da8dSAndroid Build Coastguard Worker else: 1208*cda5da8dSAndroid Build Coastguard Worker if self._loop.get_debug(): 1209*cda5da8dSAndroid Build Coastguard Worker logger.debug('process %s exited with returncode %s', 1210*cda5da8dSAndroid Build Coastguard Worker pid, returncode) 1211*cda5da8dSAndroid Build Coastguard Worker 1212*cda5da8dSAndroid Build Coastguard Worker if callback is None: 1213*cda5da8dSAndroid Build Coastguard Worker logger.warning( 1214*cda5da8dSAndroid Build Coastguard Worker "Caught subprocess termination from unknown pid: " 1215*cda5da8dSAndroid Build Coastguard Worker "%d -> %d", pid, returncode) 1216*cda5da8dSAndroid Build Coastguard Worker else: 1217*cda5da8dSAndroid Build Coastguard Worker callback(pid, returncode, *args) 1218*cda5da8dSAndroid Build Coastguard Worker 1219*cda5da8dSAndroid Build Coastguard Worker 1220*cda5da8dSAndroid Build Coastguard Workerclass MultiLoopChildWatcher(AbstractChildWatcher): 1221*cda5da8dSAndroid Build Coastguard Worker """A watcher that doesn't require running loop in the main thread. 1222*cda5da8dSAndroid Build Coastguard Worker 1223*cda5da8dSAndroid Build Coastguard Worker This implementation registers a SIGCHLD signal handler on 1224*cda5da8dSAndroid Build Coastguard Worker instantiation (which may conflict with other code that 1225*cda5da8dSAndroid Build Coastguard Worker install own handler for this signal). 1226*cda5da8dSAndroid Build Coastguard Worker 1227*cda5da8dSAndroid Build Coastguard Worker The solution is safe but it has a significant overhead when 1228*cda5da8dSAndroid Build Coastguard Worker handling a big number of processes (*O(n)* each time a 1229*cda5da8dSAndroid Build Coastguard Worker SIGCHLD is received). 1230*cda5da8dSAndroid Build Coastguard Worker """ 1231*cda5da8dSAndroid Build Coastguard Worker 1232*cda5da8dSAndroid Build Coastguard Worker # Implementation note: 1233*cda5da8dSAndroid Build Coastguard Worker # The class keeps compatibility with AbstractChildWatcher ABC 1234*cda5da8dSAndroid Build Coastguard Worker # To achieve this it has empty attach_loop() method 1235*cda5da8dSAndroid Build Coastguard Worker # and doesn't accept explicit loop argument 1236*cda5da8dSAndroid Build Coastguard Worker # for add_child_handler()/remove_child_handler() 1237*cda5da8dSAndroid Build Coastguard Worker # but retrieves the current loop by get_running_loop() 1238*cda5da8dSAndroid Build Coastguard Worker 1239*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 1240*cda5da8dSAndroid Build Coastguard Worker self._callbacks = {} 1241*cda5da8dSAndroid Build Coastguard Worker self._saved_sighandler = None 1242*cda5da8dSAndroid Build Coastguard Worker 1243*cda5da8dSAndroid Build Coastguard Worker def is_active(self): 1244*cda5da8dSAndroid Build Coastguard Worker return self._saved_sighandler is not None 1245*cda5da8dSAndroid Build Coastguard Worker 1246*cda5da8dSAndroid Build Coastguard Worker def close(self): 1247*cda5da8dSAndroid Build Coastguard Worker self._callbacks.clear() 1248*cda5da8dSAndroid Build Coastguard Worker if self._saved_sighandler is None: 1249*cda5da8dSAndroid Build Coastguard Worker return 1250*cda5da8dSAndroid Build Coastguard Worker 1251*cda5da8dSAndroid Build Coastguard Worker handler = signal.getsignal(signal.SIGCHLD) 1252*cda5da8dSAndroid Build Coastguard Worker if handler != self._sig_chld: 1253*cda5da8dSAndroid Build Coastguard Worker logger.warning("SIGCHLD handler was changed by outside code") 1254*cda5da8dSAndroid Build Coastguard Worker else: 1255*cda5da8dSAndroid Build Coastguard Worker signal.signal(signal.SIGCHLD, self._saved_sighandler) 1256*cda5da8dSAndroid Build Coastguard Worker self._saved_sighandler = None 1257*cda5da8dSAndroid Build Coastguard Worker 1258*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 1259*cda5da8dSAndroid Build Coastguard Worker return self 1260*cda5da8dSAndroid Build Coastguard Worker 1261*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, exc_type, exc_val, exc_tb): 1262*cda5da8dSAndroid Build Coastguard Worker pass 1263*cda5da8dSAndroid Build Coastguard Worker 1264*cda5da8dSAndroid Build Coastguard Worker def add_child_handler(self, pid, callback, *args): 1265*cda5da8dSAndroid Build Coastguard Worker loop = events.get_running_loop() 1266*cda5da8dSAndroid Build Coastguard Worker self._callbacks[pid] = (loop, callback, args) 1267*cda5da8dSAndroid Build Coastguard Worker 1268*cda5da8dSAndroid Build Coastguard Worker # Prevent a race condition in case the child is already terminated. 1269*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid(pid) 1270*cda5da8dSAndroid Build Coastguard Worker 1271*cda5da8dSAndroid Build Coastguard Worker def remove_child_handler(self, pid): 1272*cda5da8dSAndroid Build Coastguard Worker try: 1273*cda5da8dSAndroid Build Coastguard Worker del self._callbacks[pid] 1274*cda5da8dSAndroid Build Coastguard Worker return True 1275*cda5da8dSAndroid Build Coastguard Worker except KeyError: 1276*cda5da8dSAndroid Build Coastguard Worker return False 1277*cda5da8dSAndroid Build Coastguard Worker 1278*cda5da8dSAndroid Build Coastguard Worker def attach_loop(self, loop): 1279*cda5da8dSAndroid Build Coastguard Worker # Don't save the loop but initialize itself if called first time 1280*cda5da8dSAndroid Build Coastguard Worker # The reason to do it here is that attach_loop() is called from 1281*cda5da8dSAndroid Build Coastguard Worker # unix policy only for the main thread. 1282*cda5da8dSAndroid Build Coastguard Worker # Main thread is required for subscription on SIGCHLD signal 1283*cda5da8dSAndroid Build Coastguard Worker if self._saved_sighandler is not None: 1284*cda5da8dSAndroid Build Coastguard Worker return 1285*cda5da8dSAndroid Build Coastguard Worker 1286*cda5da8dSAndroid Build Coastguard Worker self._saved_sighandler = signal.signal(signal.SIGCHLD, self._sig_chld) 1287*cda5da8dSAndroid Build Coastguard Worker if self._saved_sighandler is None: 1288*cda5da8dSAndroid Build Coastguard Worker logger.warning("Previous SIGCHLD handler was set by non-Python code, " 1289*cda5da8dSAndroid Build Coastguard Worker "restore to default handler on watcher close.") 1290*cda5da8dSAndroid Build Coastguard Worker self._saved_sighandler = signal.SIG_DFL 1291*cda5da8dSAndroid Build Coastguard Worker 1292*cda5da8dSAndroid Build Coastguard Worker # Set SA_RESTART to limit EINTR occurrences. 1293*cda5da8dSAndroid Build Coastguard Worker signal.siginterrupt(signal.SIGCHLD, False) 1294*cda5da8dSAndroid Build Coastguard Worker 1295*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid_all(self): 1296*cda5da8dSAndroid Build Coastguard Worker for pid in list(self._callbacks): 1297*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid(pid) 1298*cda5da8dSAndroid Build Coastguard Worker 1299*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid(self, expected_pid): 1300*cda5da8dSAndroid Build Coastguard Worker assert expected_pid > 0 1301*cda5da8dSAndroid Build Coastguard Worker 1302*cda5da8dSAndroid Build Coastguard Worker try: 1303*cda5da8dSAndroid Build Coastguard Worker pid, status = os.waitpid(expected_pid, os.WNOHANG) 1304*cda5da8dSAndroid Build Coastguard Worker except ChildProcessError: 1305*cda5da8dSAndroid Build Coastguard Worker # The child process is already reaped 1306*cda5da8dSAndroid Build Coastguard Worker # (may happen if waitpid() is called elsewhere). 1307*cda5da8dSAndroid Build Coastguard Worker pid = expected_pid 1308*cda5da8dSAndroid Build Coastguard Worker returncode = 255 1309*cda5da8dSAndroid Build Coastguard Worker logger.warning( 1310*cda5da8dSAndroid Build Coastguard Worker "Unknown child process pid %d, will report returncode 255", 1311*cda5da8dSAndroid Build Coastguard Worker pid) 1312*cda5da8dSAndroid Build Coastguard Worker debug_log = False 1313*cda5da8dSAndroid Build Coastguard Worker else: 1314*cda5da8dSAndroid Build Coastguard Worker if pid == 0: 1315*cda5da8dSAndroid Build Coastguard Worker # The child process is still alive. 1316*cda5da8dSAndroid Build Coastguard Worker return 1317*cda5da8dSAndroid Build Coastguard Worker 1318*cda5da8dSAndroid Build Coastguard Worker returncode = waitstatus_to_exitcode(status) 1319*cda5da8dSAndroid Build Coastguard Worker debug_log = True 1320*cda5da8dSAndroid Build Coastguard Worker try: 1321*cda5da8dSAndroid Build Coastguard Worker loop, callback, args = self._callbacks.pop(pid) 1322*cda5da8dSAndroid Build Coastguard Worker except KeyError: # pragma: no cover 1323*cda5da8dSAndroid Build Coastguard Worker # May happen if .remove_child_handler() is called 1324*cda5da8dSAndroid Build Coastguard Worker # after os.waitpid() returns. 1325*cda5da8dSAndroid Build Coastguard Worker logger.warning("Child watcher got an unexpected pid: %r", 1326*cda5da8dSAndroid Build Coastguard Worker pid, exc_info=True) 1327*cda5da8dSAndroid Build Coastguard Worker else: 1328*cda5da8dSAndroid Build Coastguard Worker if loop.is_closed(): 1329*cda5da8dSAndroid Build Coastguard Worker logger.warning("Loop %r that handles pid %r is closed", loop, pid) 1330*cda5da8dSAndroid Build Coastguard Worker else: 1331*cda5da8dSAndroid Build Coastguard Worker if debug_log and loop.get_debug(): 1332*cda5da8dSAndroid Build Coastguard Worker logger.debug('process %s exited with returncode %s', 1333*cda5da8dSAndroid Build Coastguard Worker expected_pid, returncode) 1334*cda5da8dSAndroid Build Coastguard Worker loop.call_soon_threadsafe(callback, pid, returncode, *args) 1335*cda5da8dSAndroid Build Coastguard Worker 1336*cda5da8dSAndroid Build Coastguard Worker def _sig_chld(self, signum, frame): 1337*cda5da8dSAndroid Build Coastguard Worker try: 1338*cda5da8dSAndroid Build Coastguard Worker self._do_waitpid_all() 1339*cda5da8dSAndroid Build Coastguard Worker except (SystemExit, KeyboardInterrupt): 1340*cda5da8dSAndroid Build Coastguard Worker raise 1341*cda5da8dSAndroid Build Coastguard Worker except BaseException: 1342*cda5da8dSAndroid Build Coastguard Worker logger.warning('Unknown exception in SIGCHLD handler', exc_info=True) 1343*cda5da8dSAndroid Build Coastguard Worker 1344*cda5da8dSAndroid Build Coastguard Worker 1345*cda5da8dSAndroid Build Coastguard Workerclass ThreadedChildWatcher(AbstractChildWatcher): 1346*cda5da8dSAndroid Build Coastguard Worker """Threaded child watcher implementation. 1347*cda5da8dSAndroid Build Coastguard Worker 1348*cda5da8dSAndroid Build Coastguard Worker The watcher uses a thread per process 1349*cda5da8dSAndroid Build Coastguard Worker for waiting for the process finish. 1350*cda5da8dSAndroid Build Coastguard Worker 1351*cda5da8dSAndroid Build Coastguard Worker It doesn't require subscription on POSIX signal 1352*cda5da8dSAndroid Build Coastguard Worker but a thread creation is not free. 1353*cda5da8dSAndroid Build Coastguard Worker 1354*cda5da8dSAndroid Build Coastguard Worker The watcher has O(1) complexity, its performance doesn't depend 1355*cda5da8dSAndroid Build Coastguard Worker on amount of spawn processes. 1356*cda5da8dSAndroid Build Coastguard Worker """ 1357*cda5da8dSAndroid Build Coastguard Worker 1358*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 1359*cda5da8dSAndroid Build Coastguard Worker self._pid_counter = itertools.count(0) 1360*cda5da8dSAndroid Build Coastguard Worker self._threads = {} 1361*cda5da8dSAndroid Build Coastguard Worker 1362*cda5da8dSAndroid Build Coastguard Worker def is_active(self): 1363*cda5da8dSAndroid Build Coastguard Worker return True 1364*cda5da8dSAndroid Build Coastguard Worker 1365*cda5da8dSAndroid Build Coastguard Worker def close(self): 1366*cda5da8dSAndroid Build Coastguard Worker self._join_threads() 1367*cda5da8dSAndroid Build Coastguard Worker 1368*cda5da8dSAndroid Build Coastguard Worker def _join_threads(self): 1369*cda5da8dSAndroid Build Coastguard Worker """Internal: Join all non-daemon threads""" 1370*cda5da8dSAndroid Build Coastguard Worker threads = [thread for thread in list(self._threads.values()) 1371*cda5da8dSAndroid Build Coastguard Worker if thread.is_alive() and not thread.daemon] 1372*cda5da8dSAndroid Build Coastguard Worker for thread in threads: 1373*cda5da8dSAndroid Build Coastguard Worker thread.join() 1374*cda5da8dSAndroid Build Coastguard Worker 1375*cda5da8dSAndroid Build Coastguard Worker def __enter__(self): 1376*cda5da8dSAndroid Build Coastguard Worker return self 1377*cda5da8dSAndroid Build Coastguard Worker 1378*cda5da8dSAndroid Build Coastguard Worker def __exit__(self, exc_type, exc_val, exc_tb): 1379*cda5da8dSAndroid Build Coastguard Worker pass 1380*cda5da8dSAndroid Build Coastguard Worker 1381*cda5da8dSAndroid Build Coastguard Worker def __del__(self, _warn=warnings.warn): 1382*cda5da8dSAndroid Build Coastguard Worker threads = [thread for thread in list(self._threads.values()) 1383*cda5da8dSAndroid Build Coastguard Worker if thread.is_alive()] 1384*cda5da8dSAndroid Build Coastguard Worker if threads: 1385*cda5da8dSAndroid Build Coastguard Worker _warn(f"{self.__class__} has registered but not finished child processes", 1386*cda5da8dSAndroid Build Coastguard Worker ResourceWarning, 1387*cda5da8dSAndroid Build Coastguard Worker source=self) 1388*cda5da8dSAndroid Build Coastguard Worker 1389*cda5da8dSAndroid Build Coastguard Worker def add_child_handler(self, pid, callback, *args): 1390*cda5da8dSAndroid Build Coastguard Worker loop = events.get_running_loop() 1391*cda5da8dSAndroid Build Coastguard Worker thread = threading.Thread(target=self._do_waitpid, 1392*cda5da8dSAndroid Build Coastguard Worker name=f"waitpid-{next(self._pid_counter)}", 1393*cda5da8dSAndroid Build Coastguard Worker args=(loop, pid, callback, args), 1394*cda5da8dSAndroid Build Coastguard Worker daemon=True) 1395*cda5da8dSAndroid Build Coastguard Worker self._threads[pid] = thread 1396*cda5da8dSAndroid Build Coastguard Worker thread.start() 1397*cda5da8dSAndroid Build Coastguard Worker 1398*cda5da8dSAndroid Build Coastguard Worker def remove_child_handler(self, pid): 1399*cda5da8dSAndroid Build Coastguard Worker # asyncio never calls remove_child_handler() !!! 1400*cda5da8dSAndroid Build Coastguard Worker # The method is no-op but is implemented because 1401*cda5da8dSAndroid Build Coastguard Worker # abstract base classes require it. 1402*cda5da8dSAndroid Build Coastguard Worker return True 1403*cda5da8dSAndroid Build Coastguard Worker 1404*cda5da8dSAndroid Build Coastguard Worker def attach_loop(self, loop): 1405*cda5da8dSAndroid Build Coastguard Worker pass 1406*cda5da8dSAndroid Build Coastguard Worker 1407*cda5da8dSAndroid Build Coastguard Worker def _do_waitpid(self, loop, expected_pid, callback, args): 1408*cda5da8dSAndroid Build Coastguard Worker assert expected_pid > 0 1409*cda5da8dSAndroid Build Coastguard Worker 1410*cda5da8dSAndroid Build Coastguard Worker try: 1411*cda5da8dSAndroid Build Coastguard Worker pid, status = os.waitpid(expected_pid, 0) 1412*cda5da8dSAndroid Build Coastguard Worker except ChildProcessError: 1413*cda5da8dSAndroid Build Coastguard Worker # The child process is already reaped 1414*cda5da8dSAndroid Build Coastguard Worker # (may happen if waitpid() is called elsewhere). 1415*cda5da8dSAndroid Build Coastguard Worker pid = expected_pid 1416*cda5da8dSAndroid Build Coastguard Worker returncode = 255 1417*cda5da8dSAndroid Build Coastguard Worker logger.warning( 1418*cda5da8dSAndroid Build Coastguard Worker "Unknown child process pid %d, will report returncode 255", 1419*cda5da8dSAndroid Build Coastguard Worker pid) 1420*cda5da8dSAndroid Build Coastguard Worker else: 1421*cda5da8dSAndroid Build Coastguard Worker returncode = waitstatus_to_exitcode(status) 1422*cda5da8dSAndroid Build Coastguard Worker if loop.get_debug(): 1423*cda5da8dSAndroid Build Coastguard Worker logger.debug('process %s exited with returncode %s', 1424*cda5da8dSAndroid Build Coastguard Worker expected_pid, returncode) 1425*cda5da8dSAndroid Build Coastguard Worker 1426*cda5da8dSAndroid Build Coastguard Worker if loop.is_closed(): 1427*cda5da8dSAndroid Build Coastguard Worker logger.warning("Loop %r that handles pid %r is closed", loop, pid) 1428*cda5da8dSAndroid Build Coastguard Worker else: 1429*cda5da8dSAndroid Build Coastguard Worker loop.call_soon_threadsafe(callback, pid, returncode, *args) 1430*cda5da8dSAndroid Build Coastguard Worker 1431*cda5da8dSAndroid Build Coastguard Worker self._threads.pop(expected_pid) 1432*cda5da8dSAndroid Build Coastguard Worker 1433*cda5da8dSAndroid Build Coastguard Worker 1434*cda5da8dSAndroid Build Coastguard Workerclass _UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy): 1435*cda5da8dSAndroid Build Coastguard Worker """UNIX event loop policy with a watcher for child processes.""" 1436*cda5da8dSAndroid Build Coastguard Worker _loop_factory = _UnixSelectorEventLoop 1437*cda5da8dSAndroid Build Coastguard Worker 1438*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 1439*cda5da8dSAndroid Build Coastguard Worker super().__init__() 1440*cda5da8dSAndroid Build Coastguard Worker self._watcher = None 1441*cda5da8dSAndroid Build Coastguard Worker 1442*cda5da8dSAndroid Build Coastguard Worker def _init_watcher(self): 1443*cda5da8dSAndroid Build Coastguard Worker with events._lock: 1444*cda5da8dSAndroid Build Coastguard Worker if self._watcher is None: # pragma: no branch 1445*cda5da8dSAndroid Build Coastguard Worker self._watcher = ThreadedChildWatcher() 1446*cda5da8dSAndroid Build Coastguard Worker if threading.current_thread() is threading.main_thread(): 1447*cda5da8dSAndroid Build Coastguard Worker self._watcher.attach_loop(self._local._loop) 1448*cda5da8dSAndroid Build Coastguard Worker 1449*cda5da8dSAndroid Build Coastguard Worker def set_event_loop(self, loop): 1450*cda5da8dSAndroid Build Coastguard Worker """Set the event loop. 1451*cda5da8dSAndroid Build Coastguard Worker 1452*cda5da8dSAndroid Build Coastguard Worker As a side effect, if a child watcher was set before, then calling 1453*cda5da8dSAndroid Build Coastguard Worker .set_event_loop() from the main thread will call .attach_loop(loop) on 1454*cda5da8dSAndroid Build Coastguard Worker the child watcher. 1455*cda5da8dSAndroid Build Coastguard Worker """ 1456*cda5da8dSAndroid Build Coastguard Worker 1457*cda5da8dSAndroid Build Coastguard Worker super().set_event_loop(loop) 1458*cda5da8dSAndroid Build Coastguard Worker 1459*cda5da8dSAndroid Build Coastguard Worker if (self._watcher is not None and 1460*cda5da8dSAndroid Build Coastguard Worker threading.current_thread() is threading.main_thread()): 1461*cda5da8dSAndroid Build Coastguard Worker self._watcher.attach_loop(loop) 1462*cda5da8dSAndroid Build Coastguard Worker 1463*cda5da8dSAndroid Build Coastguard Worker def get_child_watcher(self): 1464*cda5da8dSAndroid Build Coastguard Worker """Get the watcher for child processes. 1465*cda5da8dSAndroid Build Coastguard Worker 1466*cda5da8dSAndroid Build Coastguard Worker If not yet set, a ThreadedChildWatcher object is automatically created. 1467*cda5da8dSAndroid Build Coastguard Worker """ 1468*cda5da8dSAndroid Build Coastguard Worker if self._watcher is None: 1469*cda5da8dSAndroid Build Coastguard Worker self._init_watcher() 1470*cda5da8dSAndroid Build Coastguard Worker 1471*cda5da8dSAndroid Build Coastguard Worker return self._watcher 1472*cda5da8dSAndroid Build Coastguard Worker 1473*cda5da8dSAndroid Build Coastguard Worker def set_child_watcher(self, watcher): 1474*cda5da8dSAndroid Build Coastguard Worker """Set the watcher for child processes.""" 1475*cda5da8dSAndroid Build Coastguard Worker 1476*cda5da8dSAndroid Build Coastguard Worker assert watcher is None or isinstance(watcher, AbstractChildWatcher) 1477*cda5da8dSAndroid Build Coastguard Worker 1478*cda5da8dSAndroid Build Coastguard Worker if self._watcher is not None: 1479*cda5da8dSAndroid Build Coastguard Worker self._watcher.close() 1480*cda5da8dSAndroid Build Coastguard Worker 1481*cda5da8dSAndroid Build Coastguard Worker self._watcher = watcher 1482*cda5da8dSAndroid Build Coastguard Worker 1483*cda5da8dSAndroid Build Coastguard Worker 1484*cda5da8dSAndroid Build Coastguard WorkerSelectorEventLoop = _UnixSelectorEventLoop 1485*cda5da8dSAndroid Build Coastguard WorkerDefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy 1486