[Spice-devel] [PATCH spice-gtk 07/10] usbredir: Handle usb events from a thread
Hans de Goede
hdegoede at redhat.com
Mon Dec 19 03:24:40 PST 2011
This solves various latency issues with USB handling.
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
gtk/channel-usbredir.c | 5 +++++
gtk/usb-device-manager.c | 45 ++++++++++++++++++++++++++++++++-------------
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index dfd1655..e14088a 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -352,6 +352,11 @@ void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel)
case STATE_CONNECTING:
case STATE_CONNECTED:
spice_channel_disconnect(SPICE_CHANNEL(channel), SPICE_CHANNEL_NONE);
+ /*
+ * This sets the usb event thread run condition to FALSE, therefor
+ * it must be done before usbredirhost_close, as usbredirhost_close
+ * will interrupt the libusb_handle_events call in the thread.
+ */
spice_usb_device_manager_stop_event_listening(
spice_usb_device_manager_get(
spice_channel_get_session(SPICE_CHANNEL(channel)),
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 6fba6f6..44ed84d 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -26,8 +26,8 @@
#include "glib-compat.h"
#ifdef USE_USBREDIR
-#include <gusb/gusb-source.h>
#include <gusb/gusb-device-list.h>
+#include <gusb/gusb-context-private.h>
#include "channel-usbredir-priv.h"
#endif
@@ -91,8 +91,9 @@ struct _SpiceUsbDeviceManagerPrivate {
#ifdef USE_USBREDIR
GUsbContext *context;
GUsbDeviceList *devlist;
- GUsbSource *source;
int event_listeners;
+ GThread *event_thread;
+ gboolean event_thread_run;
#endif
GPtrArray *devices;
GPtrArray *channels;
@@ -204,6 +205,9 @@ static void spice_usb_device_manager_finalize(GObject *gobject)
SpiceUsbDeviceManagerPrivate *priv = self->priv;
#ifdef USE_USBREDIR
+ if (priv->event_thread)
+ g_thread_join(priv->event_thread);
+
if (priv->devlist) {
g_object_unref(priv->devlist);
g_object_unref(priv->context);
@@ -480,6 +484,18 @@ static void spice_usb_device_manager_channel_connect_cb(
/* ------------------------------------------------------------------ */
/* private api */
+static gpointer spice_usb_device_magager_usb_ev_thread(gpointer user_data)
+{
+ SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data);
+ SpiceUsbDeviceManagerPrivate *priv = self->priv;
+
+ while (priv->event_thread_run) {
+ libusb_handle_events(_g_usb_context_get_context(priv->context));
+ }
+
+ return NULL;
+}
+
gboolean spice_usb_device_manager_start_event_listening(
SpiceUsbDeviceManager *self, GError **err)
{
@@ -491,10 +507,18 @@ gboolean spice_usb_device_manager_start_event_listening(
if (priv->event_listeners > 1)
return TRUE;
- g_return_val_if_fail(priv->source == NULL, FALSE);
-
- priv->source = g_usb_source_new(priv->main_context, priv->context, err);
- return priv->source != NULL;
+ /* We don't join the thread when we stop event listening, as the
+ libusb_handle_events call in the thread won't exit until the
+ libusb_close call for the device is made from usbredirhost_close. */
+ if (priv->event_thread) {
+ g_thread_join(priv->event_thread);
+ priv->event_thread = NULL;
+ }
+ priv->event_thread_run = TRUE;
+ priv->event_thread = g_thread_create(
+ spice_usb_device_magager_usb_ev_thread,
+ self, TRUE, err);
+ return priv->event_thread != NULL;
}
void spice_usb_device_manager_stop_event_listening(
@@ -505,13 +529,8 @@ void spice_usb_device_manager_stop_event_listening(
g_return_if_fail(priv->event_listeners > 0);
priv->event_listeners--;
- if (priv->event_listeners != 0)
- return;
-
- g_return_if_fail(priv->source != NULL);
-
- g_usb_source_destroy(priv->source);
- priv->source = NULL;
+ if (priv->event_listeners == 0)
+ priv->event_thread_run = FALSE;
}
#endif
--
1.7.7.4
More information about the Spice-devel
mailing list