[Spice-devel] [PATCH spice-gtk 1/3] channel: add flush_async()

Hans de Goede hdegoede at redhat.com
Sun Dec 2 03:13:03 PST 2012


Hi,

Looks good to me, ACK series

Regards,

Hans


On 11/30/2012 01:43 PM, Marc-André Lureau wrote:
> Add spice_channel_flush_async() that asynchronously will write all the
> pending channel data.
> ---
>   doc/reference/spice-gtk-sections.txt |   2 +
>   gtk/map-file                         |   2 +
>   gtk/spice-channel-priv.h             |   1 +
>   gtk/spice-channel.c                  | 100 +++++++++++++++++++++++++++++++++++
>   gtk/spice-channel.h                  |   4 +-
>   5 files changed, 108 insertions(+), 1 deletion(-)
>
> diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
> index 60e287a..87d4225 100644
> --- a/doc/reference/spice-gtk-sections.txt
> +++ b/doc/reference/spice-gtk-sections.txt
> @@ -99,6 +99,8 @@ spice_channel_test_capability
>   spice_channel_test_common_capability
>   spice_channel_type_to_string
>   spice_channel_set_capability
> +spice_channel_flush_async
> +spice_channel_flush_finish
>   <SUBSECTION Standard>
>   SPICE_TYPE_CHANNEL_EVENT
>   spice_channel_event_get_type
> diff --git a/gtk/map-file b/gtk/map-file
> index ed2c07f..79ad9d2 100644
> --- a/gtk/map-file
> +++ b/gtk/map-file
> @@ -14,6 +14,8 @@ spice_channel_set_capability;
>   spice_channel_test_capability;
>   spice_channel_test_common_capability;
>   spice_channel_type_to_string;
> +spice_channel_flush_async;
> +spice_channel_flush_finish;
>   spice_client_error_quark;
>   spice_cursor_channel_get_type;
>   spice_display_channel_get_type;
> diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
> index a769ef8..41a1b34 100644
> --- a/gtk/spice-channel-priv.h
> +++ b/gtk/spice-channel-priv.h
> @@ -134,6 +134,7 @@ struct _SpiceChannelPrivate {
>
>       gsize                       total_read_bytes;
>       uint64_t                    last_message_serial;
> +    GSList                      *flushing;
>   };
>
>   SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel);
> diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
> index 06667d4..c9c4639 100644
> --- a/gtk/spice-channel.c
> +++ b/gtk/spice-channel.c
> @@ -1971,6 +1971,22 @@ void spice_channel_destroy(SpiceChannel *channel)
>       g_object_unref(channel);
>   }
>
> +/* any context */
> +static void spice_channel_flushed(SpiceChannel *channel, gboolean success)
> +{
> +    SpiceChannelPrivate *c = channel->priv;
> +    GSList *l;
> +
> +    for (l = c->flushing; l != NULL; l = l->next) {
> +        GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(l->data);
> +        g_simple_async_result_set_op_res_gboolean(result, success);
> +        g_simple_async_result_complete_in_idle(result);
> +    }
> +
> +    g_slist_free_full(c->flushing, g_object_unref);
> +    c->flushing = NULL;
> +}
> +
>   /* coroutine context */
>   static void spice_channel_iterate_write(SpiceChannel *channel)
>   {
> @@ -1984,6 +2000,8 @@ static void spice_channel_iterate_write(SpiceChannel *channel)
>           if (out)
>               spice_channel_write_msg(channel, out);
>       } while (out);
> +
> +    spice_channel_flushed(channel, TRUE);
>   }
>
>   /* coroutine context */
> @@ -2444,6 +2462,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
>
>       STATIC_MUTEX_LOCK(c->xmit_queue_lock);
>       c->xmit_queue_blocked = TRUE; /* Disallow queuing new messages */
> +    gboolean was_empty = g_queue_is_empty(&c->xmit_queue);
>       g_queue_foreach(&c->xmit_queue, (GFunc)spice_msg_out_unref, NULL);
>       g_queue_clear(&c->xmit_queue);
>       if (c->xmit_queue_wakeup_id) {
> @@ -2451,6 +2470,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
>           c->xmit_queue_wakeup_id = 0;
>       }
>       STATIC_MUTEX_UNLOCK(c->xmit_queue_lock);
> +    spice_channel_flushed(channel, was_empty);
>
>       g_array_set_size(c->remote_common_caps, 0);
>       g_array_set_size(c->remote_caps, 0);
> @@ -2722,3 +2742,83 @@ static void spice_channel_send_migration_handshake(SpiceChannel *channel)
>           c->state = SPICE_CHANNEL_STATE_MIGRATING;
>       }
>   }
> +
> +/**
> + * spice_channel_flush_async:
> + * @channel: a #SpiceChannel
> + * @cancellable: (allow-none): optional GCancellable object, %NULL to ignore
> + * @callback: (scope async): callback to call when the request is satisfied
> + * @user_data: (closure): the data to pass to callback function
> + *
> + * Forces an asynchronous write of all user-space buffered data for
> + * the given channel.
> + *
> + * When the operation is finished callback will be called. You can
> + * then call spice_channel_flush_finish() to get the result of the
> + * operation.
> + *
> + * Since: 0.15
> + **/
> +void spice_channel_flush_async(SpiceChannel *self, GCancellable *cancellable,
> +                               GAsyncReadyCallback callback, gpointer user_data)
> +{
> +    GSimpleAsyncResult *simple;
> +    SpiceChannelPrivate *c;
> +    gboolean was_empty;
> +
> +    g_return_if_fail(SPICE_IS_CHANNEL(self));
> +    c = self->priv;
> +
> +    if (!c->state == SPICE_CHANNEL_STATE_READY) {
> +        g_simple_async_report_error_in_idle(G_OBJECT(self), callback, user_data,
> +            SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
> +            "The channel is not ready yet");
> +        return;
> +    }
> +
> +    simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
> +                                       spice_channel_flush_async);
> +
> +    STATIC_MUTEX_LOCK(c->xmit_queue_lock);
> +    was_empty = g_queue_is_empty(&c->xmit_queue);
> +    STATIC_MUTEX_UNLOCK(c->xmit_queue_lock);
> +    if (was_empty) {
> +        g_simple_async_result_set_op_res_gboolean(simple, TRUE);
> +        g_simple_async_result_complete_in_idle(simple);
> +        return;
> +    }
> +
> +    c->flushing = g_slist_append(c->flushing, simple);
> +}
> +
> +/**
> + * spice_channel_flush_finish:
> + * @channel: a #SpiceChannel
> + * @result: a #GAsyncResult
> + * @error: a #GError location to store the error occurring, or %NULL
> + * to ignore.
> + *
> + * Finishes flushing a channel.
> + *
> + * Returns: %TRUE if flush operation succeeded, %FALSE otherwise.
> + * Since: 0.15
> + **/
> +gboolean spice_channel_flush_finish(SpiceChannel *self, GAsyncResult *result,
> +                                    GError **error)
> +{
> +    GSimpleAsyncResult *simple;
> +
> +    g_return_val_if_fail(SPICE_IS_CHANNEL(self), FALSE);
> +    g_return_val_if_fail(result != NULL, FALSE);
> +
> +    simple = (GSimpleAsyncResult *)result;
> +
> +    if (g_simple_async_result_propagate_error(simple, error))
> +        return -1;
> +
> +    g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self),
> +                                                        spice_channel_flush_async), FALSE);
> +
> +    CHANNEL_DEBUG(self, "flushed finished!");
> +    return g_simple_async_result_get_op_res_gboolean(simple);
> +}
> diff --git a/gtk/spice-channel.h b/gtk/spice-channel.h
> index d40b844..52ecd97 100644
> --- a/gtk/spice-channel.h
> +++ b/gtk/spice-channel.h
> @@ -20,6 +20,7 @@
>
>   G_BEGIN_DECLS
>
> +#include <gio/gio.h>
>   #include "spice-types.h"
>   #include "spice-glib-enums.h"
>   #include "spice-util.h"
> @@ -112,7 +113,8 @@ gboolean spice_channel_open_fd(SpiceChannel *channel, int fd);
>   void spice_channel_disconnect(SpiceChannel *channel, SpiceChannelEvent reason);
>   gboolean spice_channel_test_capability(SpiceChannel *channel, guint32 cap);
>   gboolean spice_channel_test_common_capability(SpiceChannel *channel, guint32 cap);
> -
> +void spice_channel_flush_async(SpiceChannel *channel, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
> +gboolean spice_channel_flush_finish(SpiceChannel *channel, GAsyncResult *result, GError **error);
>   #ifndef SPICE_DISABLE_DEPRECATED
>   SPICE_DEPRECATED
>   void spice_channel_set_capability(SpiceChannel *channel, guint32 cap);
>


More information about the Spice-devel mailing list