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