]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
qemu: Start vsock notify handler thread after starting qemu
authorDaanDeMeyer <daan.j.demeyer@gmail.com>
Tue, 6 Jan 2026 19:21:51 +0000 (20:21 +0100)
committerDaanDeMeyer <daan.j.demeyer@gmail.com>
Tue, 6 Jan 2026 19:21:51 +0000 (20:21 +0100)
mkosi/qemu.py

index 5a6c4a6abca9c885c0fd18179041c4aa90272a1b..a433d574249dfb846813d090c44a425a115e418b 100644 (file)
@@ -428,7 +428,7 @@ def start_virtiofsd(
             proc.terminate()
 
 
-async def notify(messages: queue.SimpleQueue[tuple[str, str]], *, sock: socket.socket) -> None:
+async def vsock_notify_handler(messages: queue.SimpleQueue[tuple[str, str]], *, sock: socket.socket) -> None:
     import asyncio
 
     loop = asyncio.get_running_loop()
@@ -460,20 +460,6 @@ async def notify(messages: queue.SimpleQueue[tuple[str, str]], *, sock: socket.s
         logging.debug(f"Received {num_messages} notify messages totalling {format_bytes(num_bytes)} bytes")
 
 
-@contextlib.contextmanager
-def vsock_notify_handler() -> Iterator[tuple[str, AsyncioThread[tuple[str, str]]]]:
-    """
-    This yields a vsock address and an object that will be filled in with the notifications from the VM.
-    """
-    with socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) as vsock:
-        vsock.bind((socket.VMADDR_CID_ANY, socket.VMADDR_PORT_ANY))
-        vsock.listen()
-        vsock.setblocking(False)
-
-        with AsyncioThread(functools.partial(notify, sock=vsock)) as thread:
-            yield f"vsock-stream:{socket.VMADDR_CID_HOST}:{vsock.getsockname()[1]}", thread
-
-
 @contextlib.contextmanager
 def start_journal_remote(config: Config, sockfd: int) -> Iterator[None]:
     assert config.forward_journal
@@ -1226,6 +1212,7 @@ def run_qemu(args: Args, config: Config) -> None:
         assert ovmf
         cmdline += ["-drive", f"if=pflash,format={ovmf.format},readonly=on,file={ovmf.firmware}"]
 
+    vsock: Optional[socket.socket] = None
     notify: Optional[AsyncioThread[tuple[str, str]]] = None
 
     with contextlib.ExitStack() as stack:
@@ -1371,8 +1358,13 @@ def run_qemu(args: Args, config: Config) -> None:
                 cmdline += ["-device", "tpm-tis-device,tpmdev=tpm0"]
 
         if QemuDeviceNode.vhost_vsock in qemu_device_fds:
-            addr, notify = stack.enter_context(vsock_notify_handler())
-            (credentials / "vmm.notify_socket").write_text(addr)
+            vsock = stack.enter_context(socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM))
+            vsock.bind((socket.VMADDR_CID_ANY, socket.VMADDR_PORT_ANY))
+            vsock.listen()
+            vsock.setblocking(False)
+            (credentials / "vmm.notify_socket").write_text(
+                f"vsock-stream:{socket.VMADDR_CID_HOST}:{vsock.getsockname()[1]}"
+            )
 
         if config.forward_journal:
             (credentials / "journal.forward_to_socket").write_text(
@@ -1482,6 +1474,13 @@ def run_qemu(args: Args, config: Config) -> None:
 
             register_machine(config, proc.pid, fname, cid)
 
+            # Fork and threads don't mix well when using preexec functions, so start the thread to handle
+            # vsock notifications only after we have started qemu.
+            if vsock:
+                notify = stack.enter_context(
+                    AsyncioThread(functools.partial(vsock_notify_handler, sock=vsock))
+                )
+
             proc.send_signal(signal.SIGCONT)
 
         if notify and (status := int({k: v for k, v in notify.process()}.get("EXIT_STATUS", "0"))) != 0: