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