From: Marc-André Lureau <[email protected]> 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é <[email protected]> Signed-off-by: Marc-André Lureau <[email protected]> --- include/ui/console.h | 1 + system/runstate.c | 5 +++++ ui/vnc.c | 20 ++++++++++++++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 550a5e08e46..89fb4c1942a 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -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); diff --git a/system/runstate.c b/system/runstate.c index 770253b467b..0e1cb3b4e67 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -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 */ } diff --git a/ui/vnc.c b/ui/vnc.c index 1c649e7bccf..d65153a5001 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -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); -- 2.54.0
