@samitouri / QOSamiQemu / commits / f96eac8a4f

monitor: minimal conversion of monitors to QOM

This introduces abstract QOM type "monitor", with concrete subtypes "monitor-hmp" and "monitor-qmp". This is the bare minimum conversion of just the type declarations and replacing g_new/g_free with object_new/object_unref. Command line option "-monitor" now creates a "monitor-hmp" object "/objects/compat_monitorNNN" in addition to the character device "/chardevs/compat_monitorNNN". NNN counts up from zero. Exception: "-monitor chardev:ID" creates a "monitor-hmp" object "/objects/ID", and does not create a character device. "-qmp" and "-qmp-pretty" work the same, except they create a "monitor-qmp" object. "-mon" now creates either a "monitor-hmp" or "monitor-qmp" object "/objects/ID" if the option argument provides an ID, else "/objects/compat_monitorNNN". "-gdbstub" and "-serial mon:..." now create a "monitor-hmp" object "/objects/compat_monitorNNN". Note that the object's name in "/objects/" matches the QemuOpts ID when it exists. The only cases where it doesn't exist are "-mon" without ID, "-gdbstub" and "-serial mon:". A future patch will make "monitor-hmp" and "monitor-qmp" work with "-object" and "object-add". Note: there is a slight change in the NNN values assigned. The old code would increment the counter for every monitor added (except for -mon, -serial mon:..., -gdbstub), regardless of whether it needed a "compat_monitorNNN" ID assignment. Now it is only incremented when an automatic ID assigned is needed (but even for -mon, -serial mon:..., -gdbstub). Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-ID: <20260706135824.2623960-6-berrange@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [Commit message made slightly more precise] Signed-off-by: Markus Armbruster <armbru@redhat.com>

