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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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);

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/spice-devel



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]