|
9 | 9 | from collections import deque |
10 | 10 | from signal import Signals |
11 | 11 | from typing import Any, Callable, Deque, List, Optional, cast |
| 12 | +from asyncio.unix_events import ThreadedChildWatcher |
| 13 | +try: |
| 14 | + from asyncio.unix_events import PidfdChildWatcher |
| 15 | +except ImportError: |
| 16 | + PidfdChildWatcher = None |
12 | 17 |
|
13 | 18 | if sys.version_info >= (3, 12): |
14 | 19 | from typing import Final, override |
@@ -188,18 +193,33 @@ async def connect_stdout(): |
188 | 193 |
|
189 | 194 | @override |
190 | 195 | def _connect_child(self, argv: List[str]) -> None: |
191 | | - if os.name != 'nt': |
192 | | - # see #238, #241 |
193 | | - self._child_watcher = asyncio.get_child_watcher() |
194 | | - self._child_watcher.attach_loop(self._loop) |
195 | | - |
196 | 196 | async def create_subprocess(): |
197 | 197 | transport: asyncio.SubprocessTransport # type: ignore |
198 | 198 | transport, protocol = await self._loop.subprocess_exec( |
199 | 199 | self._protocol_factory, *argv) |
200 | 200 | pid = transport.get_pid() |
201 | 201 | debug("child subprocess_exec successful, PID = %s", pid) |
202 | 202 |
|
| 203 | + if os.name != 'nt': |
| 204 | + # see #238, #241 |
| 205 | + pidfd_works = False |
| 206 | + if PidfdChildWatcher is not None and hasattr(os, "pidfd_open"): |
| 207 | + try: |
| 208 | + fd = os.pidfd_open(pid) |
| 209 | + except Exception: |
| 210 | + pass |
| 211 | + else: |
| 212 | + os.close(fd) |
| 213 | + pidfd_works = True |
| 214 | + |
| 215 | + if pidfd_works: |
| 216 | + watcher = PidfdChildWatcher() |
| 217 | + else: |
| 218 | + watcher = ThreadedChildWatcher() |
| 219 | + |
| 220 | + watcher.attach_loop(self._loop) |
| 221 | + self._child_watcher = watcher |
| 222 | + |
203 | 223 | self._transport = cast(asyncio.WriteTransport, |
204 | 224 | transport.get_pipe_transport(0)) # stdin |
205 | 225 | self._protocol = protocol |
|
0 commit comments