[Spice-devel] [spice-gtk v3 02/16] file-xfer: introduce flush_callback and flush_done

Victor Toso victortoso at redhat.com
Mon May 30 09:54:58 UTC 2016


By introducing a flush_callback such as SpiceFileTransferTaskFlushCb
SpiceFileTransferTask becomes agnostic on how channel-main flushes
the data.

The spice_file_transfer_task_flush_done() function is now introduced
to tell SpiceFileTransferTask that flushing is over and we can read
more data if no error has happened.

This change is related to split SpiceFileTransferTask from
channel-main.
---
 src/channel-main.c | 143 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 88 insertions(+), 55 deletions(-)

diff --git a/src/channel-main.c b/src/channel-main.c
index 89675d5..702f146 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -54,9 +54,14 @@
 
 typedef struct spice_migrate spice_migrate;
 
+typedef void (*SpiceFileTransferTaskFlushCb)(SpiceFileTransferTask *xfer_task,
+                                             void *buffer,
+                                             gssize count,
+                                             gpointer user_data);
 static guint32 spice_file_transfer_task_get_id(SpiceFileTransferTask *self);
 static SpiceMainChannel *spice_file_transfer_task_get_channel(SpiceFileTransferTask *self);
 static GCancellable *spice_file_transfer_task_get_cancellable(SpiceFileTransferTask *self);
+static void spice_file_transfer_task_flush_done(SpiceFileTransferTask *self, GError *error);
 
 /**
  * SECTION:file-transfer-task
@@ -89,6 +94,8 @@ struct _SpiceFileTransferTask
     GCancellable                   *cancellable;
     GFileProgressCallback          progress_callback;
     gpointer                       progress_callback_data;
+    SpiceFileTransferTaskFlushCb   flush_callback;
+    gpointer                       flush_callback_data;
     GAsyncReadyCallback            callback;
     gpointer                       user_data;
     char                           *buffer;
@@ -1859,73 +1866,49 @@ static void file_xfer_data_flushed_cb(GObject *source_object,
     SpiceMainChannel *channel = (SpiceMainChannel *)source_object;
     GError *error = NULL;
 
-    self->pending = FALSE;
     file_xfer_flush_finish(channel, res, &error);
-    if (error || self->error) {
-        spice_file_transfer_task_completed(self, error);
-        return;
-    }
-
-    if (spice_util_get_debug()) {
-        const GTimeSpan interval = 20 * G_TIME_SPAN_SECOND;
-        gint64 now = g_get_monotonic_time();
-
-        if (interval < now - self->last_update) {
-            gchar *basename = g_file_get_basename(self->file);
-            self->last_update = now;
-            SPICE_DEBUG("transferred %.2f%% of the file %s",
-                        100.0 * self->read_bytes / self->file_size, basename);
-            g_free(basename);
-        }
-    }
-
-    if (self->progress_callback) {
-        goffset read = 0;
-        goffset total = 0;
-        SpiceMainChannel *main_channel = self->channel;
-        GHashTableIter iter;
-        gpointer key, value;
-
-        /* since the progress_callback does not have a parameter to indicate
-         * which file the progress is associated with, report progress on all
-         * current transfers */
-        g_hash_table_iter_init(&iter, main_channel->priv->file_xfer_tasks);
-        while (g_hash_table_iter_next(&iter, &key, &value)) {
-            SpiceFileTransferTask *t = (SpiceFileTransferTask *)value;
-            read += t->read_bytes;
-            total += t->file_size;
-        }
-
-        self->progress_callback(read, total, self->progress_callback_data);
-    }
-
-    /* Read more data */
-    file_xfer_continue_read(self);
+    spice_file_transfer_task_flush_done(self, error);
 }
 
-static void file_xfer_queue(SpiceFileTransferTask *self, int data_size)
+static void file_xfer_queue(SpiceFileTransferTask *xfer_task, void *buffer, int data_size)
 {
     VDAgentFileXferDataMessage msg;
     SpiceMainChannel *channel;
 
-    channel = spice_file_transfer_task_get_channel(self);
+    channel = spice_file_transfer_task_get_channel(xfer_task);
     g_return_if_fail(channel != NULL);
 
-    msg.id = spice_file_transfer_task_get_id(self);
+    msg.id = spice_file_transfer_task_get_id(xfer_task);
     msg.size = data_size;
     agent_msg_queue_many(channel, VD_AGENT_FILE_XFER_DATA,
                          &msg, sizeof(msg),
-                         self->buffer, data_size, NULL);
+                         buffer, data_size, NULL);
     spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
 }
 
