monitor: use class method for I/O thread request
Introducing a virtual "requires_iothread" method allows the code to automatically initialize the I/O thread during object completion. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Tested-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-ID: <20260706135824.2623960-16-berrange@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
Daniel P. Berrangé committed
Jul 6, 2026 at 14:58 UTC
12de966616cbb350a48443f4161407abac23aae4
3 files changed
+32
-24
monitor/monitor-internal.h
+9
-5
@@ -121,6 +121,12 @@ struct MonitorClass {
121
* the monitor to accept further client input
122
*/
123
void (*accept_input)(Monitor *mon);
124
+
125
+ /*
126
+ * If non-NULL and returns true, then an I/O thread
127
+ * is required for processing the monitor
128
+ */
129
+ bool (*requires_iothread)(const Monitor *mon);
130
};
131
132
struct Monitor {
@@ -129,7 +135,6 @@ struct Monitor {
135
CharFrontend chr;
136
int suspend_cnt; /* Needs to be accessed atomically */
137
bool is_qmp;
132
- bool use_io_thread;
138
139
char *mon_cpu_path;
140
QTAILQ_ENTRY(Monitor) entry;
@@ -159,9 +164,8 @@ struct MonitorHMP {
164
bool use_readline;
165
/*
166
* State used only in the thread "owning" the monitor.
162
- * If @use_io_thread, this is @mon_iothread. (This does not actually happen
163
- * in the current state of the code.)
164
- * Else, it's the main thread.
167
+ * This is currently always the main thread, since
168
+ * HMP does not allow use of the I/O thread at this time.
169
* These members can be safely accessed without locks.
170
*/
171
ReadLineState *rs;
@@ -210,7 +214,7 @@ extern QemuMutex monitor_lock;
214
extern MonitorList mon_list;
215
216
void monitor_complete(Monitor *mon, Error **errp);
213
-void monitor_iothread_init(Monitor *mon);
217
+bool monitor_requires_iothread(const Monitor *mon);
218
int monitor_can_read(void *opaque);
219
void monitor_list_append(Monitor *mon);
220
void monitor_fdsets_cleanup(void);
monitor/monitor.c
+12
-10
@@ -162,6 +162,12 @@ bool monitor_cur_is_qmp(void)
162
return cur_mon && monitor_is_qmp(cur_mon);
163
}
164
165
+bool monitor_requires_iothread(const Monitor *mon)
166
+{
167
+ MonitorClass *cls = MONITOR_GET_CLASS(mon);
168
+ return cls->requires_iothread && cls->requires_iothread(mon);
169
+}
170
+
171
/**
172
* Is @mon is using readline?
173
* Note: not all HMP monitors use readline, e.g., gdbserver has a
@@ -563,7 +569,7 @@ int monitor_suspend(Monitor *mon)
569
570
qatomic_inc(&mon->suspend_cnt);
571
566
- if (mon->use_io_thread) {
572
+ if (monitor_requires_iothread(mon)) {
573
/*
574
* Kick I/O thread to make sure this takes effect. It'll be
575
* evaluated again in prepare() of the watch object.
@@ -596,7 +602,7 @@ void monitor_resume(Monitor *mon)
602
if (qatomic_dec_fetch(&mon->suspend_cnt) == 0) {
603
AioContext *ctx;
604
599
- if (mon->use_io_thread) {
605
+ if (monitor_requires_iothread(mon)) {
606
ctx = iothread_get_aio_context(mon_iothread);
607
} else {
608
ctx = qemu_get_aio_context();
@@ -634,14 +640,6 @@ void monitor_list_append(Monitor *mon)
640
}
641
}
642
637
-void monitor_iothread_init(Monitor *mon)
638
-{
639
- if (!mon_iothread) {
640
- mon_iothread = iothread_create("mon_iothread", &error_abort);
641
- }
642
- mon->use_io_thread = true;
643
-}
644
-
643
void monitor_cleanup(void)
644
{
645
/*
@@ -743,6 +741,10 @@ void monitor_complete(Monitor *mon, Error **errp)
741
return;
742
}
743
}
744
+
745
+ if (monitor_requires_iothread(mon) && !mon_iothread) {
746
+ mon_iothread = iothread_create("mon_iothread", &error_abort);
747
+ }
748
}
749
750
int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
monitor/qmp.c
+11
-9
@@ -100,6 +100,7 @@ static void monitor_qmp_set_pretty(Object *obj, bool val, Error **errp)
100
}
101
102
static void monitor_qmp_emit_event(Monitor *mon, QAPIEvent event, QDict *qdict);
103
+static bool monitor_qmp_requires_iothread(const Monitor *mon);
104
105
static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
106
{
@@ -110,6 +111,7 @@ static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
111
monitor_qmp_set_pretty);
112
113
moncls->emit_event = monitor_qmp_emit_event;
114
+ moncls->requires_iothread = monitor_qmp_requires_iothread;
115
}
116
117
static void handle_qmp_command(void *opaque, QObject *req, Error *err);
@@ -136,6 +138,11 @@ static void monitor_qmp_emit_event(Monitor *mon, QAPIEvent event, QDict *qdict)
138
qmp_send_response(qmp, qdict);
139
}
140
141
+static bool monitor_qmp_requires_iothread(const Monitor *mon)
142
+{
143
+ return qemu_chr_has_feature(mon->chr.chr,
144
+ QEMU_CHAR_FEATURE_GCONTEXT);
145
+}
146
147
static bool qmp_oob_enabled(MonitorQMP *mon)
148
{
@@ -146,7 +153,8 @@ static void monitor_qmp_caps_reset(MonitorQMP *mon)
153
{
154
memset(mon->capab_offered, 0, sizeof(mon->capab_offered));
155
memset(mon->capab, 0, sizeof(mon->capab));
149
- mon->capab_offered[QMP_CAPABILITY_OOB] = mon->parent_obj.use_io_thread;
156
+ mon->capab_offered[QMP_CAPABILITY_OOB] =
157
+ monitor_requires_iothread(MONITOR(mon));
158
}
159
160
static void qmp_request_free(QMPRequest *req)
@@ -562,7 +570,7 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
570
MonitorQMP *mon = opaque;
571
GMainContext *context;
572
565
- assert(mon->parent_obj.use_io_thread);
573
+ assert(monitor_requires_iothread(MONITOR(mon)));
574
context = iothread_get_g_main_context(mon_iothread);
575
assert(context);
576
qemu_chr_fe_set_handlers(&mon->parent_obj.chr, monitor_can_read,
@@ -598,13 +606,7 @@ void monitor_new_qmp(const char *id, const char *chardev_id,
606
607
qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
608
601
- /* Note: we run QMP monitor in I/O thread when @chr supports that */
602
- if (qemu_chr_has_feature(mon->parent_obj.chr.chr,
603
- QEMU_CHAR_FEATURE_GCONTEXT)) {
604
- monitor_iothread_init(&mon->parent_obj);
605
- }
606
-
607
- if (mon->parent_obj.use_io_thread) {
609
+ if (monitor_requires_iothread(MONITOR(mon))) {
610
/*
611
* Make sure the old iowatch is gone. It's possible when
612
* e.g. the chardev is in client mode, with wait=on.