aboutsummaryrefslogtreecommitdiff
path: root/monitor/qmp.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2023-05-25 08:36:10 -0700
committerRichard Henderson <richard.henderson@linaro.org>2023-05-25 08:36:10 -0700
commit6ad2c71c238183437c91bb9fa0c8d87a9559eca3 (patch)
treed7e51d80fbf89ee4eeb1f2c9b32605f030b34cfd /monitor/qmp.c
parentb300c134465465385045ab705b68a42699688332 (diff)
parenteea7cd3fc5139d7523f3c7a67d9c864b944dfacd (diff)
downloadqemu-6ad2c71c238183437c91bb9fa0c8d87a9559eca3.zip
qemu-6ad2c71c238183437c91bb9fa0c8d87a9559eca3.tar.gz
qemu-6ad2c71c238183437c91bb9fa0c8d87a9559eca3.tar.bz2
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* hot-unplug fixes for ioport * purge qatomic_mb_read/set from monitor * build system fixes * OHCI fix from gitlab * provide EPYC-Rome CPU model not susceptible to XSAVES erratum # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmRvGpEUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOa/Af/WS5/tmIlEYgH7UOPERQXNqf7+Jwj # bA2wgqv3ZoQwcgp5f4EVjfA8ABfpGxLZy6xIdUSbWANb8lDJNuh/nPd/em3rWUAU # LnJGGdo1vF31gfsVQnlzb7hJi3ur+e2f8JqkRVskDCk3a7YY44OCN42JdKWLrN9u # CFf2zYqxMqXHjrYrY0Kx2oTkfGDZrfwUlx0vM4dHb8IEoxaplfDd8lJXQzjO4htr # 3nPBPjQ+h08EeC7mObH4XoJE0omzovR10GkBo8K4q952xGOQ041Y/2YY7JwLfx0D # na7IanVo+ZAmvTJZoJFSBwNnXkTMHvDH5+Hc45NSTsDBtz0YJhRxPw/z/A== # =A5Lp # -----END PGP SIGNATURE----- # gpg: Signature made Thu 25 May 2023 01:21:37 AM PDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [undefined] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: monitor: do not use mb_read/mb_set monitor: extract request dequeuing to a new function monitor: introduce qmp_dispatcher_co_wake monitor: cleanup fetching of QMP requests monitor: cleanup detection of qmp_dispatcher_co shutting down monitor: do not use mb_read/mb_set for suspend_cnt monitor: add more *_locked() functions monitor: allow calling monitor_resume under mon_lock monitor: use QEMU_LOCK_GUARD a bit more softmmu/ioport.c: make MemoryRegionPortioList owner of portio_list MemoryRegions softmmu/ioport.c: QOMify MemoryRegionPortioList softmmu/ioport.c: allocate MemoryRegionPortioList ports on the heap usb/ohci: Set pad to 0 after frame update meson: move -no-pie from linker to compiler meson: fix rule for qemu-ga installer meson.build: Fix glib -Wno-unused-function workaround target/i386: EPYC-Rome model without XSAVES Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'monitor/qmp.c')
-rw-r--r--monitor/qmp.c106
1 files changed, 70 insertions, 36 deletions
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 092c527..c8e0156 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -33,6 +33,30 @@
#include "qapi/qmp/qlist.h"
#include "trace.h"
+/*
+ * qmp_dispatcher_co_busy is used for synchronisation between the
+ * monitor thread and the main thread to ensure that the dispatcher
+ * 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 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 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.
+ *
+ * Access must be atomic for thread safety.
+ */
+static bool qmp_dispatcher_co_busy = true;
+
struct QMPRequest {
/* Owner of the request */
MonitorQMP *mon;
@@ -178,8 +202,6 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
Monitor *mon;
MonitorQMP *qmp_mon;
- QEMU_LOCK_GUARD(&monitor_lock);
-
QTAILQ_FOREACH(mon, &mon_list, entry) {
if (!monitor_is_qmp(mon)) {
continue;
@@ -207,53 +229,56 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
return req_obj;
}
-void coroutine_fn monitor_qmp_dispatcher_co(void *data)
+static QMPRequest *monitor_qmp_dispatcher_pop_any(void)
{
- QMPRequest *req_obj = NULL;
- QDict *rsp;
- bool oob_enabled;
- MonitorQMP *mon;
-
while (true) {
- assert(qatomic_mb_read(&qmp_dispatcher_co_busy) == true);
+ /*
+ * 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_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);
- /* On shutdown, don't take any more requests from the queue */
- if (qmp_dispatcher_co_shutdown) {
- return;
- }
+ WITH_QEMU_LOCK_GUARD(&monitor_lock) {
+ QMPRequest *req_obj;
- while (!(req_obj = monitor_qmp_requests_pop_any_with_lock())) {
- /*
- * No more requests to process. Wait to be reentered from
- * handle_qmp_command() when it pushes more requests, or
- * from monitor_cleanup() when it requests shutdown.
- */
- if (!qmp_dispatcher_co_shutdown) {
- qemu_coroutine_yield();
-
- /*
- * busy must be set to true again by whoever
- * rescheduled us to avoid double scheduling
- */
- assert(qatomic_xchg(&qmp_dispatcher_co_busy, false) == true);
+ /* On shutdown, don't take any more requests from the queue */
+ if (qmp_dispatcher_co_shutdown) {
+ return NULL;
}
- /*
- * qmp_dispatcher_co_shutdown may have changed if we
- * yielded and were reentered from monitor_cleanup()
- */
- if (qmp_dispatcher_co_shutdown) {
- return;
+ req_obj = monitor_qmp_requests_pop_any_with_lock();
+ if (req_obj) {
+ return req_obj;
}
}
+ /*
+ * No more requests to process. Wait to be reentered from
+ * handle_qmp_command() when it pushes more requests, or
+ * from monitor_cleanup() when it requests shutdown.
+ */
+ qemu_coroutine_yield();
+ }
+}
+
+void coroutine_fn monitor_qmp_dispatcher_co(void *data)
+{
+ QMPRequest *req_obj;
+ QDict *rsp;
+ bool oob_enabled;
+ MonitorQMP *mon;
+
+ while ((req_obj = monitor_qmp_dispatcher_pop_any()) != NULL) {
trace_monitor_qmp_in_band_dequeue(req_obj,
req_obj->mon->qmp_requests->length);
@@ -340,6 +365,17 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co);
qemu_coroutine_yield();
}
+ qatomic_set(&qmp_dispatcher_co, NULL);
+}
+
+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);
+ }
}
static void handle_qmp_command(void *opaque, QObject *req, Error *err)
@@ -403,9 +439,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
}
/* Kick the dispatcher routine */
- if (!qatomic_xchg(&qmp_dispatcher_co_busy, true)) {
- aio_co_wake(qmp_dispatcher_co);
- }
+ qmp_dispatcher_co_wake();
}
static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)