+static void file_xfer_flush_callback(SpiceFileTransferTask *xfer_task,
+                                     void *buffer,
+                                     gssize count,
+                                     gpointer user_data)
+{
+    SpiceMainChannel *main_channel;
+    GCancellable *cancellable;
+
+    file_xfer_queue(xfer_task, buffer, count);
+    if (count == 0)
+        return;
+
+    main_channel = spice_file_transfer_task_get_channel(xfer_task);
+    cancellable = spice_file_transfer_task_get_cancellable(xfer_task);
+    file_xfer_flush_async(main_channel, cancellable, file_xfer_data_flushed_cb, xfer_task);
+}
+
 /* main context */
 static void file_xfer_read_cb(GObject *source_object,
                               GAsyncResult *res,
                               gpointer user_data)
 {
     SpiceFileTransferTask *self = user_data;
-    SpiceMainChannel *channel = self->channel;
     gssize count;
     GError *error = NULL;
 
@@ -1939,17 +1922,12 @@ static void file_xfer_read_cb(GObject *source_object,
     }
 
     if (count > 0 || self->file_size == 0) {
-        GCancellable *cancellable;
-
         self->read_bytes += count;
         g_object_notify(G_OBJECT(self), "progress");
-        file_xfer_queue(self, count);
-        if (count == 0)
-            return;
-        cancellable = spice_file_transfer_task_get_cancellable(self);
-        file_xfer_flush_async(channel, cancellable,
-                              file_xfer_data_flushed_cb, self);
-        self->pending = TRUE;
+        if (self->flush_callback) {
+            self->pending = TRUE;
+            self->flush_callback(self, self->buffer, count, self->flush_callback_data);
+        }
     } else if (error) {
         spice_channel_wakeup(SPICE_CHANNEL(self->channel), FALSE);
         spice_file_transfer_task_completed(self, error);
@@ -3097,6 +3075,8 @@ static void file_xfer_send_start_msg_async(SpiceMainChannel *channel,
                                            GCancellable *cancellable,
                                            GFileProgressCallback progress_callback,
                                            gpointer progress_callback_data,
+                                           SpiceFileTransferTaskFlushCb flush_callback,
+                                           gpointer flush_callback_data,
                                            GAsyncReadyCallback callback,
                                            gpointer user_data)
 {
@@ -3116,6 +3096,8 @@ static void file_xfer_send_start_msg_async(SpiceMainChannel *channel,
         task->flags = flags;
         task->progress_callback = progress_callback;
         task->progress_callback_data = progress_callback_data;
+        task->flush_callback = flush_callback;
+        task->flush_callback_data = flush_callback_data;
         task->callback = callback;
         task->user_data = user_data;
 
@@ -3204,6 +3186,8 @@ void spice_main_file_copy_async(SpiceMainChannel *channel,
                                    cancellable,
                                    progress_callback,
                                    progress_callback_data,
+                                   file_xfer_flush_callback,
+                                   NULL,
                                    callback,
                                    user_data);
 }
@@ -3249,6 +3233,55 @@ static GCancellable *spice_file_transfer_task_get_cancellable(SpiceFileTransferT
     return self->cancellable;
 }
 
+static void spice_file_transfer_task_flush_done(SpiceFileTransferTask *self, GError *error)
+{
+    g_return_if_fail(self != NULL);
+    g_return_if_fail(self->pending);
+
+    self->pending = FALSE;
+
+    if (error || self->error) {
+        spice_file_transfer_task_completed(self, error);
+        return;
+    }
+
+    if (spice_util_get_debug()) {
+        const GTimeSpan interval = 20 * G_TIME_SPAN_SECOND;
+        gint64 now = g_get_monotonic_time();
+
+        if (interval < now - self->last_update) {
+            gchar *basename = g_file_get_basename(self->file);
+            self->last_update = now;
+            SPICE_DEBUG("transferred %.2f%% of the file %s",
+                        100.0 * self->read_bytes / self->file_size, basename);
+            g_free(basename);
+        }
+    }
+
+    if (self->progress_callback) {
+        goffset read = 0;
+        goffset total = 0;
+        SpiceMainChannel *main_channel = self->channel;
+        GHashTableIter iter;
+        gpointer key, value;
+
+        /* since the progress_callback does not have a parameter to indicate
+         * which file the progress is associated with, report progress on all
+         * current transfers */
+        g_hash_table_iter_init(&iter, main_channel->priv->file_xfer_tasks);
+        while (g_hash_table_iter_next(&iter, &key, &value)) {
+            SpiceFileTransferTask *t = (SpiceFileTransferTask *)value;
+            read += t->read_bytes;
+            total += t->file_size;
+        }
+
+        self->progress_callback(read, total, self->progress_callback_data);
+    }
+
+    /* Read more data */
+    file_xfer_continue_read(self);
+}
+
 static void
 spice_file_transfer_task_get_property(GObject *object,
                                       guint property_id,
-- 
2.5.5



More information about the Spice-devel mailing list