[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