|
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