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); -- 1.7.11.7 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel