[Spice-devel] [PATCH spice-gtk 1/5] usb-device-manager: Avoid needless re-numeration of usb devs under Linux

Hans de Goede hdegoede at redhat.com
Tue Apr 23 05:19:48 PDT 2013


libusb_get_device_list() is not exactly a cheap call (lots of sysfs and
usbfs accesses), so it is worth to avoid it where possible.

This patch restores the old (pre win32 support addition) of dealing with
libusb-devices under Linux, it keeps the device from the first lookup
in spice_usb_device_manager_add_dev cached and uses that throughout.

This also means that spice_usb_device_manager_device_to_libdev can no
longer fail under Linux, so no need to error check it.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/usb-device-manager.c | 47 +++++++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 16 deletions(-)

diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 92d4615..76f82b2 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -140,8 +140,11 @@ typedef struct _SpiceUsbDeviceInfo {
     guint8  devaddr;
     guint16 vid;
     guint16 pid;
+#ifdef G_OS_WIN32
     guint8  state;
-    guint8  reserved;
+#else
+    libusb_device *libdev;
+#endif
     gint    ref;
 } SpiceUsbDeviceInfo;
 
@@ -1261,8 +1264,8 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
             continue; /* Skip already used channels */
 
         libdev = spice_usb_device_manager_device_to_libdev(self, device);
-        if (libdev == NULL) {
 #ifdef G_OS_WIN32
+        if (libdev == NULL) {
             /* Most likely, the device was plugged out at driver installation
              * time, and its remove-device event was ignored.
              * So remove the device now
@@ -1272,13 +1275,13 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self,
             g_ptr_array_remove(priv->devices, device);
             g_signal_emit(self, signals[DEVICE_REMOVED], 0, device);
             spice_usb_device_unref(device);
-#endif
             g_simple_async_result_set_error(result,
                                             SPICE_CLIENT_ERROR,
                                             SPICE_CLIENT_ERROR_FAILED,
                                             _("Device was not found"));
             goto done;
         }
+#endif
         spice_usbredir_channel_connect_device_async(channel,
                                  libdev,
                                  device,
@@ -1563,6 +1566,9 @@ static SpiceUsbDeviceInfo *spice_usb_device_new(libusb_device *libdev)
     info->vid = vid;
     info->pid = pid;
     info->ref = 1;
+#ifndef G_OS_WIN32
+    info->libdev = libusb_ref_device(libdev);
+#endif
 
     return info;
 }
@@ -1642,26 +1648,24 @@ static void spice_usb_device_unref(SpiceUsbDevice *device)
 
     ref_count_is_0 = g_atomic_int_dec_and_test(&info->ref);
     if (ref_count_is_0) {
+#ifndef G_OS_WIN32
+        libusb_unref_device(info->libdev);
+#endif
         g_free(info);
     }
 }
 
-#ifndef G_OS_WIN32 /* Linux -- compare bus.addr */
+#ifndef G_OS_WIN32 /* Linux -- directly compare libdev */
 static gboolean
 spice_usb_device_equal_libdev(SpiceUsbDevice *device,
                               libusb_device  *libdev)
 {
-    guint8 addr1, addr2, bus1, bus2;
+    SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
 
     if ((device == NULL) || (libdev == NULL))
         return FALSE;
 
-    bus1  = spice_usb_device_get_busnum(device);
-    addr1 = spice_usb_device_get_devaddr(device);
-    bus2  = libusb_get_bus_number(libdev);
-    addr2 = libusb_get_device_address(libdev);
-
-    return ((bus1 == bus2) && (addr1 == addr2));
+    return info->libdev == libdev;
 }
 #else /* Windows -- compare vid:pid of device and libdev */
 static gboolean
@@ -1692,6 +1696,14 @@ static libusb_device *
 spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
                                           SpiceUsbDevice *device)
 {
+#ifdef G_OS_WIN32
+    /*
+     * On win32 we need to do this the hard and slow way, by asking libusb to
+     * re-enumerate all devices and then finding a matching device.
+     * We cannot cache the libusb_device like we do under Linux since the
+     * driver swap we do under windows invalidates the cached libdev.
+     */
+
     libusb_device *d, **devlist;
     int bus, addr;
     int i;
@@ -1701,13 +1713,9 @@ spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
     g_return_val_if_fail(self->priv != NULL, NULL);
     g_return_val_if_fail(self->priv->context != NULL, NULL);
 
-#ifndef G_OS_WIN32
-    bus  = spice_usb_device_get_busnum(device);
-    addr = spice_usb_device_get_devaddr(device);
-#else
+    /* On windows we match by vid / pid, since the address may change */
     bus  = spice_usb_device_get_vid(device);
     addr = spice_usb_device_get_pid(device);
-#endif
 
     libusb_get_device_list(self->priv->context, &devlist);
     if (!devlist)
@@ -1723,5 +1731,12 @@ spice_usb_device_manager_device_to_libdev(SpiceUsbDeviceManager *self,
     libusb_free_device_list(devlist, 1);
 
     return d;
+
+#else
+    /* Simply return a ref to the cached libdev */
+    SpiceUsbDeviceInfo *info = (SpiceUsbDeviceInfo *)device;
+
+    return libusb_ref_device(info->libdev);
+#endif
 }
 #endif /* USE_USBREDIR */
-- 
1.8.2



More information about the Spice-devel mailing list