ui/vnc: clean up VNC displays on exit

Previously, VNC displays were never torn down on QEMU exit, leaking
resources and leaving connected clients with unclean disconnects.

Add vnc_cleanup() to free all VNC displays during qemu_cleanup().
Make vnc_display_close() initiate disconnection of active clients,
and have vnc_display_free() drain the main loop until all clients
have completed their teardown, instead of asserting the client list
is empty.

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau
2026-04-08 17:15:42 +04:00
parent bbd8cb0ed7
commit 4a33bdd9e0
3 changed files with 24 additions and 2 deletions

View File

@@ -445,6 +445,7 @@ void vnc_parse(const char *str);
int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp);
bool vnc_display_reload_certs(const char *id, Error **errp);
bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp);
void vnc_cleanup(void);
/* input.c */
int index_from_key(const char *key, size_t key_length);

View File

@@ -61,6 +61,8 @@
#include "system/confidential-guest-support.h"
#include "system/system.h"
#include "system/tpm.h"
#include "ui/console.h"
#include "trace.h"
static NotifierList exit_notifiers =
@@ -1044,5 +1046,8 @@ void qemu_cleanup(int status)
monitor_cleanup();
qemu_chr_cleanup();
user_creatable_cleanup();
#ifdef CONFIG_VNC
vnc_cleanup();
#endif
/* TODO: unref root container, check all devices are ok */
}

View File

@@ -3473,8 +3473,13 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
static void vnc_display_close(VncDisplay *vd)
{
VncState *vs;
assert(vd);
QTAILQ_FOREACH(vs, &vd->clients, next) {
vnc_disconnect_start(vs);
}
if (vd->listener) {
qio_net_listener_disconnect(vd->listener);
object_unref(OBJECT(vd->listener));
@@ -3515,10 +3520,12 @@ void vnc_display_free(VncDisplay *vd)
return;
}
assert(QTAILQ_EMPTY(&vd->clients));
vnc_display_close(vd);
while (!QTAILQ_EMPTY(&vd->clients)) {
main_loop_wait(false);
}
vnc_stop_worker_thread(vd);
vnc_display_close(vd);
unregister_displaychangelistener(&vd->dcl);
qkbd_state_free(vd->kbd);
qemu_del_vm_change_state_handler(vd->vmstate_handler_entry);
@@ -4348,6 +4355,15 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
return vnc_display_new(id, errp) != NULL ? 0 : -1;
}
void vnc_cleanup(void)
{
VncDisplay *vd, *vd_next;
QTAILQ_FOREACH_SAFE(vd, &vnc_displays, next, vd_next) {
vnc_display_free(vd);
}
}
static void vnc_register_config(void)
{
qemu_add_opts(&qemu_vnc_opts);