diff options
author | Christophe Fergeau <cfergeau@redhat.com> | 2016-06-29 16:57:36 +0200 |
---|---|---|
committer | Christophe Fergeau <cfergeau@redhat.com> | 2016-06-30 18:16:10 +0200 |
commit | c0ccc8144e8554e4a8c4395f80d7e8c10d2dcfc0 (patch) | |
tree | 2ee808d184fc224fa094207c6e6438d16408cd03 | |
parent | 4a777ec0a6153e8229c406ff9b1589e30195afc2 (diff) |
usb-device-manager: Avoid USB event thread leak
This is a follow-up of the previous commit ('usb-channel: Really stop
listening for USB events on disconnection').
Since the USB event thread has to be stopped when we destroy the
associated SpiceUsbDeviceManager, spice_usb_device_manager_dispose()
should force event_thread_run to FALSE even if
spice_usb_device_manager_stop_event_listening() was not enough. When
this happens, this means that there is a bug in the internal users of
spice_usb_device_manager_start_event_listening(), but with this change,
we'll at least warn about it, and avoid a thread leak/potential future
crash.
-rw-r--r-- | src/usb-device-manager.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c index 808ec6c..53505fa 100644 --- a/src/usb-device-manager.c +++ b/src/usb-device-manager.c @@ -375,12 +375,22 @@ static void spice_usb_device_manager_dispose(GObject *gobject) #ifdef USE_LIBUSB_HOTPLUG if (priv->hp_handle) { spice_usb_device_manager_stop_event_listening(self); + if (g_atomic_int_get(&priv->event_thread_run)) { + /* Force termination of the event thread even if there were some + * mismatched spice_usb_device_manager_{start,stop}_event_listening + * calls. Otherwise, the usb event thread will be leaked, and will + * try to use the libusb context we destroy in finalize(), which would + * cause a crash */ + g_warn_if_reached(); + g_atomic_int_set(&priv->event_thread_run, FALSE); + } /* This also wakes up the libusb_handle_events() in the event_thread */ libusb_hotplug_deregister_callback(priv->context, priv->hp_handle); priv->hp_handle = 0; } #endif - if (priv->event_thread && !g_atomic_int_get(&priv->event_thread_run)) { + if (priv->event_thread) { + g_warn_if_fail(g_atomic_int_get(&priv->event_thread_run) == FALSE); g_thread_join(priv->event_thread); priv->event_thread = NULL; } |