From eea7cd3fc5139d7523f3c7a67d9c864b944dfacd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Mar 2023 12:34:01 +0100 Subject: [PATCH] monitor: do not use mb_read/mb_set Instead of relying on magic memory barriers, document the pattern that is being used. It is the one based on Dekker's algorithm, and in this case it is embodied as follows: enqueue request; sleeping = true; smp_mb(); smp_mb(); if (sleeping) kick(); if (!have a request) yield(); Signed-off-by: Paolo Bonzini --- monitor/qmp.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/monitor/qmp.c b/monitor/qmp.c index e6b1043c9f..c8e0156974 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -39,13 +39,16 @@ * coroutine never gets scheduled a second time when it's already * scheduled (scheduling the same coroutine twice is forbidden). * - * It is true if the coroutine is active and processing requests. - * Additional requests may then be pushed onto mon->qmp_requests, - * and @qmp_dispatcher_co_shutdown may be set without further ado. - * @qmp_dispatcher_co_busy must not be woken up in this case. + * It is true if the coroutine will process at least one more request + * before going to sleep. Either it has been kicked already, or it + * is active and processing requests. Additional requests may therefore + * be pushed onto mon->qmp_requests, and @qmp_dispatcher_co_shutdown may + * be set without further ado. @qmp_dispatcher_co must not be woken up + * in this case. * - * If false, you also have to set @qmp_dispatcher_co_busy to true and - * wake up @qmp_dispatcher_co after pushing the new requests. + * If false, you have to wake up @qmp_dispatcher_co after pushing new + * requests. You also have to set @qmp_dispatcher_co_busy to true + * before waking up the coroutine. * * The coroutine will automatically change this variable back to false * before it yields. Nobody else may set the variable to false. @@ -230,15 +233,18 @@ static QMPRequest *monitor_qmp_dispatcher_pop_any(void) { while (true) { /* - * busy must be set to true again by whoever - * rescheduled us to avoid double scheduling + * To avoid double scheduling, busy is true on entry to + * monitor_qmp_dispatcher_co(), and must be set again before + * aio_co_wake()-ing it. */ - assert(qatomic_mb_read(&qmp_dispatcher_co_busy) == true); + assert(qatomic_read(&qmp_dispatcher_co_busy) == true); /* * Mark the dispatcher as not busy already here so that we * don't miss any new requests coming in the middle of our * processing. + * + * Clear qmp_dispatcher_co_busy before reading request. */ qatomic_mb_set(&qmp_dispatcher_co_busy, false); @@ -364,6 +370,9 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) void qmp_dispatcher_co_wake(void) { + /* Write request before reading qmp_dispatcher_co_busy. */ + smp_mb__before_rmw(); + if (!qatomic_xchg(&qmp_dispatcher_co_busy, true)) { aio_co_wake(qmp_dispatcher_co); }