<div dir="ltr">+1 (for code)<div>please correct commit message<br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 2, 2015 at 4:41 PM, Kirill Moizik <span dir="ltr"><<a href="mailto:kirill@daynix.com" target="_blank">kirill@daynix.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">we will spawn a separate thread to disconnect usb device, when finish we will update widget to allow further<br>
usb redirection operations<br>
1) expose spice_usbredir_channel_connect_device_async function for asynchronous disconnect<br>
2) threads synchronization<br>
<br>
Signed-off-by: Kirill Moizik <<a href="mailto:kmoizik@redhat.com">kmoizik@redhat.com</a>><br>
---<br>
 src/channel-usbredir-priv.h |  8 ++++-<br>
 src/channel-usbredir.c      | 77 ++++++++++++++++++++++++++++++++++++++-------<br>
 src/map-file                |  1 +<br>
 src/usb-device-manager.c    | 60 ++++++++++++++++++++++++++++++++++-<br>
 src/usb-device-manager.h    |  8 +++++<br>
 src/usb-device-widget.c     | 19 +++++++++--<br>
 6 files changed, 157 insertions(+), 16 deletions(-)<br>
<br>
diff --git a/src/channel-usbredir-priv.h b/src/channel-usbredir-priv.h<br>
index 2c4c6f7..f954377 100644<br>
--- a/src/channel-usbredir-priv.h<br>
+++ b/src/channel-usbredir-priv.h<br>
@@ -33,6 +33,10 @@ G_BEGIN_DECLS<br>
 void spice_usbredir_channel_set_context(SpiceUsbredirChannel *channel,<br>
                                         libusb_context       *context);<br>
<br>
+void spice_usbredir_channel_disconnect_device_async(SpiceUsbredirChannel *channel,<br>
+                                                    GSimpleAsyncResult *simple,<br>
+                                                    GCancellable *cancellable);<br>
+<br>
 /* Note the context must be set, and the channel must be brought up<br>
    (through spice_channel_connect()), before calling this. */<br>
 void spice_usbredir_channel_connect_device_async(<br>
@@ -47,7 +51,9 @@ gboolean spice_usbredir_channel_connect_device_finish(<br>
                                         GAsyncResult         *res,<br>
                                         GError              **err);<br>
<br>
-void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel);<br>
+void spice_usbredir_channel_disconnect_device(GSimpleAsyncResult *simple,<br>
+                                              GObject *object,<br>
+                                              GCancellable *cancellable);<br>
<br>
 libusb_device *spice_usbredir_channel_get_device(SpiceUsbredirChannel *channel);<br>
<br>
diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c<br>
index 97003dc..587f9d1 100644<br>
--- a/src/channel-usbredir.c<br>
+++ b/src/channel-usbredir.c<br>
@@ -79,6 +79,7 @@ struct _SpiceUsbredirChannelPrivate {<br>
     GSimpleAsyncResult *result;<br>
     SpiceUsbAclHelper *acl_helper;<br>
 #endif<br>
+    void* redirect_mutex;<br>
 };<br>
<br>
 static void channel_set_handlers(SpiceChannelClass *klass);<br>
@@ -108,23 +109,51 @@ static void spice_usbredir_channel_init(SpiceUsbredirChannel *channel)<br>
 #ifdef USE_USBREDIR<br>
     channel->priv = SPICE_USBREDIR_CHANNEL_GET_PRIVATE(channel);<br>
 #endif<br>
+    channel->priv->redirect_mutex = usbredir_alloc_lock();<br>
 }<br>
<br>
 #ifdef USE_USBREDIR<br>
+typedef struct _reset_cb_data<br>
+{<br>
+    gboolean migrating;<br>
+} reset_cb_data;<br>
+<br>
+static void spice_usbredir_channel_reset_cb(GObject *gobject,<br>
+                                            GAsyncResult *result,<br>
+                                            gpointer user_data)<br>
+{<br>
+    SpiceChannel *spiceChannel =  SPICE_CHANNEL(gobject);<br>
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(spiceChannel);<br>
+    SpiceUsbredirChannelPrivate *priv = channel->priv;<br>
+    reset_cb_data *data = user_data;<br>
+<br>
+    usbredirhost_close(priv->host);<br>
+    priv->host = NULL;<br>
+    /* Call set_context to re-create the host */<br>
+    spice_usbredir_channel_set_context(channel, priv->context);<br>
+    SPICE_CHANNEL_CLASS(spice_usbredir_channel_parent_class)->channel_reset(spiceChannel, data->migrating);<br>
+    g_object_unref(result);<br>
+    g_free(data);<br>
+}<br>
+<br>
 static void spice_usbredir_channel_reset(SpiceChannel *c, gboolean migrating)<br>
 {<br>
     SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(c);<br>
     SpiceUsbredirChannelPrivate *priv = channel->priv;<br>
<br>
+    GSimpleAsyncResult *result ;<br>
     if (priv->host) {<br>
-        if (priv->state == STATE_CONNECTED)<br>
-            spice_usbredir_channel_disconnect_device(channel);<br>
-        usbredirhost_close(priv->host);<br>
-        priv->host = NULL;<br>
-        /* Call set_context to re-create the host */<br>
-        spice_usbredir_channel_set_context(channel, priv->context);<br>
+        if (priv->state == STATE_CONNECTED){<br>
+            reset_cb_data *data = g_new(reset_cb_data,1);<br>
+            data->migrating = migrating;<br>
+            result = g_simple_async_result_new(G_OBJECT(c),<br>
+                       spice_usbredir_channel_reset_cb, data,<br>
+                       spice_usbredir_channel_reset);<br>
+            spice_usbredir_channel_disconnect_device_async(channel, result, NULL);<br>
+        }<br>
+    } else {<br>
+        SPICE_CHANNEL_CLASS(spice_usbredir_channel_parent_class)->channel_reset(c, migrating);<br>
     }<br>
-    SPICE_CHANNEL_CLASS(spice_usbredir_channel_parent_class)->channel_reset(c, migrating);<br>
 }<br>
 #endif<br>
<br>
@@ -149,7 +178,7 @@ static void spice_usbredir_channel_dispose(GObject *obj)<br>
 {<br>
     SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(obj);<br>
<br>
-    spice_usbredir_channel_disconnect_device(channel);<br>
+    spice_usbredir_channel_disconnect_device(NULL, G_OBJECT(channel), NULL);<br>
<br>
     /* Chain up to the parent class */<br>
     if (G_OBJECT_CLASS(spice_usbredir_channel_parent_class)->dispose)<br>
@@ -182,6 +211,7 @@ static void spice_usbredir_channel_finalize(GObject *obj)<br>
<br>
     if (channel->priv->host)<br>
         usbredirhost_close(channel->priv->host);<br>
+    usbredir_free_lock(channel->priv->redirect_mutex);<br>
<br>
     /* Chain up to the parent class */<br>
     if (G_OBJECT_CLASS(spice_usbredir_channel_parent_class)->finalize)<br>
@@ -380,6 +410,7 @@ void spice_usbredir_channel_connect_device_async(<br>
                                         spice_usbredir_channel_open_device_async,<br>
                                         G_PRIORITY_DEFAULT,<br>
                                         cancellable);<br>
+    g_object_unref(result);<br>
     return;<br>
 #endif<br>
<br>
@@ -406,11 +437,29 @@ gboolean spice_usbredir_channel_connect_device_finish(<br>
     return TRUE;<br>
 }<br>
<br>
-G_GNUC_INTERNAL<br>
-void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel)<br>
+<br>
+void spice_usbredir_channel_disconnect_device_async(SpiceUsbredirChannel *channel,<br>
+                                                    GSimpleAsyncResult *simple,<br>
+                                                    GCancellable *cancellable)<br>
 {<br>
-    SpiceUsbredirChannelPrivate *priv = channel->priv;<br>
+    if (channel) {<br>
+        g_simple_async_result_run_in_thread(simple,<br>
+                                            spice_usbredir_channel_disconnect_device,<br>
+                                            G_PRIORITY_DEFAULT,<br>
+                                            cancellable);<br>
+    } else {<br>
+        g_simple_async_result_complete_in_idle(simple);<br>
+    }<br>
+    g_object_unref(simple);<br>
+}<br>
<br>
+void spice_usbredir_channel_disconnect_device(GSimpleAsyncResult *simple,<br>
+                                              GObject *object,<br>
+                                              GCancellable *cancellable)<br>
+{<br>
+<br>
+    SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(object);<br>
+    SpiceUsbredirChannelPrivate *priv = channel->priv;<br>
     CHANNEL_DEBUG(channel, "disconnecting device from usb channel %p", channel);<br>
<br>
     switch (priv->state) {<br>
@@ -438,7 +487,9 @@ void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel)<br>
                     spice_usb_device_manager_get(session, NULL));<br>
         }<br>
         /* This also closes the libusb handle we passed from open_device */<br>
