summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Moizik <kmoizik@redhat.com>2016-03-08 16:05:53 +0200
committerJonathon Jongsma <jjongsma@redhat.com>2016-03-24 11:00:01 -0500
commit4eea5f3afeb4ad8c5f47cc03793474602696ca29 (patch)
tree7c6b4c90896b42a1494497dd0040edd9c141f871
parent7fec6cd96176290ffe475612535d139936d31c0b (diff)
usbredir: Spawn a different thread for device redirection flow
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 implicitly via usbredirhost_set_device(..., NULL) from spice_usbredir_channel_disconnect_device(). 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 when usbdk is used. Following commits also move usbredirhost_set_device(..., NULL) call to separate threads. Since this commit introduces additional execution contexts running in parallel to the main thread there 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 are either thread safe or already performed by a separate thread and protected by locks as needed. As for channels and usbredir, in order to achieve thread safety additional locks were introduced by previous patches in preparation to adding asynchronous contexts: 1. Channel objects data accesses from different threads protected with a new lock (device_connect_mutex); 2. Handling usbredir messages protected by the same new lock in order to ensure there are no messages processing flows in progress when device gets connected or disconnected. Signed-off-by: Kirill Moizik <kmoizik@redhat.com> Signed-off-by: Dmitry Fleytman <dfleytma@redhat.com> Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
-rw-r--r--src/channel-usbredir.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c
index a2a9343..6ced764 100644
--- a/src/channel-usbredir.c
+++ b/src/channel-usbredir.c
@@ -319,6 +319,36 @@ static void spice_usbredir_channel_open_acl_cb(
}
#endif
+#ifndef USE_POLKIT
+static void
+_open_device_async_cb(GTask *task,
+ gpointer object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GError *err = NULL;
+ SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object);
+ SpiceUsbredirChannelPrivate *priv = channel->priv;
+
+ spice_usbredir_channel_lock(channel);
+
+ if (!spice_usbredir_channel_open_device(channel, &err)) {
+ libusb_unref_device(priv->device);
+ priv->device = NULL;
+ g_boxed_free(spice_usb_device_get_type(), priv->spice_device);
+ priv->spice_device = NULL;
+ }
+
+ spice_usbredir_channel_unlock(channel);
+
+ if (err) {
+ g_task_return_error(task, err);
+ } else {
+ g_task_return_boolean(task, TRUE);
+ }
+}
+#endif
+
G_GNUC_INTERNAL
void spice_usbredir_channel_connect_device_async(
SpiceUsbredirChannel *channel,
@@ -330,9 +360,6 @@ void spice_usbredir_channel_connect_device_async(
{
SpiceUsbredirChannelPrivate *priv = channel->priv;
GTask *task;
-#ifndef USE_POLKIT
- GError *err = NULL;
-#endif
g_return_if_fail(SPICE_IS_USBREDIR_CHANNEL(channel));
g_return_if_fail(device != NULL);
@@ -375,15 +402,7 @@ void spice_usbredir_channel_connect_device_async(
channel);
return;
#else
- if (!spice_usbredir_channel_open_device(channel, &err)) {
- g_task_return_error(task, err);
- libusb_unref_device(priv->device);
- priv->device = NULL;
- g_boxed_free(spice_usb_device_get_type(), priv->spice_device);
- priv->spice_device = NULL;
- } else {
- g_task_return_boolean(task, TRUE);
- }
+ g_task_run_in_thread(task, _open_device_async_cb);
#endif
done: