From 932611bb1fd27a016521623e4f049e41d406d3c9 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Fri, 3 Jan 2025 08:37:22 +0100 Subject: [PATCH] Replace deprecated asyncio.get_child_watcher() Use PidfdChildWatcher if os.pidfd_open is available and otherwise use ThreadedChildWatcher which should work in any case. Fixes #583 --- pynvim/msgpack_rpc/event_loop/asyncio.py | 41 +++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/pynvim/msgpack_rpc/event_loop/asyncio.py b/pynvim/msgpack_rpc/event_loop/asyncio.py index cb17f321..5d8ef2a0 100644 --- a/pynvim/msgpack_rpc/event_loop/asyncio.py +++ b/pynvim/msgpack_rpc/event_loop/asyncio.py @@ -188,10 +188,42 @@ async def connect_stdout(): @override def _connect_child(self, argv: List[str]) -> None: + def can_use_pidfd(): + # Unix system without pidfd_open? + if not hasattr(os, 'pidfd_open'): + return False + + # Check that we are not blocked by security policy like SECCOMP + try: + pid = os.getpid() + fd = os.pidfd_open(pid, 0) + os.close(fd) + except OSError: + return False + + return True + + def get_child_watcher(): + if can_use_pidfd(): + try: + from asyncio.unix_events import PidfdChildWatcher + return PidfdChildWatcher() + except ImportError: + pass + + try: + from asyncio.unix_events import ThreadedChildWatcher + return ThreadedChildWatcher() + except ImportError: + pass + + # FIXME Python 3.7, return None if we drop support + return asyncio.get_child_watcher() + if os.name != 'nt': - # see #238, #241 - self._child_watcher = asyncio.get_child_watcher() - self._child_watcher.attach_loop(self._loop) + watcher = get_child_watcher() + watcher.attach_loop(self._loop) + self._child_watcher = watcher async def create_subprocess(): transport: asyncio.SubprocessTransport # type: ignore @@ -250,7 +282,8 @@ def _close_transport(transport): # Windows: for ProactorBasePipeTransport, close() doesn't take in # effect immediately (closing happens asynchronously inside the # event loop), need to wait a bit for completing graceful shutdown. - if os.name == 'nt' and hasattr(transport, '_sock'): + if (sys.version_info.major == 3 and sys.version_info.minor < 13 and + os.name == 'nt' and hasattr(transport, '_sock')): async def wait_until_closed(): # pylint: disable-next=protected-access while transport._sock is not None: