[Spice-devel] [PATCH spice-gtk 6/8] channel-usbredir: Make spice_usbredir_channel_connect async

Hans de Goede hdegoede at redhat.com
Wed Nov 16 09:49:49 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 |   14 ++++++++---
 gtk/channel-usbredir.c      |   49 ++++++++++++++++++++++++++++++++++++-------
 gtk/usb-device-manager.c    |   29 +++++++++++++++++++------
 3 files changed, 73 insertions(+), 19 deletions(-)

diff --git a/gtk/channel-usbredir-priv.h b/gtk/channel-usbredir-priv.h
index 05988e1..8bb42a5 100644
--- a/gtk/channel-usbredir-priv.h
+++ b/gtk/channel-usbredir-priv.h
@@ -28,10 +28,16 @@
 
 G_BEGIN_DECLS
 
-gboolean spice_usbredir_channel_connect(SpiceUsbredirChannel *channel,
-                                        GUsbContext *context,
-                                        GUsbDevice *device,
-                                        GError **err);
+void spice_usbredir_channel_connect_async(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 4194b48..fd54594 100644
--- a/gtk/channel-usbredir.c
+++ b/gtk/channel-usbredir.c
@@ -153,27 +153,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_async(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_channel_disconnect(SPICE_CHANNEL(channel), SPICE_CHANNEL_NONE);
+    result = g_simple_async_result_new(G_OBJECT(channel), callback, user_data,
+                                       spice_usbredir_channel_connect_async);
+
+    if (priv->device) {
+        g_simple_async_result_set_error(result,
+                            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+                            "Error channel is busy");
+        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_async),
+                         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 9b02066..b1d6c95 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_async(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_async(channel,
+                                 priv->context,
+                                 (GUsbDevice *)device,
+                                 cancellable,
+                                 spice_usb_device_manager_channel_connect_cb,
+                                 result);
+        return;
     }
 #endif
 
-- 
1.7.7.3



More information about the Spice-devel mailing list