@samitouri / QOSamiQemu / commits / 12de966616

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.