summaryrefslogtreecommitdiff
path: root/src/channel-main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/channel-main.c')
-rw-r--r--src/channel-main.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/src/channel-main.c b/src/channel-main.c
index a833078..2493ead 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -152,7 +152,7 @@ struct _SpiceMainChannelPrivate {
gint timer_id;
GQueue *agent_msg_queue;
GHashTable *file_xfer_tasks;
- GSList *flushing;
+ GHashTable *flushing;
guint switch_host_delayed_id;
guint migrate_delayed_id;
@@ -289,6 +289,8 @@ static void spice_main_channel_init(SpiceMainChannel *channel)
c->agent_msg_queue = g_queue_new();
c->file_xfer_tasks = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, g_object_unref);
+ c->flushing = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ g_object_unref);
c->cancellable_volume_info = g_cancellable_new();
spice_main_channel_reset_capabilties(SPICE_CHANNEL(channel));
@@ -406,6 +408,7 @@ static void spice_main_channel_dispose(GObject *obj)
}
g_clear_pointer(&c->file_xfer_tasks, g_hash_table_unref);
+ g_clear_pointer (&c->flushing, g_hash_table_unref);
g_cancellable_cancel(c->cancellable_volume_info);
g_clear_object(&c->cancellable_volume_info);
@@ -917,20 +920,22 @@ static void agent_free_msg_queue(SpiceMainChannel *channel)
c->agent_msg_queue = NULL;
}
-/* Here, flushing algorithm is stolen from spice-channel.c */
-static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success)
+static gboolean flush_foreach_remove(gpointer key G_GNUC_UNUSED,
+ gpointer value, gpointer user_data)
{
- SpiceMainChannelPrivate *c = channel->priv;
- GSList *l;
+ gboolean success = GPOINTER_TO_UINT(user_data);
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(value);
- 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_simple_async_result_set_op_res_gboolean(result, success);
+ g_simple_async_result_complete_in_idle(result);
+ return TRUE;
+}
- g_slist_free_full(c->flushing, g_object_unref);
- c->flushing = NULL;
+static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success)
+{
+ SpiceMainChannelPrivate *c = channel->priv;
+ g_hash_table_foreach_remove(c->flushing, flush_foreach_remove,
+ GUINT_TO_POINTER(success));
}
static void file_xfer_flush_async(SpiceMainChannel *channel, GCancellable *cancellable,
@@ -951,7 +956,8 @@ static void file_xfer_flush_async(SpiceMainChannel *channel, GCancellable *cance
return;
}
- c->flushing = g_slist_append(c->flushing, simple);
+ /* wait until the last message currently in the queue has been sent */
+ g_hash_table_insert(c->flushing, g_queue_peek_tail(c->agent_msg_queue), simple);
}
static gboolean file_xfer_flush_finish(SpiceMainChannel *channel, GAsyncResult *result,
@@ -978,11 +984,22 @@ static void agent_send_msg_queue(SpiceMainChannel *channel)
while (c->agent_tokens > 0 &&
!g_queue_is_empty(c->agent_msg_queue)) {
+ GSimpleAsyncResult *simple;
c->agent_tokens--;
out = g_queue_pop_head(c->agent_msg_queue);
spice_msg_out_send_internal(out);
+
+ simple = g_hash_table_lookup(c->flushing, out);
+ if (simple) {
+ /* if there's a flush task waiting for this message, finish it */
+ g_simple_async_result_set_op_res_gboolean(simple, TRUE);
+ g_simple_async_result_complete_in_idle(simple);
+ g_hash_table_remove(c->flushing, out);
+ }
}
- if (g_queue_is_empty(c->agent_msg_queue) && c->flushing != NULL) {
+ if (g_queue_is_empty(c->agent_msg_queue) &&
+ g_hash_table_size(c->flushing) != 0) {
+ g_warning("unexpected flush task in list, clearing");
file_xfer_flushed(channel, TRUE);
}
}