[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