Re: [PATCH v4 07/16] usbredir: Spawn a different thread for device redirection flow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 23 Sep 2015, at 15:08 PM, Christophe Fergeau <cfergeau@xxxxxxxxxx> wrote:

On Sun, Aug 16, 2015 at 03:35:44PM +0300, Dmitry Fleytman wrote:
From: Kirill Moizik <kmoizik@xxxxxxxxxx>

On Windows when using usbdk, opening and closing USB device handle,
i.e. calling libusb_open()/libusb_unref_device() can block for a few
seconds (3-5 second more specifically on patch author's HW).

libusb_open() is called by spice_usbredir_channel_open_device().

libusb_unref_device() is called implicitely via
usbredirhost_set_device(..., NULL) from
spice_usbredir_channel_disconnect_device().

Is this libusb_unref_device() or libusb_close() which can block?

spice_usbredir_channel_disconnect_device() does:

/* This also closes the libusb handle we passed from open_device */
usbredirhost_set_device(priv->host, NULL);
libusb_unref_device(priv->device);

so the libusb_close() call is done by usbredirhost_set_device() while
the libusb_unref_device() call is done explicitly in
spice_usbredir_channel_disconnect_device()

If what is blocking is libusb_unref_device(), I would not bother making
disconnect() async by running in a thread, but I'd just spawn a thread
to do the libusb_unref_device() call. I don't think it's important that
we wait until the call completes, so _disconnect() would not need to
change apart from this delayed unref.

If the blocking call is libusb_close(), I don't know if the same
approach can be used with usbredirhost_set_device? Has this been tried?

The blocking call is libusb_close().
It is safer to wait for device close operation to complete, otherwise re-connection to the same device may be initiated while close is still in progress which may bring execution to a different corner cases...


Christophe



Both these calls happen on the main thread. If it blocks,
this causes the UI to freeze.

This commit makes sure libusb_open() is called from a different
thread to avoid blocking the mainloop freezes when usbdk is used.

Following commits also move usbredirhost_set_device(..., NULL) call
to the different threads.

Since this commit introduces additional execution contexts running in
parallell to the main thread threre are thread safety concerns to be secured.
Mainly there are 3 types of objects accessed by newly introduced threads:
 1. libusb contexts
 2. usbredir context
 3. redirection channels

Fortunately libusb accesses either thread safe of already performed by
a separate thread and protected by locks as needed.

As for channels and usbredir, in order to achieve thread safety this patch introduces
additional locks and references, namely:

1. To make sure channel objects are not disposed while redirection in progress,
  they are referenced on flow start and unreferenced on flow completion;
2. Channel objects data accesses from different threads protected with a
  new lock (flows_mutex);
3. Handling usbredir messages protected by the same new lock in order to
  ensure there are no messages processing flows in progres when device gets
  connected or disconneced.

Signed-off-by: Kirill Moizik <kmoizik@xxxxxxxxxx>
Signed-off-by: Dmitry Fleytman <dfleytma@xxxxxxxxxx>
---
src/channel-usbredir.c | 41 ++++++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c
index bbfd2b0..44da3ce 100644
--- a/src/channel-usbredir.c
+++ b/src/channel-usbredir.c
@@ -315,6 +315,27 @@ static void spice_usbredir_channel_open_acl_cb(
}
#endif

+#ifndef USE_POLKIT
+static void
+_open_device_async_cb(GSimpleAsyncResult *simple,
+                      GObject *object,
+                      GCancellable *cancellable)
+{
+    GError *err = NULL;
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object);
+    SpiceUsbredirChannelPrivate *priv = channel->priv;
+    g_mutex_lock(priv->flows_mutex);
+    if (!spice_usbredir_channel_open_device(channel, &err)) {
+        g_simple_async_result_take_error(simple, err);
+        libusb_unref_device(priv->device);
+        priv->device = NULL;
+        g_boxed_free(spice_usb_device_get_type(), priv->spice_device);
+        priv->spice_device = NULL;
+     }
+    g_mutex_unlock(priv->flows_mutex);
+}
+#endif
+
G_GNUC_INTERNAL
void spice_usbredir_channel_connect_device_async(
                                          SpiceUsbredirChannel *channel,
@@ -324,15 +345,14 @@ void spice_usbredir_channel_connect_device_async(
                                          GAsyncReadyCallback   callback,
                                          gpointer              user_data)
{
-    SpiceUsbredirChannelPrivate *priv = channel->priv;
+    SpiceUsbredirChannelPrivate *priv;
    GSimpleAsyncResult *result;
-#if ! USE_POLKIT
-    GError *err = NULL;
-#endif

    g_return_if_fail(SPICE_IS_USBREDIR_CHANNEL(channel));
    g_return_if_fail(device != NULL);

+    priv = channel->priv;
+
    CHANNEL_DEBUG(channel, "connecting usb channel %p", channel);

    result = g_simple_async_result_new(G_OBJECT(channel), callback, user_data,
@@ -369,13 +389,12 @@ void spice_usbredir_channel_connect_device_async(
                                  channel);
    return;
#else
-    if (!spice_usbredir_channel_open_device(channel, &err)) {
-        g_simple_async_result_take_error(result, err);
-        libusb_unref_device(priv->device);
-        priv->device = NULL;
-        g_boxed_free(spice_usb_device_get_type(), priv->spice_device);
-        priv->spice_device = NULL;
-    }
+    g_simple_async_result_run_in_thread(result,
+                                        _open_device_async_cb,
+                                        G_PRIORITY_DEFAULT,
+                                        cancellable);
+    g_object_unref(result);
+    return;
#endif

done:
-- 
2.4.3

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/spice-devel

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/spice-devel

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]