[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 20/36] monitor: allow using IO thread for parsing
From: |
Eric Blake |
Subject: |
[Qemu-devel] [PULL 20/36] monitor: allow using IO thread for parsing |
Date: |
Mon, 12 Mar 2018 13:36:11 -0500 |
From: Peter Xu <address@hidden>
For each Monitor, add one field "use_io_thr" to show whether it will be
using the dedicated monitor IO thread to handle input/output. When set,
monitor IO parsing work will be offloaded to the dedicated monitor IO
thread, rather than the original main loop thread.
This only works for QMP. HMP will always be run on the main loop
thread.
Currently we're still keeping use_io_thr off always. Will turn it on
later at some point.
One thing to mention is that we cannot set use_io_thr for every QMP
monitor. The problem is that MUXed typed chardevs may not work well
with it now. When MUX is used, frontend of chardev can be the monitor
plus something else. The only thing we know would be safe to be run
outside main thread so far is the monitor frontend. All the rest of the
frontends should still be run in main thread only.
Signed-off-by: Peter Xu <address@hidden>
Message-Id: <address@hidden>
Reviewed-by: Eric Blake <address@hidden>
Signed-off-by: Eric Blake <address@hidden>
---
monitor.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 90 insertions(+), 8 deletions(-)
diff --git a/monitor.c b/monitor.c
index 63b93f83217..ce9f7fc8e8a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -35,6 +35,7 @@
#include "net/net.h"
#include "net/slirp.h"
#include "chardev/char-fe.h"
+#include "chardev/char-io.h"
#include "ui/qemu-spice.h"
#include "sysemu/numa.h"
#include "monitor/monitor.h"
@@ -79,6 +80,7 @@
#include "qapi/qapi-introspect.h"
#include "sysemu/qtest.h"
#include "sysemu/cpus.h"
+#include "sysemu/iothread.h"
#include "qemu/cutils.h"
#if defined(TARGET_S390X)
@@ -192,6 +194,7 @@ struct Monitor {
int flags;
int suspend_cnt;
bool skip_flush;
+ bool use_io_thr;
QemuMutex out_lock;
QString *outbuf;
@@ -210,6 +213,11 @@ struct Monitor {
QTAILQ_ENTRY(Monitor) entry;
};
+/* Let's add monitor global variables to this struct. */
+static struct {
+ IOThread *mon_iothread;
+} mon_global;
+
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
@@ -570,7 +578,8 @@ static void monitor_qapi_event_init(void)
static void handle_hmp_command(Monitor *mon, const char *cmdline);
-static void monitor_data_init(Monitor *mon, bool skip_flush)
+static void monitor_data_init(Monitor *mon, bool skip_flush,
+ bool use_io_thr)
{
memset(mon, 0, sizeof(Monitor));
qemu_mutex_init(&mon->out_lock);
@@ -578,6 +587,7 @@ static void monitor_data_init(Monitor *mon, bool skip_flush)
/* Use *mon_cmds by default. */
mon->cmd_table = mon_cmds;
mon->skip_flush = skip_flush;
+ mon->use_io_thr = use_io_thr;
}
static void monitor_data_destroy(Monitor *mon)
@@ -598,7 +608,7 @@ char *qmp_human_monitor_command(const char *command_line,
bool has_cpu_index,
char *output = NULL;
Monitor *old_mon, hmp;
- monitor_data_init(&hmp, true);
+ monitor_data_init(&hmp, true, false);
old_mon = cur_mon;
cur_mon = &hmp;
@@ -3985,12 +3995,29 @@ static void sortcmdlist(void)
qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
}
+static GMainContext *monitor_get_io_context(void)
+{
+ return iothread_get_g_main_context(mon_global.mon_iothread);
+}
+
+static AioContext *monitor_get_aio_context(void)
+{
+ return iothread_get_aio_context(mon_global.mon_iothread);
+}
+
+static void monitor_iothread_init(void)
+{
+ mon_global.mon_iothread = iothread_create("mon_iothread",
+ &error_abort);
+}
+
void monitor_init_globals(void)
{
monitor_init_qmp_commands();
monitor_qapi_event_init();
sortcmdlist();
qemu_mutex_init(&monitor_lock);
+ monitor_iothread_init();
}
/* These functions just adapt the readline interface in a typesafe way. We
@@ -4033,11 +4060,41 @@ void error_vprintf_unless_qmp(const char *fmt, va_list
ap)
}
}
+static void monitor_list_append(Monitor *mon)
+{
+ qemu_mutex_lock(&monitor_lock);
+ QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
+ qemu_mutex_unlock(&monitor_lock);
+}
+
+static void monitor_qmp_setup_handlers_bh(void *opaque)
+{
+ Monitor *mon = opaque;
+ GMainContext *context;
+
+ if (mon->use_io_thr) {
+ /*
+ * When use_io_thr is set, we use the global shared dedicated
+ * IO thread for this monitor to handle input/output.
+ */
+ context = monitor_get_io_context();
+ /* We should have inited globals before reaching here. */
+ assert(context);
+ } else {
+ /* The default main loop, which is the main thread */
+ context = NULL;
+ }
+
+ qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
+ monitor_qmp_event, NULL, mon, context, true);
+ monitor_list_append(mon);
+}
+
void monitor_init(Chardev *chr, int flags)
{
Monitor *mon = g_malloc(sizeof(*mon));
- monitor_data_init(mon, false);
+ monitor_data_init(mon, false, false);
qemu_chr_fe_init(&mon->chr, chr, &error_abort);
mon->flags = flags;
@@ -4050,24 +4107,46 @@ void monitor_init(Chardev *chr, int flags)
}
if (monitor_is_qmp(mon)) {
- qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
- monitor_qmp_event, NULL, mon, NULL, true);
qemu_chr_fe_set_echo(&mon->chr, true);
json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
+ if (mon->use_io_thr) {
+ /*
+ * We can't call qemu_chr_fe_set_handlers() directly here
+ * since during the procedure the chardev will be active
+ * and running in monitor iothread, while we'll still do
+ * something before returning from it, which is a possible
+ * race too. To avoid that, we just create a BH to setup
+ * the handlers.
+ */
+ aio_bh_schedule_oneshot(monitor_get_aio_context(),
+ monitor_qmp_setup_handlers_bh, mon);
+ /* We'll add this to mon_list in the BH when setup done */
+ return;
+ } else {
+ qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read,
+ monitor_qmp_read, monitor_qmp_event,
+ NULL, mon, NULL, true);
+ }
} else {
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
monitor_event, NULL, mon, NULL, true);
}
- qemu_mutex_lock(&monitor_lock);
- QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
- qemu_mutex_unlock(&monitor_lock);
+ monitor_list_append(mon);
}
void monitor_cleanup(void)
{
Monitor *mon, *next;
+ /*
+ * We need to explicitly stop the iothread (but not destroy it),
+ * cleanup the monitor resources, then destroy the iothread since
+ * we need to unregister from chardev below in
+ * monitor_data_destroy(), and chardev is not thread-safe yet
+ */
+ iothread_stop(mon_global.mon_iothread);
+
qemu_mutex_lock(&monitor_lock);
QTAILQ_FOREACH_SAFE(mon, &mon_list, entry, next) {
QTAILQ_REMOVE(&mon_list, mon, entry);
@@ -4075,6 +4154,9 @@ void monitor_cleanup(void)
g_free(mon);
}
qemu_mutex_unlock(&monitor_lock);
+
+ iothread_destroy(mon_global.mon_iothread);
+ mon_global.mon_iothread = NULL;
}
QemuOptsList qemu_mon_opts = {
--
2.14.3
- [Qemu-devel] [PULL 11/36] block: Deprecate "backing": "", (continued)
- [Qemu-devel] [PULL 11/36] block: Deprecate "backing": "", Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 17/36] monitor: move the cur_mon hack deeper for QMP, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 10/36] block: Handle null backing link, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 13/36] qobject: introduce qstring_get_try_str(), Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 26/36] qmp: add new event "command-dropped", Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 19/36] monitor: let mon_list be tail queue, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 01/36] qapi2texi: minor python code simplification, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 12/36] docs: update QMP documents for OOB commands, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 14/36] qobject: introduce qobject_get_try_str(), Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 22/36] monitor: introduce monitor_qmp_respond(), Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 20/36] monitor: allow using IO thread for parsing,
Eric Blake <=
- [Qemu-devel] [PULL 24/36] monitor: let suspend/resume work even with QMPs, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 29/36] qmp: support out-of-band (oob) execution, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 32/36] qmp: add command "x-oob-test", Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 34/36] tests: qmp-test: add oob test, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 28/36] qapi: introduce new cmd option "allow-oob", Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 21/36] qmp: introduce QMPCapability, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 30/36] qmp: isolate responses into io thread, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 15/36] qobject: let object_property_get_str() use new API, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 23/36] monitor: let suspend_cnt be thread safe, Eric Blake, 2018/03/12
- [Qemu-devel] [PULL 27/36] monitor: send event when command queue full, Eric Blake, 2018/03/12