<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>