[Spice-devel] [PATCH spice-gtk 3/5] channel-usbredir.c: Make spice_usbredir_channel_connect async

Hans de Goede hdegoede at redhat.com
Tue Nov 15 07:30:59 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 -> Make spice_usbredir_channel_connect() async

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

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 gtk/channel-usbredir-priv.h |   13 ++++++++---
 gtk/channel-usbredir.c      |   49 ++++++++++++++++++++++++++++++++++++-------
 gtk/usb-device-manager.c    |   29 +++++++++++++++++++------
 3 files changed, 72 insertions(+), 19 deletions(-)

diff --git a/gtk/channel-usbredir-priv.h b/gtk/channel-usbredir-priv.h
index 05988e1..700bad2 100644
--- a/gtk/channel-usbredir-priv.h
+++ b/gtk/channel-usbredir-priv.h
@@ -28,10 +28,15 @@
 
 G_BEGIN_DECLS
 
-gboolean spice_usbredir_channel_connect(SpiceUsbredirChannel *channel,
-                                        GUsbContext *context,
-                                        GUsbDevice *device,
-                                        GError **err);
+void spice_usbredir_channel_connect(SpiceUsbredirChannel *channel,
+                                    GUsbContext          *context,
+                                    GUsbDevice           *device,
+                                    GCancellable         *cancellable,
+                                    GAsyncReadyCallback   callback,
+                                    gpointer              user_data);
+gboolean spice_usbredir_channel_connect_finish(SpiceUsbredirChannel *channel,
+                                               GAsyncResult         *res,
+                                               GError              **err);
 void spice_usbredir_channel_disconnect(SpiceUsbredirChannel *channel);
 
 GUsbDevice *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel);
diff --git a/gtk/channel-usbredir.c b/gtk/channel-usbredir.c
index 474ffb5..94c801a 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -150,27 +150,60 @@ static gboolean spice_usbredir_channel_open_device(
 }
 
 G_GNUC_INTERNAL
-gboolean spice_usbredir_channel_connect(SpiceUsbredirChannel *channel,
-                                        GUsbContext *context,
-                                        GUsbDevice *device,
-                                        GError **err)
+void spice_usbredir_channel_connect(SpiceUsbredirChannel *channel,
+                                    GUsbContext          *context,
+                                    GUsbDevice           *device,
+                                    GCancellable         *cancellable,
+                                    GAsyncReadyCallback   callback,
+                                    gpointer              user_data)
 {
     SpiceUsbredirChannelPrivate *priv = channel->priv;
+    GSimpleAsyncResult *result;
+    GError *err = NULL;
 
-    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+    g_return_if_fail(SPICE_IS_USBREDIR_CHANNEL(channel));
+    g_return_if_fail(context != NULL);
+    g_return_if_fail(device != NULL);
 
     SPICE_DEBUG("connecting usb channel %p", channel);
 
-    spice_usbredir_channel_disconnect(channel);
+    result = g_simple_async_result_new(G_OBJECT(channel), callback, user_data,
+                                       spice_usbredir_channel_connect);
+
+    if (priv->device) {
+        g_simple_async_result_set_error(result,
+                            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            "Cannot connect an already connected usb channel");
+        goto done;
+    }
 
     priv->context = g_object_ref(context);
     priv->device  = g_object_ref(device);
-    if (!spice_usbredir_channel_open_device(channel, err)) {
+    if (!spice_usbredir_channel_open_device(channel, &err)) {
+        g_simple_async_result_take_error(result, err);
         g_clear_object(&priv->context);
         g_clear_object(&priv->device);
-        return FALSE;
     }
 
+done:
+    g_simple_async_result_complete_in_idle(result);
+    g_object_unref(result);
+}
+
+G_GNUC_INTERNAL
+gboolean spice_usbredir_channel_connect_finish(SpiceUsbredirChannel *channel,
+                                               GAsyncResult         *res,
+                                               GError              **err)
+{
+    GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(res);
+
+    g_return_val_if_fail(g_simple_async_result_is_valid(res, G_OBJECT(channel),
+                                     spice_usbredir_channel_connect),
+                         FALSE);
+
+    if (g_simple_async_result_propagate_error(result, err))
+        return FALSE;
+
     return TRUE;
 }
 
diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c
index dd2e0c4..7f1cc12 100644
--- a/gtk/usb-device-manager.c
+++ b/gtk/usb-device-manager.c
@@ -480,6 +480,21 @@ static void spice_usb_device_manager_dev_removed(GUsbDeviceList *devlist,
     g_signal_emit(manager, signals[DEVICE_REMOVED], 0, device);
     g_ptr_array_remove(priv->devices, device);
 }
+
+static void spice_usb_device_manager_channel_connect_cb(
+    GObject *gobject, GAsyncResult *channel_res, gpointer user_data)
+{
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(gobject);
+    GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(user_data);
+    GError *err = NULL;
+
+    spice_usbredir_channel_connect_finish(channel, channel_res, &err);
+    if (err) {
+        g_simple_async_result_take_error(result, err);
+    }
+    g_simple_async_result_complete(result);
+    g_object_unref(result);
+}
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -635,13 +650,13 @@ void spice_usb_device_manager_connect_device(SpiceUsbDeviceManager *self,
         if (spice_usbredir_channel_get_device(channel))
             continue; /* Skip already used channels */
 
-        if (!spice_usbredir_channel_connect(channel, priv->context,
-                                            (GUsbDevice *)device, &e)) {
-            g_simple_async_result_take_error(result, e);
-            goto done;
-        }
-
-        goto done;
+        spice_usbredir_channel_connect(channel,
+                                 priv->context,
+                                 (GUsbDevice *)device,
+                                 cancellable,
+                                 spice_usb_device_manager_channel_connect_cb,
+                                 result);
+        return;
     }
 #endif
 
-- 
1.7.7.1



More information about the Spice-devel mailing list