mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Use PidfdChildWatcher by default when available (#87951)
This is a backport from cpython 3.12 https://docs.python.org/3/library/asyncio-policy.html > PidfdChildWatcher is a “Goldilocks” child watcher implementation. It doesn’t require signals or threads, doesn’t interfere with any processes launched outside the event loop, and scales linearly with the number of subprocesses launched by the event loop. The main disadvantage is that pidfds are specific to Linux, and only work on recent (5.3+) kernels. https://github.com/python/cpython/pull/98024 There are some additional fixes in cpython 3.12 in https://github.com/python/cpython/pull/94184 when there is no event loop running in the main thread but this is not a problem we have
This commit is contained in:
parent
71b67e20e4
commit
d1e1734fc7
@ -2,8 +2,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from asyncio import events
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@ -49,6 +51,22 @@ class RuntimeConfig:
|
|||||||
open_ui: bool = False
|
open_ui: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
def can_use_pidfd() -> bool:
|
||||||
|
"""Check if pidfd_open is available.
|
||||||
|
|
||||||
|
Back ported from cpython 3.12
|
||||||
|
"""
|
||||||
|
if not hasattr(os, "pidfd_open"):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
pid = os.getpid()
|
||||||
|
os.close(os.pidfd_open(pid, 0)) # pylint: disable=no-member
|
||||||
|
except OSError:
|
||||||
|
# blocked by security policy like SECCOMP
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
|
class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
|
||||||
"""Event loop policy for Home Assistant."""
|
"""Event loop policy for Home Assistant."""
|
||||||
|
|
||||||
@ -56,6 +74,23 @@ class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
|
|||||||
"""Init the event loop policy."""
|
"""Init the event loop policy."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
self._watcher: asyncio.AbstractChildWatcher | None = None
|
||||||
|
|
||||||
|
def _init_watcher(self) -> None:
|
||||||
|
"""Initialize the watcher for child processes.
|
||||||
|
|
||||||
|
Back ported from cpython 3.12
|
||||||
|
"""
|
||||||
|
with events._lock: # type: ignore[attr-defined] # pylint: disable=protected-access
|
||||||
|
if self._watcher is None: # pragma: no branch
|
||||||
|
if can_use_pidfd():
|
||||||
|
self._watcher = asyncio.PidfdChildWatcher()
|
||||||
|
else:
|
||||||
|
self._watcher = asyncio.ThreadedChildWatcher()
|
||||||
|
if threading.current_thread() is threading.main_thread():
|
||||||
|
self._watcher.attach_loop(
|
||||||
|
self._local._loop # type: ignore[attr-defined] # pylint: disable=protected-access
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def loop_name(self) -> str:
|
def loop_name(self) -> str:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user