Commit 285689a3f1 for qemu.org

commit 285689a3f1f3a60f9cca56156e587a2008231bd3
Author: Marc-André Lureau <marcandre.lureau@redhat.com>
Date:   Tue Jun 23 11:44:30 2026 +0400

    ui: add display cleanup infrastructure

    Add a cleanup callback to QemuDisplay and a qemu_display_cleanup()
    function that iterates all registered display types and calls their
    cleanup handler. Wire it into qemu_cleanup() in runstate.c, replacing
    the ad-hoc vnc_cleanup() call.

    This provides a structured alternative to atexit() handlers, giving
    deterministic teardown ordering and making resource leaks visible to
    sanitizers.

    The cleanup should happen before user_creatable_cleanup(), since some
    display have weak user-creatable references to cleanup before.

    Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
    Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
    Message-ID: <20260623-b4-ui-v4-15-4656aec3398d@redhat.com>

diff --git a/include/ui/console.h b/include/ui/console.h
index b7bfecb6ee..5322c56009 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -403,6 +403,7 @@ struct QemuDisplay {
     DisplayType type;
     void (*early_init)(DisplayOptions *opts);
     void (*init)(DisplayState *ds, DisplayOptions *opts);
+    void (*cleanup)(void);
     const char *vc;
 };

@@ -411,6 +412,7 @@ bool qemu_display_find_default(DisplayOptions *opts);
 void qemu_display_early_init(DisplayOptions *opts);
 void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
 const char *qemu_display_get_vc(DisplayOptions *opts);
+void qemu_display_cleanup(void);
 void qemu_display_help(void);

 /* vnc.c */
diff --git a/system/runstate.c b/system/runstate.c
index d35fa270bd..18e585be47 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -62,7 +62,6 @@
 #include "system/system.h"
 #include "system/tpm.h"
 #include "ui/console.h"
-#include "ui/qemu-spice-module.h"

 #include "trace.h"

@@ -1046,12 +1045,7 @@ void qemu_cleanup(int status)
     audio_cleanup();
     monitor_cleanup();
     qemu_chr_cleanup();
+    qemu_display_cleanup();
     user_creatable_cleanup();
-#ifdef CONFIG_VNC
-    vnc_cleanup();
-#endif
-#ifdef CONFIG_SPICE
-    qemu_spice.cleanup();
-#endif
     /* TODO: unref root container, check all devices are ok */
 }
diff --git a/ui/console.c b/ui/console.c
index 58f29e82c8..1fe3e3a3a6 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -42,6 +42,7 @@
 #include "qemu/memfd.h"
 #include "ui/vt100.h"
 #include "vgafont.h"
+#include "ui/qemu-spice.h"

 #include "console-priv.h"

@@ -575,7 +576,7 @@ void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
 {
     /* display has opengl support */
     assert(con);
-    if (con->gl) {
+    if (gl && con->gl) {
         error_report("The console already has an OpenGL context.");
         exit(1);
     }
@@ -1414,6 +1415,23 @@ void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
     dpys[opts->type]->init(ds, opts);
 }

+void qemu_display_cleanup(void)
+{
+    int i;
+
+    for (i = 0; i < DISPLAY_TYPE__MAX; i++) {
+        if (dpys[i] && dpys[i]->cleanup) {
+            dpys[i]->cleanup();
+        }
+    }
+#ifdef CONFIG_VNC
+    vnc_cleanup();
+#endif
+#ifdef CONFIG_SPICE
+    qemu_spice.cleanup();
+#endif
+}
+
 const char *qemu_display_get_vc(DisplayOptions *opts)
 {
 #ifdef CONFIG_PIXMAN