File kvmd-event_loop.patch of Package kvmd
From d8c0a63a0cc023a5215363c995f152495671bacb Mon Sep 17 00:00:00 2001
From: Oleg Girko <ol@infoserver.lv>
Date: Mon, 10 Nov 2025 19:57:09 +0000
Subject: [PATCH] Fix event loop handling for compatibility with Python 3.14.
Starting with Python 3.14, asyncio.get_event_loop() does not create an
event loop for the current thread automatically if it's not created yet.
Automatic event loop creation was already deprecated, but now instead of
deprecation warning, RuntimeError exception is raised.
This change adds aiotools.get_event_loop() function that creates a new
event loop in case asyncio.get_event_loop() raises RuntimeError.
All calls of asyncio.get_event_loop() replaced with
aiotools.get_event_loop().
Signed-off-by: Oleg Girko <ol@infoserver.lv>
---
kvmd/aiotools.py | 12 ++++++++++--
kvmd/apps/kvmd/streamer.py | 2 +-
kvmd/apps/vnc/rfb/stream.py | 2 +-
kvmd/htserver.py | 2 +-
kvmd/inotify.py | 4 ++--
5 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/kvmd/aiotools.py b/kvmd/aiotools.py
index 847c2dfa..4fb71c87 100644
--- a/kvmd/aiotools.py
+++ b/kvmd/aiotools.py
@@ -51,6 +51,14 @@ async def write_file(path: str, text: str) -> None:
async with aiofiles.open(path, "w") as file:
await file.write(text)
+def get_event_loop() -> asyncio.AbstractEventLoop:
+ try:
+ loop = asyncio.get_event_loop()
+ except RuntimeError:
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ return loop
+
# =====
def run(coro: Coroutine, final: (Coroutine | None)=None) -> None:
@@ -62,7 +70,7 @@ def run(coro: Coroutine, final: (Coroutine | None)=None) -> None:
def sigterm_handler() -> None:
raise SystemExit()
- loop = asyncio.get_event_loop()
+ loop = get_event_loop()
loop.add_signal_handler(signal.SIGINT, sigint_handler)
loop.add_signal_handler(signal.SIGTERM, sigterm_handler)
@@ -200,7 +208,7 @@ async def run_async(func: Callable[..., _RetvalT], *args: Any) -> _RetvalT:
def run_sync(coro: Coroutine[Any, Any, _RetvalT]) -> _RetvalT:
- return asyncio.get_event_loop().run_until_complete(coro)
+ return get_event_loop().run_until_complete(coro)
# =====
diff --git a/kvmd/apps/kvmd/streamer.py b/kvmd/apps/kvmd/streamer.py
index d1a5b792..76e8fbcf 100644
--- a/kvmd/apps/kvmd/streamer.py
+++ b/kvmd/apps/kvmd/streamer.py
@@ -302,7 +302,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
self.__notifier.notify(self.__ST_STREAMER)
get_logger(0).info("Installing SIGUSR2 streamer handler ...")
- asyncio.get_event_loop().add_signal_handler(signal.SIGUSR2, signal_handler)
+ aiotools.get_event_loop().add_signal_handler(signal.SIGUSR2, signal_handler)
prev: dict = {}
while True:
diff --git a/kvmd/apps/vnc/rfb/stream.py b/kvmd/apps/vnc/rfb/stream.py
index 53add06f..a70af614 100644
--- a/kvmd/apps/vnc/rfb/stream.py
+++ b/kvmd/apps/vnc/rfb/stream.py
@@ -112,7 +112,7 @@ class RfbClientStream:
# =====
async def _start_tls(self, ssl_context: ssl.SSLContext, ssl_timeout: float) -> None:
- loop = asyncio.get_event_loop()
+ loop = aiotools.get_event_loop()
ssl_reader = asyncio.StreamReader()
protocol = asyncio.StreamReaderProtocol(ssl_reader)
diff --git a/kvmd/htserver.py b/kvmd/htserver.py
index 62eeab5f..9c765401 100644
--- a/kvmd/htserver.py
+++ b/kvmd/htserver.py
@@ -327,7 +327,7 @@ class HttpServer:
shutdown_timeout=1,
access_log_format=access_log_format,
print=self.__run_app_print,
- loop=asyncio.get_event_loop(),
+ loop=aiotools.get_event_loop(),
)
# =====
diff --git a/kvmd/inotify.py b/kvmd/inotify.py
index 7d282d96..e2391b2f 100644
--- a/kvmd/inotify.py
+++ b/kvmd/inotify.py
@@ -296,7 +296,7 @@ class Inotify:
def __enter__(self) -> "Inotify":
assert self.__fd < 0
self.__fd = _inotify_check(libc.inotify_init())
- asyncio.get_event_loop().add_reader(self.__fd, self.__read_and_queue_events)
+ aiotools.get_event_loop().add_reader(self.__fd, self.__read_and_queue_events)
return self
def __exit__(
@@ -307,7 +307,7 @@ class Inotify:
) -> None:
if self.__fd >= 0:
- asyncio.get_event_loop().remove_reader(self.__fd)
+ aiotools.get_event_loop().remove_reader(self.__fd)
for wd in list(self.__wd_by_path.values()):
libc.inotify_rm_watch(self.__fd, wd)
try:
--
2.52.0