From f784f4e6d1c19a8afdf2c1714533efbcc8c4300d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jank=C5=AF?= Date: Sun, 29 Dec 2019 16:35:13 +0100 Subject: [PATCH] main: remove msg from c->flushing asap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The msg is no longer valid after spice_msg_out_send_internal(), so it shouldn't be present in c->flushing since the same memory can be assigned to a new message. This currently causes issues when transferring multiple big files at once (tested 4 × 200 MB). The following can happen in agent_send_msg_queue(), after msg is flushed: (task1, task2 refers to two distinct SpiceFileTransferTasks, one per file) g_task_return_boolean(task1) -> file_xfer_data_flushed_cb(task1) -> spice_file_transfer_task_read_async(task1) -> g_coroutine_object_notify() [switches from coroutine context to main] ... file_xfer_read_async_cb(task2) -> file_xfer_queue_msg_to_agent(task2) [allocates new msg for task2 at the same address as the old msg] -> file_xfer_flush_async(task2) [inserts to c->flushing, but the old msg is still present, so the data in the hash table changes from task1 to task2] ... program returns to coroutine context, g_task_return_boolean(task1) returns -> g_hash_table_remove() [removes the entry that now contains task2] Consequently, flush task for task2 never finishes and it gets stuck. This issue is present since 2261e50a6411c58ab6fdaf02b04acfb54aebf936, that replaced g_object_notify() in spice_file_transfer_task_read_async() with g_coroutine_object_notify(). To solve it, remove the msg from c->flushing before finishing the flush task. Signed-off-by: Jakub Janků --- src/channel-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/channel-main.c b/src/channel-main.c index bf941d6..f81cecb 100644 --- a/src/channel-main.c +++ b/src/channel-main.c @@ -944,9 +944,9 @@ static void agent_send_msg_queue(SpiceMainChannel *channel) task = g_hash_table_lookup(c->flushing, out); if (task) { /* if there's a flush task waiting for this message, finish it */ + g_hash_table_remove(c->flushing, out); g_task_return_boolean(task, TRUE); g_object_unref(task); - g_hash_table_remove(c->flushing, out); } } if (g_queue_is_empty(c->agent_msg_queue) &&