[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