+        usbredir_lock_lock(channel->priv->redirect_mutex);<br>
         usbredirhost_set_device(priv->host, NULL);<br>
+        usbredir_unlock_lock(channel->priv->redirect_mutex);<br>
         libusb_unref_device(priv->device);<br>
         priv->device = NULL;<br>
         g_boxed_free(spice_usb_device_get_type(), priv->spice_device);<br>
@@ -611,7 +662,7 @@ static gboolean device_error(gpointer user_data)<br>
<br>
     /* Check that the device has not changed before we manage to run */<br>
     if (data->spice_device == priv->spice_device) {<br>
-        spice_usbredir_channel_disconnect_device(channel);<br>
+        spice_usbredir_channel_disconnect_device(NULL, G_OBJECT(channel), NULL);<br>
         spice_usb_device_manager_device_error(<br>
                 spice_usb_device_manager_get(<br>
                     spice_channel_get_session(SPICE_CHANNEL(channel)), NULL),<br>
@@ -650,7 +701,9 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in)<br>
     priv->read_buf = buf;<br>
     priv->read_buf_size = size;<br>
<br>
+    usbredir_lock_lock(priv->redirect_mutex);<br>
     r = usbredirhost_read_guest_data(priv->host);<br>
+    usbredir_unlock_lock(priv->redirect_mutex);<br>
     if (r != 0) {<br>
         SpiceUsbDevice *spice_device = priv->spice_device;<br>
         gchar *desc;<br>
diff --git a/src/map-file b/src/map-file<br>
index f9883b2..d3b55f0 100644<br>
--- a/src/map-file<br>
+++ b/src/map-file<br>
@@ -119,6 +119,7 @@ spice_usb_device_get_libusb_device;<br>
 spice_usb_device_get_type;<br>
 spice_g_udev_set_redirecting;<br>
 spice_g_udev_handle_device_change;<br>
+spice_usb_device_manager_disconnect_device_async;<br>
 spice_usb_device_manager_set_redirecting;<br>
 spice_usb_device_manager_get_redirecting;<br>
 spice_usb_device_manager_can_redirect_device;<br>
diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c<br>
index db4944f..106330f 100644<br>
--- a/src/usb-device-manager.c<br>
+++ b/src/usb-device-manager.c<br>
@@ -1597,6 +1597,64 @@ gboolean spice_usb_device_manager_connect_device_finish(<br>
<br>
     return TRUE;<br>
 }<br>
+typedef struct _disconnect_cb_data<br>
+{<br>
+    SpiceUsbDeviceManager  *self;<br>
+    GSimpleAsyncResult     *result;<br>
+    SpiceUsbDevice         *device;<br>
+} disconnect_cb_data;<br>
+<br>
+static<br>
+void spice_usb_device_manager_disconnect_device_async_cb(GObject *gobject,<br>
+                                                    GAsyncResult *channel_res,<br>
+                                                    gpointer user_data)<br>
+{<br>
+    disconnect_cb_data    *data    = user_data;<br>
+    SpiceUsbDeviceManager *self    = SPICE_USB_DEVICE_MANAGER(data->self);<br>
+    GSimpleAsyncResult    *result  = G_SIMPLE_ASYNC_RESULT(data->result);<br>
+<br>
+#ifdef G_OS_WIN32<br>
+    if (self->priv->use_usbclerk) {<br>
+        spice_usb_device_manager_driver_uninstall_async(self, data->device);<br>
+    }<br>
+#endif<br>
+    g_simple_async_result_complete(result);<br>
+    g_object_unref(result);<br>
+    g_free(data);<br>
+}<br>
+<br>
+void spice_usb_device_manager_disconnect_device_async(SpiceUsbDeviceManager *self,<br>
+                                                      SpiceUsbDevice *device,<br>
+                                                      GCancellable *cancellable,<br>
+                                                      GAsyncReadyCallback callback,<br>
+                                                      gpointer user_data)<br>
+{<br>
+    GSimpleAsyncResult *nested;<br>
+    GSimpleAsyncResult *result;<br>
+    g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));<br>
+<br>
+    g_return_if_fail(device != NULL);<br>
+<br>
+    SPICE_DEBUG("disconnecting device %p", device);<br>
+<br>
+#ifdef USE_USBREDIR<br>
+    SpiceUsbredirChannel *channel;<br>
+<br>
+    channel = spice_usb_device_manager_get_channel_for_dev(self, device);<br>
+    nested  = g_simple_async_result_new(G_OBJECT(self), callback, user_data,<br>
+                              spice_usb_device_manager_disconnect_device_async);<br>
+    disconnect_cb_data *data = g_new(disconnect_cb_data,1);<br>
+    data->self = self;<br>
+    data->result = nested;<br>
+    data->device = device;<br>
+<br>
+    result = g_simple_async_result_new(G_OBJECT(channel),<br>
+                       spice_usb_device_manager_disconnect_device_async_cb, data,<br>
+                       spice_usb_device_manager_disconnect_device_async);<br>
+<br>
+    spice_usbredir_channel_disconnect_device_async(channel,result,cancellable);<br>
+#endif<br>
+}<br>
<br>
 /**<br>
  * spice_usb_device_manager_disconnect_device:<br>
@@ -1618,7 +1676,7 @@ void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,<br>
<br>
     channel = spice_usb_device_manager_get_channel_for_dev(self, device);<br>
     if (channel)<br>
-        spice_usbredir_channel_disconnect_device(channel);<br>
+        spice_usbredir_channel_disconnect_device(NULL, G_OBJECT(channel), NULL);<br>
<br>
 #ifdef G_OS_WIN32<br>
     if (self->priv->use_usbclerk) {<br>
diff --git a/src/usb-device-manager.h b/src/usb-device-manager.h<br>
index dca374d..abe80f7 100644<br>
--- a/src/usb-device-manager.h<br>
+++ b/src/usb-device-manager.h<br>
@@ -106,6 +106,14 @@ void spice_usb_device_manager_connect_device_async(<br>
                                              GCancellable *cancellable,<br>
                                              GAsyncReadyCallback callback,<br>
                                              gpointer user_data);<br>
+<br>
+void spice_usb_device_manager_disconnect_device_async(<br>
+                                             SpiceUsbDeviceManager *manager,<br>
+                                             SpiceUsbDevice *device,<br>
+                                             GCancellable *cancellable,<br>
+                                             GAsyncReadyCallback callback,<br>
+                                             gpointer user_data);<br>
+<br>
 gboolean spice_usb_device_manager_connect_device_finish(<br>
     SpiceUsbDeviceManager *self, GAsyncResult *res, GError **err);<br>
<br>
diff --git a/src/usb-device-widget.c b/src/usb-device-widget.c<br>
index 4c466ca..c50c3b6 100644<br>
--- a/src/usb-device-widget.c<br>
+++ b/src/usb-device-widget.c<br>
@@ -450,6 +450,17 @@ static void set_redirecting(SpiceUsbDeviceWidget *self, gboolean val)<br>
                           set_sensitive_all, (gpointer) &sensitive);<br>
 }<br>
<br>
+static void disconnect_cb(GObject *gobject, GAsyncResult *res, gpointer user_data)<br>
+{<br>
+    connect_cb_data *data = user_data;<br>
+    SpiceUsbDeviceWidget *self = data->self;<br>
+    set_redirecting (self,FALSE);<br>
+    spice_usb_device_widget_update_status(self);<br>
+    g_object_unref(data->check);<br>
+    g_object_unref(data->self);<br>
+    g_free(data);<br>
+}<br>
+<br>
 static void connect_cb(GObject *gobject, GAsyncResult *res, gpointer user_data)<br>
 {<br>
     SpiceUsbDeviceManager *manager = SPICE_USB_DEVICE_MANAGER(gobject);<br>
@@ -501,8 +512,12 @@ static void checkbox_clicked_cb(GtkWidget *check, gpointer user_data)<br>
                                                       connect_cb,<br>
                                                       data);<br>
     } else {<br>
-        spice_usb_device_manager_disconnect_device(priv->manager,<br>
-                                                   device);<br>
+        spice_usb_device_manager_disconnect_device_async(priv->manager,<br>
+                                                         device,<br>
+                                                         NULL,<br>
+                                                         disconnect_cb,<br>
+                                                         data);<br>
+<br>
     }<br>
     spice_usb_device_widget_update_status(self);<br>
 }<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.1.0<br>
<br>
</font></span></blockquote></div><br></div></div></div>