[Spice-devel] [PATCH spice-gtk 1/3] channel: add flush_async()
Marc-André Lureau
marcandre.lureau at gmail.com
Fri Nov 30 04:43:44 PST 2012
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
More information about the Spice-devel
mailing list