|
2 | 2 | from __future__ import annotations
|
3 | 3 |
|
4 | 4 | import asyncio
|
| 5 | +from asyncio import events |
5 | 6 | import dataclasses
|
6 | 7 | import logging
|
| 8 | +import os |
7 | 9 | import threading
|
8 | 10 | import traceback
|
9 | 11 | from typing import Any
|
@@ -49,13 +51,46 @@ class RuntimeConfig:
|
49 | 51 | open_ui: bool = False
|
50 | 52 |
|
51 | 53 |
|
| 54 | +def can_use_pidfd() -> bool: |
| 55 | + """Check if pidfd_open is available. |
| 56 | +
|
| 57 | + Back ported from cpython 3.12 |
| 58 | + """ |
| 59 | + if not hasattr(os, "pidfd_open"): |
| 60 | + return False |
| 61 | + try: |
| 62 | + pid = os.getpid() |
| 63 | + os.close(os.pidfd_open(pid, 0)) # pylint: disable=no-member |
| 64 | + except OSError: |
| 65 | + # blocked by security policy like SECCOMP |
| 66 | + return False |
| 67 | + return True |
| 68 | + |
| 69 | + |
52 | 70 | class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
|
53 | 71 | """Event loop policy for Home Assistant."""
|
54 | 72 |
|
55 | 73 | def __init__(self, debug: bool) -> None:
|
56 | 74 | """Init the event loop policy."""
|
57 | 75 | super().__init__()
|
58 | 76 | self.debug = debug
|
| 77 | + self._watcher: asyncio.AbstractChildWatcher | None = None |
| 78 | + |
| 79 | + def _init_watcher(self) -> None: |
| 80 | + """Initialize the watcher for child processes. |
| 81 | +
|
| 82 | + Back ported from cpython 3.12 |
| 83 | + """ |
| 84 | + with events._lock: # type: ignore[attr-defined] # pylint: disable=protected-access |
| 85 | + if self._watcher is None: # pragma: no branch |
| 86 | + if can_use_pidfd(): |
| 87 | + self._watcher = asyncio.PidfdChildWatcher() |
| 88 | + else: |
| 89 | + self._watcher = asyncio.ThreadedChildWatcher() |
| 90 | + if threading.current_thread() is threading.main_thread(): |
| 91 | + self._watcher.attach_loop( |
| 92 | + self._local._loop # type: ignore[attr-defined] # pylint: disable=protected-access |
| 93 | + ) |
59 | 94 |
|
60 | 95 | @property
|
61 | 96 | def loop_name(self) -> str:
|
|
0 commit comments