[Spice-devel] [PATCH spice-gtk 2/5] usb-device-manager: Make spice_usb_device_manager_connect_device async

Hans de Goede hdegoede at redhat.com
Tue Nov 15 07:30:58 PST 2011


With the (upcoming) introduction of the usb device node acl helper, which
uses policykit, spice_usbredir_channel_connect() may take a long time as
it will be waiting for the helper, which will be waiting for policykit which
may be interacting with the user. So spice_usbredir_channel_connect() will
need to become async, and since spice_usb_device_manager_connect_device
calls spice_usbredir_channel_connect it thus also needs to become async.

Note that this patch only changes spice_usb_device_manager_connect_device's
API to use the standard GIO async API, it is not actually async after this
patch since spice_usbredir_channel_connect is not yet async.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/Makefile.am          |    2 +-
 gtk/usb-device-manager.c |  106 +++++++++++++++++++++++++++++++++-------------
 gtk/usb-device-manager.h |   12 ++++-
 3 files changed, 86 insertions(+), 34 deletions(-)

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index a3960a7..17efc89 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -571,7 +571,7 @@ gtk_introspection_files =			\
 	$(NULL)
 
 SpiceClientGLib-2.0.gir: libspice-client-glib-2.0.la
-SpiceClientGLib_2_0_gir_INCLUDES = GObject-2.0
+SpiceClientGLib_2_0_gir_INCLUDES = GObject-2.0 Gio-2.0
 SpiceClientGLib_2_0_gir_CFLAGS = $(SPICE_COMMON_CPPFLAGS)
 SpiceClientGLib_2_0_gir_LIBS = libspice-client-glib-2.0.la
 SpiceClientGLib_2_0_gir_FILES = $(glib_introspection_files)
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index 2fb3dbb..dd2e0c4 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -22,7 +22,6 @@
 #include "config.h"
 
 #include <glib-object.h>
-#include <gio/gio.h> /* For GInitable */
 
 #include "glib-compat.h"
 
@@ -424,6 +423,27 @@ static gboolean spice_usb_device_manager_source_callback(gpointer user_data)
     return TRUE;
 }
 
+static void spice_usb_device_manager_auto_connect_cb(GObject      *gobject,
+                                                     GAsyncResult *res,
+                                                     gpointer      user_data)
+{
+    SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(gobject);
+    SpiceUsbDevice *device = user_data;
+    GError *err = NULL;
+
+    spice_usb_device_manager_connect_device_finish(self, res, &err);
+    if (err) {
+        gchar *desc = spice_usb_device_get_description(device);
+        g_prefix_error(&err, "Could not auto-redirect %s: ", desc);
+        g_free(desc);
+
+        g_warning("%s", err->message);
+        g_signal_emit(self, signals[AUTO_CONNECT_FAILED], 0, device, err);
+        g_error_free(err);
+    }
+    g_object_unref(device);
+}
+
 static void spice_usb_device_manager_dev_added(GUsbDeviceList *devlist,
                                                GUsbDevice     *_device,
                                                GUdevDevice    *udev,
@@ -436,17 +456,9 @@ static void spice_usb_device_manager_dev_added(GUsbDeviceList *devlist,
     g_ptr_array_add(priv->devices, g_object_ref(device));
 
     if (priv->auto_connect) {
-        GError *err = NULL;
-        spice_usb_device_manager_connect_device(manager, device, &err);
-        if (err) {
-            gchar *desc = spice_usb_device_get_description(device);
-            g_prefix_error(&err, "Could not auto-redirect %s: ", desc);
-            g_free(desc);
-
-            g_warning("%s", err->message);
-            g_signal_emit(manager, signals[AUTO_CONNECT_FAILED], 0, device, err);
-            g_error_free(err);
-        }
+        spice_usb_device_manager_connect_device(manager, device, NULL,
+                                   spice_usb_device_manager_auto_connect_cb,
+                                   g_object_ref(device));
     }
 
     SPICE_DEBUG("device added %p", device);
@@ -573,33 +585,44 @@ gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *sel
  * spice_usb_device_manager_connect_device:
  * @manager: the #SpiceUsbDeviceManager manager
  * @device: a #SpiceUsbDevice to redirect
- *
- * Returns: %TRUE if @device has been successfully connected and
- * associated with a redirection chanel
+ * @cancellable: a #GCancellable or NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to callback
  */
-gboolean spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *self,
-                                                 SpiceUsbDevice *device, GError **err)
+void spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *self,
+                                             SpiceUsbDevice *device,
+                                             GCancellable *cancellable,
+                                             GAsyncReadyCallback callback,
+                                             gpointer user_data)
 {
-    g_return_val_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self), FALSE);
-    g_return_val_if_fail(device != NULL, FALSE);
-    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+    GSimpleAsyncResult *result;
+    GError *e = NULL;
+
+    g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
+    g_return_if_fail(device != NULL);
 
     SPICE_DEBUG("connecting device %p", device);
 