Daniel P. Berrangé committed Jul 6, 2026 at 14:57 UTC f96eac8a4fc48372eda26de396844be3b9f13d27
10 files changed +129 -29
chardev/char.c
+1 -1
@@ -805,7 +805,7 @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename,
805
806 if (qemu_opt_get_bool(opts, "mux", 0)) {
807 assert(permit_mux_mon);
808 - monitor_new_hmp(chr, true, &err);
808 + monitor_new_hmp(NULL, chr, true, &err);
809 if (err) {
810 error_report_err(err);
811 object_unparent(OBJECT(chr));
gdbstub/system.c
+1 -1
@@ -390,7 +390,7 @@ bool gdbserver_start(const char *device, Error **errp)
390 /* Initialize a monitor terminal for gdb */
391 mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
392 NULL, NULL, &error_abort);
393 - monitor_new_hmp(mon_chr, false, &error_abort);
393 + monitor_new_hmp(NULL, mon_chr, false, &error_abort);
394 } else {
395 qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
396 mon_chr = gdbserver_system_state.mon_chr;
include/monitor/monitor.h
+15 -3
@@ -5,8 +5,17 @@
5 #include "qapi/qapi-types-misc.h"
6 #include "qemu/readline.h"
7 #include "exec/hwaddr.h"
8 +#include "qom/object.h"
9 +
10 +#define TYPE_MONITOR "monitor"
11 +OBJECT_DECLARE_TYPE(Monitor, MonitorClass, MONITOR);
12 +
13 +#define TYPE_MONITOR_HMP "monitor-hmp"
14 +OBJECT_DECLARE_TYPE(MonitorHMP, MonitorHMPClass, MONITOR_HMP);
15 +
16 +#define TYPE_MONITOR_QMP "monitor-qmp"
17 +OBJECT_DECLARE_TYPE(MonitorQMP, MonitorQMPClass, MONITOR_QMP);
18
9 -typedef struct MonitorHMP MonitorHMP;
19 typedef struct MonitorOptions MonitorOptions;
20
21 #define QMP_REQ_QUEUE_LEN_MAX 8
@@ -19,8 +28,11 @@ bool monitor_cur_is_qmp(void);
28
29 void monitor_init_globals(void);
30 void monitor_init_globals_core(void);
22 -void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp);
23 -void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp);
31 +char *monitor_compat_id(void);
32 +void monitor_new_qmp(const char *id, Chardev *chr,
33 + bool pretty, Error **errp);
34 +void monitor_new_hmp(const char *id, Chardev *chr,
35 + bool use_readline, Error **errp);
36 int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp);
37 int monitor_new_opts(QemuOpts *opts, Error **errp);
38 void monitor_cleanup(void);
monitor/hmp.c
+28 -3
@@ -43,6 +43,20 @@
43 #include "system/block-backend.h"
44 #include "trace.h"
45
46 +OBJECT_DEFINE_TYPE(MonitorHMP, monitor_hmp, MONITOR_HMP, MONITOR);
47 +
48 +static void monitor_hmp_finalize(Object *obj)
49 +{
50 +}
51 +
52 +static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
53 +{
54 +}
55 +
56 +static void monitor_hmp_init(Object *obj)
57 +{
58 +}
59 +
60 static void monitor_command_cb(void *opaque, const char *cmdline,
61 void *readline_opaque)
62 {
@@ -1524,12 +1538,23 @@ static void monitor_readline_flush(void *opaque)
1538 monitor_flush(&mon->parent_obj);
1539 }
1540
1527 -void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
1541 +void monitor_new_hmp(const char *id, Chardev *chr,
1542 + bool use_readline, Error **errp)
1543 {
1529 - MonitorHMP *mon = g_new0(MonitorHMP, 1);
1544 + MonitorHMP *mon;
1545 + g_autofree char *autoid = id ? NULL : monitor_compat_id();
1546 + Object *obj = object_new_with_props(TYPE_MONITOR_HMP,
1547 + object_get_objects_root(),
1548 + id ? id : autoid,
1549 + errp,
1550 + NULL);
1551 + if (!obj) {
1552 + return;
1553 + }
1554 + mon = MONITOR_HMP(obj);
1555
1556 if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
1532 - g_free(mon);
1557 + object_unparent(OBJECT(mon));
1558 return;
1559 }
1560
monitor/monitor-internal.h
+16 -2
@@ -101,7 +101,13 @@ typedef struct HMPCommand {
101 bool coroutine;
102 } HMPCommand;
103
104 +
105 +struct MonitorClass {
106 + ObjectClass parent_class;
107 +};
108 +
109 struct Monitor {
110 + Object parent;
111 CharFrontend chr;
112 int suspend_cnt; /* Needs to be accessed atomically */
113 bool is_qmp;
@@ -127,6 +133,10 @@ struct Monitor {
133 int reset_seen;
134 };
135
136 +struct MonitorHMPClass {
137 + MonitorClass parent_class;
138 +};
139 +
140 struct MonitorHMP {
141 Monitor parent_obj;
142 bool use_readline;
@@ -140,7 +150,11 @@ struct MonitorHMP {
150 ReadLineState *rs;
151 };
152
143 -typedef struct {
153 +struct MonitorQMPClass {
154 + MonitorClass parent_class;
155 +};
156 +
157 +struct MonitorQMP {
158 Monitor parent_obj;
159 JSONMessageParser parser;
160 bool pretty;
@@ -160,7 +174,7 @@ typedef struct {
174 QemuMutex qmp_queue_lock;
175 /* Input queue that holds all the parsed QMP requests */
176 GQueue *qmp_requests;
163 -} MonitorQMP;
177 +};
178
179 /**
180 * Is @mon a QMP monitor?
monitor/monitor.c
+27 -4
@@ -73,6 +73,22 @@ static GHashTable *coroutine_mon; /* Maps Coroutine* to Monitor* */
73 MonitorList mon_list;
74 static bool monitor_destroyed;
75
76 +int monitor_device_index;
77 +
78 +OBJECT_DEFINE_ABSTRACT_TYPE(Monitor, monitor, MONITOR, OBJECT);
79 +
80 +static void monitor_finalize(Object *obj)
81 +{
82 +}
83 +
84 +static void monitor_class_init(ObjectClass *cls, const void *data)
85 +{
86 +}
87 +
88 +static void monitor_init(Object *obj)
89 +{
90 +}
91 +
92 Monitor *monitor_cur(void)
93 {
94 Monitor *mon;
@@ -598,7 +614,7 @@ void monitor_list_append(Monitor *mon)
614
615 if (mon) {
616 monitor_data_destroy(mon);
601 - g_free(mon);
617 + object_unparent(OBJECT(mon));
618 }
619 }
620
@@ -680,7 +696,7 @@ void monitor_cleanup(void)
696 monitor_flush(mon);
697 monitor_data_destroy(mon);
698 qemu_mutex_lock(&monitor_lock);
683 - g_free(mon);
699 + object_unparent(OBJECT(mon));
700 }
701 qemu_mutex_unlock(&monitor_lock);
702
@@ -715,6 +731,13 @@ void monitor_init_globals(void)
731 aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co);
732 }
733
734 +char *monitor_compat_id(void)
735 +{
736 + static int monitor_device_index;
737 +
738 + return g_strdup_printf("compat_monitor%d", monitor_device_index++);
739 +}
740 +
741 int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
742 {
743 ERRP_GUARD();
@@ -732,7 +755,7 @@ int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
755
756 switch (opts->mode) {
757 case MONITOR_MODE_CONTROL:
735 - monitor_new_qmp(chr, opts->pretty, errp);
758 + monitor_new_qmp(opts->id, chr, opts->pretty, errp);
759 break;
760 case MONITOR_MODE_READLINE:
761 if (!allow_hmp) {
@@ -743,7 +766,7 @@ int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
766 error_setg(errp, "'pretty' is not compatible with HMP monitors");
767 return -1;
768 }
746 - monitor_new_hmp(chr, true, errp);
769 + monitor_new_hmp(opts->id, chr, true, errp);
770 break;
771 default:
772 g_assert_not_reached();
monitor/qmp-cmds.c
+8 -7
@@ -166,12 +166,12 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
166 int64_t cpu_index, Error **errp)
167 {
168 char *output = NULL;
169 - MonitorHMP hmp = {};
169 + MonitorHMP *hmp = MONITOR_HMP(object_new(TYPE_MONITOR_HMP));
170
171 - monitor_data_init(&hmp.parent_obj, false, true, false);
171 + monitor_data_init(&hmp->parent_obj, false, true, false);
172
173 if (has_cpu_index) {
174 - int ret = monitor_set_cpu(&hmp.parent_obj, cpu_index);
174 + int ret = monitor_set_cpu(&hmp->parent_obj, cpu_index);
175 if (ret < 0) {
176 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
177 "a CPU number");
@@ -179,14 +179,15 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
179 }
180 }
181
182 - handle_hmp_command(&hmp, command_line);
182 + handle_hmp_command(hmp, command_line);
183
184 - WITH_QEMU_LOCK_GUARD(&hmp.parent_obj.mon_lock) {
185 - output = g_strdup(hmp.parent_obj.outbuf->str);
184 + WITH_QEMU_LOCK_GUARD(&hmp->parent_obj.mon_lock) {
185 + output = g_strdup(hmp->parent_obj.outbuf->str);
186 }
187
188 out:
189 - monitor_data_destroy(&hmp.parent_obj);
189 + monitor_data_destroy(&hmp->parent_obj);
190 + object_unref(hmp);
191 return output;
192 }
193
monitor/qmp.c
+28 -3
@@ -71,6 +71,20 @@ typedef struct QMPRequest QMPRequest;
71
72 QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
73
74 +OBJECT_DEFINE_TYPE(MonitorQMP, monitor_qmp, MONITOR_QMP, MONITOR);
75 +
76 +static void monitor_qmp_finalize(Object *obj)
77 +{
78 +}
79 +
80 +static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
81 +{
82 +}
83 +
84 +static void monitor_qmp_init(Object *obj)
85 +{
86 +}
87 +
88 static bool qmp_oob_enabled(MonitorQMP *mon)
89 {
90 return mon->capab[QMP_CAPABILITY_OOB];
@@ -513,12 +527,23 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
527 monitor_list_append(&mon->parent_obj);
528 }
529
516 -void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp)
530 +void monitor_new_qmp(const char *id, Chardev *chr,
531 + bool pretty, Error **errp)
532 {
518 - MonitorQMP *mon = g_new0(MonitorQMP, 1);
533 + MonitorQMP *mon;
534 + g_autofree char *autoid = id ? NULL : monitor_compat_id();
535 + Object *obj = object_new_with_props(TYPE_MONITOR_QMP,
536 + object_get_objects_root(),
537 + id ? id : autoid,
538 + errp,
539 + NULL);
540 + if (!obj) {
541 + return;
542 + }
543 + mon = MONITOR_QMP(obj);
544
545 if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
521 - g_free(mon);
546 + object_unparent(OBJECT(mon));
547 return;
548 }
549 qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
stubs/monitor-internal.c
+2 -1
@@ -8,6 +8,7 @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
8 return -1;
9 }
10
11 -void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
11 +void monitor_new_hmp(const char *id, Chardev *chr,
12 + bool use_readline, Error **errp)
13 {
14 }
system/vl.c
+3 -4
@@ -1252,7 +1252,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
1252
1253 static void monitor_parse(const char *str, const char *mode, bool pretty)
1254 {
1255 - static int monitor_device_index = 0;
1255 QemuOpts *opts;
1256 const char *p;
1257 char label[32];
@@ -1260,8 +1259,9 @@ static void monitor_parse(const char *str, const char *mode, bool pretty)
1259 if (strstart(str, "chardev:", &p)) {
1260 snprintf(label, sizeof(label), "%s", p);
1261 } else {
1263 - snprintf(label, sizeof(label), "compat_monitor%d",
1264 - monitor_device_index);
1262 + g_autofree char *id = monitor_compat_id();
1263 + assert(strlen(id) < sizeof(label));
1264 + memcpy(label, id, strlen(id) + 1);
1265 opts = qemu_chr_parse_compat(label, str, true);
1266 if (!opts) {
1267 error_report("parse error: %s", str);
@@ -1277,7 +1277,6 @@ static void monitor_parse(const char *str, const char *mode, bool pretty)
1277 } else {
1278 assert(pretty == false);
1279 }
1280 - monitor_device_index++;
1280 }
1281
1282 struct device_config {