[Spice-commits] src/channel-main.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jan 10 10:05:10 UTC 2020

 src/channel-main.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

New commits:
commit f784f4e6d1c19a8afdf2c1714533efbcc8c4300d
Author: Jakub Janků <jjanku at redhat.com>
Date:   Sun Dec 29 16:35:13 2019 +0100

    main: remove msg from c->flushing asap
    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) ->
    [allocates new msg for task2 at the same address as the old msg] ->
    [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ů <jjanku at redhat.com>

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_hash_table_remove(c->flushing, out);
     if (g_queue_is_empty(c->agent_msg_queue) &&

More information about the Spice-commits mailing list