+    result = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
+                                     spice_usb_device_manager_connect_device);
+
 #ifdef USE_USBREDIR
     SpiceUsbDeviceManagerPrivate *priv = self->priv;
     guint i;
 
     if (spice_usb_device_manager_is_device_connected(self, device)) {
-        g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+        g_simple_async_result_set_error(result,
+                            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
                             "Cannot connect an already connected usb device");
-        return FALSE;
+        goto done;
     }
 
     if (!priv->source) {
-        priv->source = g_usb_source_new(priv->main_context, priv->context, err);
-        if (*err)
-            return FALSE;
+        priv->source = g_usb_source_new(priv->main_context, priv->context, &e);
+        if (e) {
+            g_simple_async_result_take_error(result, e);
+            goto done;
+        }
 
         g_usb_source_set_callback(priv->source,
                                   spice_usb_device_manager_source_callback,
@@ -612,14 +635,37 @@ gboolean spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *self,
         if (spice_usbredir_channel_get_device(channel))
             continue; /* Skip already used channels */
 
-        return spice_usbredir_channel_connect(channel, priv->context,
-                                              (GUsbDevice *)device, err);
+        if (!spice_usbredir_channel_connect(channel, priv->context,
+                                            (GUsbDevice *)device, &e)) {
+            g_simple_async_result_take_error(result, e);
+            goto done;
+        }
+
+        goto done;
     }
 #endif
 
-    g_set_error_literal(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
-                        "No free USB channel");
-    return FALSE;
+    g_simple_async_result_set_error(result,
+                            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            "No free USB channel");
+done:
+    g_simple_async_result_complete_in_idle(result);
+    g_object_unref(result);
+}
+
+gboolean spice_usb_device_manager_connect_device_finish(
+    SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err)
+{
+    GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+    g_return_val_if_fail(g_simple_async_result_is_valid(res, G_OBJECT(self),
+                                     spice_usb_device_manager_connect_device),
+                         FALSE);
+
+    if (g_simple_async_result_propagate_error(simple, err))
+        return FALSE;
+
+    return TRUE;
 }
 
 /**
diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h
index 00f8eb2..6f35bee 100644
--- a/gtk/usb-device-manager.h
+++ b/gtk/usb-device-manager.h
@@ -22,6 +22,7 @@
 #define __SPICE_USB_DEVICE_MANAGER_H__
 
 #include "spice-client.h"
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
@@ -96,9 +97,14 @@ GPtrArray *spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *manager);
 
 gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *manager,
                                                       SpiceUsbDevice *device);
-gboolean spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *manager,
-                                                 SpiceUsbDevice *device,
-                                                 GError **err);
+void spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *manager,
+                                             SpiceUsbDevice *device,
+                                             GCancellable *cancellable,
+                                             GAsyncReadyCallback callback,
+                                             gpointer user_data);
+gboolean spice_usb_device_manager_connect_device_finish(
+    SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err);
+
 void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,
                                                 SpiceUsbDevice *device);
 
-- 
1.7.7.1



More information about the Spice-devel mailing list