qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1] coroutine: avoid inserting duplicate coroutine to co_queue_wakeup
@ 2024-03-25  9:18 zhuyangyang via
  2024-03-25 15:50 ` Stefan Hajnoczi
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: zhuyangyang via @ 2024-03-25  9:18 UTC (permalink / raw)
  To: Stefan Hajnoczi, Fam Zheng, qemu-block, qemu-devel
  Cc: qemu-stable, luolongmin, suxiaodong1, chenxiaoyu48, wangyan122,
	yebiaoxiang

If g_main_loop_run()/aio_poll() is called in the coroutine context,
the pending coroutine may be woken up repeatedly, and the co_queue_wakeup
may be disordered.

When the poll() syscall exited in g_main_loop_run()/aio_poll(), it means
some listened events is completed. Therefore, the completion callback
function is dispatched.

If this callback function needs to invoke aio_co_enter(), it will only
wake up the coroutine (because we are already in coroutine context),
which may cause that the data on this listening event_fd/socket_fd
is not read/cleared. When the next poll () exits, it will be woken up again
and inserted into the wakeup queue again.

For example, if TLS is enabled in NBD, the server will call g_main_loop_run()
in the coroutine, and repeatedly wake up the io_read event on a socket.
The call stack is as follows:

aio_co_enter()
aio_co_wake()
qio_channel_restart_read()
aio_dispatch_handler()
aio_dispatch_handlers()
aio_dispatch()
aio_ctx_dispatch()
g_main_context_dispatch()
g_main_loop_run()
nbd_negotiate_handle_starttls()
nbd_negotiate_options()
nbd_negotiate()
nbd_co_client_start()
coroutine_trampoline()

Signed-off-by: zhuyangyang <zhuyangyang14@huawei.com>
---
 util/async.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/util/async.c b/util/async.c
index 0467890052..25fc1e6083 100644
--- a/util/async.c
+++ b/util/async.c
@@ -705,7 +705,18 @@ void aio_co_enter(AioContext *ctx, Coroutine *co)
     if (qemu_in_coroutine()) {
         Coroutine *self = qemu_coroutine_self();
         assert(self != co);
-        QSIMPLEQ_INSERT_TAIL(&self->co_queue_wakeup, co, co_queue_next);
+        /*
+         * If the Coroutine *co is already in the co_queue_wakeup, this
+         * repeated insertion will causes the loss of other queue element
+         * or infinite loop.
+         * For examplex:
+         * Head->a->b->c->NULL, after insert_tail(head, b) => Head->a->b->NULL
+         * Head->a-b>->NULL, after insert_tail(head, b) => Head->a->b->b...
+         */
+        if (!co->co_queue_next.sqe_next &&
+            self->co_queue_wakeup.sqh_last != &co->co_queue_next.sqe_next) {
+            QSIMPLEQ_INSERT_TAIL(&self->co_queue_wakeup, co, co_queue_next);
+        }
     } else {
         qemu_aio_coroutine_enter(ctx, co);
     }
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2024-04-01  7:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-25  9:18 [PATCH v1] coroutine: avoid inserting duplicate coroutine to co_queue_wakeup zhuyangyang via
2024-03-25 15:50 ` Stefan Hajnoczi
2024-03-26 11:53   ` zhuyangyang via
2024-03-27 22:13   ` Eric Blake
2024-03-28  8:54     ` Kevin Wolf
2024-03-25 16:00 ` Eric Blake
2024-03-26 12:25   ` zhuyangyang via
2024-03-28 12:40 ` Eric Blake
2024-03-29 13:09   ` Zhu Yangyang via
2024-04-01  8:04   ` Zhu Yangyang via

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).