monitor: add 'chardev' property to Monitor base class
This is associates both QMP and HMP monitors with a character device backend. 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-8-berrange@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
Daniel P. Berrangé committed
Jul 6, 2026 at 14:57 UTC
1a65434329460e67436cf9331b8c7215efbcb74b
4 files changed
+63
-32
monitor/hmp.c
+10
-14
@@ -1542,28 +1542,24 @@ static void monitor_readline_flush(void *opaque)
1542
void monitor_new_hmp(const char *id, const char *chardev_id,
1543
bool use_readline, Error **errp)
1544
{
1545
+ ERRP_GUARD();
1546
MonitorHMP *mon;
1547
g_autofree char *autoid = id ? NULL : monitor_compat_id();
1547
- Chardev *chr;
1548
- Object *obj;
1548
+ Object *obj = object_new_with_props(TYPE_MONITOR_HMP,
1549
+ object_get_objects_root(),
1550
+ id ? id : autoid,
1551
+ errp,
1552
+ "chardev", chardev_id,
1553
+ NULL);
1554
1550
- chr = qemu_chr_find(chardev_id);
1551
- if (chr == NULL) {
1552
- error_setg(errp, "chardev \"%s\" not found", chardev_id);
1553
- return;
1554
- }
1555
-
1556
- obj = object_new_with_props(TYPE_MONITOR_HMP,
1557
- object_get_objects_root(),
1558
- id ? id : autoid,
1559
- errp,
1560
- NULL);
1555
if (!obj) {
1556
return;
1557
}
1558
+
1559
mon = MONITOR_HMP(obj);
1560
1566
- if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
1561
+ monitor_complete(MONITOR(mon), errp);
1562
+ if (*errp) {
1563
object_unparent(OBJECT(mon));
1564
return;
1565
}
monitor/monitor-internal.h
+2
@@ -108,6 +108,7 @@ struct MonitorClass {
108
109
struct Monitor {
110
Object parent;
111
+ char *chardev_id;
112
CharFrontend chr;
113
int suspend_cnt; /* Needs to be accessed atomically */
114
bool is_qmp;
@@ -192,6 +193,7 @@ extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
193
extern QemuMutex monitor_lock;
194
extern MonitorList mon_list;
195
196
+void monitor_complete(Monitor *mon, Error **errp);
197
void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush,
198
bool use_io_thread);
199
void monitor_data_destroy(Monitor *mon);
monitor/monitor.c
+36
@@ -79,10 +79,31 @@ OBJECT_DEFINE_ABSTRACT_TYPE(Monitor, monitor, MONITOR, OBJECT);
79
80
static void monitor_finalize(Object *obj)
81
{
82
+ Monitor *mon = MONITOR(obj);
83
+
84
+ g_free(mon->chardev_id);
85
+}
86
+
87
+static char *monitor_get_chardev_id(Object *obj, Error **errp)
88
+{
89
+ Monitor *mon = MONITOR(obj);
90
+
91
+ return g_strdup(mon->chardev_id);
92
+}
93
+
94
+static void monitor_set_chardev_id(Object *obj, const char *str, Error **errp)
95
+{
96
+ Monitor *mon = MONITOR(obj);
97
+
98
+ g_free(mon->chardev_id);
99
+ mon->chardev_id = g_strdup(str);
100
}
101
102
static void monitor_class_init(ObjectClass *cls, const void *data)
103
{
104
+ object_class_property_add_str(cls, "chardev",
105
+ monitor_get_chardev_id,
106
+ monitor_set_chardev_id);
107
}
108
109
static void monitor_init(Object *obj)
@@ -738,6 +759,21 @@ char *monitor_compat_id(void)
759
return g_strdup_printf("compat_monitor%d", monitor_device_index++);
760
}
761
762
+void monitor_complete(Monitor *mon, Error **errp)
763
+{
764
+ if (mon->chardev_id) {
765
+ Chardev *chr = qemu_chr_find(mon->chardev_id);
766
+ if (chr == NULL) {
767
+ error_setg(errp, "chardev \"%s\" not found", mon->chardev_id);
768
+ return;
769
+ }
770
+
771
+ if (!qemu_chr_fe_init(&mon->chr, chr, errp)) {
772
+ return;
773
+ }
774
+ }
775
+}
776
+
777
int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
778
{
779
ERRP_GUARD();
monitor/qmp.c
+15
-18
@@ -530,36 +530,33 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
530
void monitor_new_qmp(const char *id, const char *chardev_id,
531
bool pretty, Error **errp)
532
{
533
+ ERRP_GUARD();
534
MonitorQMP *mon;
535
g_autofree char *autoid = id ? NULL : monitor_compat_id();
535
- Chardev *chr;
536
- Object *obj;
536
+ Object *obj = object_new_with_props(TYPE_MONITOR_QMP,
537
+ object_get_objects_root(),
538
+ id ? id : autoid,
539
+ errp,
540
+ "chardev", chardev_id,
541
+ NULL);
542
538
- chr = qemu_chr_find(chardev_id);
539
- if (chr == NULL) {
540
- error_setg(errp, "chardev \"%s\" not found", chardev_id);
541
- return;
542
- }
543
-
544
- obj = object_new_with_props(TYPE_MONITOR_QMP,
545
- object_get_objects_root(),
546
- id ? id : autoid,
547
- errp,
548
- NULL);
543
if (!obj) {
544
return;
545
}
552
- mon = MONITOR_QMP(obj);
546
554
- if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
547
+ mon = MONITOR_QMP(obj);
548
+ monitor_complete(MONITOR(mon), errp);
549
+ if (*errp) {
550
object_unparent(OBJECT(mon));
551
return;
552
}
553
+
554
qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);
555
556
/* Note: we run QMP monitor in I/O thread when @chr supports that */
557
monitor_data_init(&mon->parent_obj, true, false,
562
- qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
558
+ qemu_chr_has_feature(mon->parent_obj.chr.chr,
559
+ QEMU_CHAR_FEATURE_GCONTEXT));
560
561
mon->pretty = pretty;
562
@@ -572,12 +569,12 @@ void monitor_new_qmp(const char *id, const char *chardev_id,
569
* Make sure the old iowatch is gone. It's possible when
570
* e.g. the chardev is in client mode, with wait=on.
571
*/
575
- remove_fd_in_watch(chr);
572
+ remove_fd_in_watch(mon->parent_obj.chr.chr);
573
/*
574
* Clean up listener IO sources early to prevent racy fd
575
* handling between the main thread and the I/O thread.
576
*/
580
- remove_listener_fd_in_watch(chr);
577
+ remove_listener_fd_in_watch(mon->parent_obj.chr.chr);
578
/*
579
* We can't call qemu_chr_fe_set_handlers() directly here
580
* since chardev might be running in the monitor I/O