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>
This commit is contained in:
Daniel P. Berrangé
2026-07-06 14:57:53 +01:00
committed by Markus Armbruster
parent fc500ce4d3
commit f96eac8a4f
10 changed files with 129 additions and 29 deletions

View File

@@ -805,7 +805,7 @@ static Chardev *qemu_chr_new_from_name(const char *label, const char *filename,
if (qemu_opt_get_bool(opts, "mux", 0)) {
assert(permit_mux_mon);
monitor_new_hmp(chr, true, &err);
monitor_new_hmp(NULL, chr, true, &err);
if (err) {
error_report_err(err);
object_unparent(OBJECT(chr));

View File

@@ -390,7 +390,7 @@ bool gdbserver_start(const char *device, Error **errp)
/* Initialize a monitor terminal for gdb */
mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
NULL, NULL, &error_abort);
monitor_new_hmp(mon_chr, false, &error_abort);
monitor_new_hmp(NULL, mon_chr, false, &error_abort);
} else {
qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
mon_chr = gdbserver_system_state.mon_chr;

View File

@@ -5,8 +5,17 @@
#include "qapi/qapi-types-misc.h"
#include "qemu/readline.h"
#include "exec/hwaddr.h"
#include "qom/object.h"
#define TYPE_MONITOR "monitor"
OBJECT_DECLARE_TYPE(Monitor, MonitorClass, MONITOR);
#define TYPE_MONITOR_HMP "monitor-hmp"
OBJECT_DECLARE_TYPE(MonitorHMP, MonitorHMPClass, MONITOR_HMP);
#define TYPE_MONITOR_QMP "monitor-qmp"
OBJECT_DECLARE_TYPE(MonitorQMP, MonitorQMPClass, MONITOR_QMP);
typedef struct MonitorHMP MonitorHMP;
typedef struct MonitorOptions MonitorOptions;
#define QMP_REQ_QUEUE_LEN_MAX 8
@@ -19,8 +28,11 @@ bool monitor_cur_is_qmp(void);
void monitor_init_globals(void);
void monitor_init_globals_core(void);
void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp);
void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp);
char *monitor_compat_id(void);
void monitor_new_qmp(const char *id, Chardev *chr,
bool pretty, Error **errp);
void monitor_new_hmp(const char *id, Chardev *chr,
bool use_readline, Error **errp);
int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp);
int monitor_new_opts(QemuOpts *opts, Error **errp);
void monitor_cleanup(void);

View File

@@ -43,6 +43,20 @@
#include "system/block-backend.h"
#include "trace.h"
OBJECT_DEFINE_TYPE(MonitorHMP, monitor_hmp, MONITOR_HMP, MONITOR);
static void monitor_hmp_finalize(Object *obj)
{
}
static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
{
}
static void monitor_hmp_init(Object *obj)
{
}
static void monitor_command_cb(void *opaque, const char *cmdline,
void *readline_opaque)
{
@@ -1524,12 +1538,23 @@ static void monitor_readline_flush(void *opaque)
monitor_flush(&mon->parent_obj);
}
void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
void monitor_new_hmp(const char *id, Chardev *chr,
bool use_readline, Error **errp)
{
MonitorHMP *mon = g_new0(MonitorHMP, 1);
MonitorHMP *mon;
g_autofree char *autoid = id ? NULL : monitor_compat_id();
Object *obj = object_new_with_props(TYPE_MONITOR_HMP,
object_get_objects_root(),
id ? id : autoid,
errp,
NULL);
if (!obj) {
return;
}
mon = MONITOR_HMP(obj);
if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
g_free(mon);
object_unparent(OBJECT(mon));
return;
}

View File

@@ -101,7 +101,13 @@ typedef struct HMPCommand {
bool coroutine;
} HMPCommand;
struct MonitorClass {
ObjectClass parent_class;
};
struct Monitor {
Object parent;
CharFrontend chr;
int suspend_cnt; /* Needs to be accessed atomically */
bool is_qmp;
@@ -127,6 +133,10 @@ struct Monitor {
int reset_seen;
};
struct MonitorHMPClass {
MonitorClass parent_class;
};
struct MonitorHMP {
Monitor parent_obj;
bool use_readline;
@@ -140,7 +150,11 @@ struct MonitorHMP {
ReadLineState *rs;
};
typedef struct {
struct MonitorQMPClass {
MonitorClass parent_class;
};
struct MonitorQMP {
Monitor parent_obj;
JSONMessageParser parser;
bool pretty;
@@ -160,7 +174,7 @@ typedef struct {
QemuMutex qmp_queue_lock;
/* Input queue that holds all the parsed QMP requests */
GQueue *qmp_requests;
} MonitorQMP;
};
/**
* Is @mon a QMP monitor?

View File

@@ -73,6 +73,22 @@ static GHashTable *coroutine_mon; /* Maps Coroutine* to Monitor* */
MonitorList mon_list;
static bool monitor_destroyed;
int monitor_device_index;
OBJECT_DEFINE_ABSTRACT_TYPE(Monitor, monitor, MONITOR, OBJECT);
static void monitor_finalize(Object *obj)
{
}
static void monitor_class_init(ObjectClass *cls, const void *data)
{
}
static void monitor_init(Object *obj)
{
}
Monitor *monitor_cur(void)
{
Monitor *mon;
@@ -598,7 +614,7 @@ void monitor_list_append(Monitor *mon)
if (mon) {
monitor_data_destroy(mon);
g_free(mon);
object_unparent(OBJECT(mon));
}
}
@@ -680,7 +696,7 @@ void monitor_cleanup(void)
monitor_flush(mon);
monitor_data_destroy(mon);
qemu_mutex_lock(&monitor_lock);
g_free(mon);
object_unparent(OBJECT(mon));
}
qemu_mutex_unlock(&monitor_lock);
@@ -715,6 +731,13 @@ void monitor_init_globals(void)
aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co);
}
char *monitor_compat_id(void)
{
static int monitor_device_index;
return g_strdup_printf("compat_monitor%d", monitor_device_index++);
}
int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
{
ERRP_GUARD();
@@ -732,7 +755,7 @@ int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
switch (opts->mode) {
case MONITOR_MODE_CONTROL:
monitor_new_qmp(chr, opts->pretty, errp);
monitor_new_qmp(opts->id, chr, opts->pretty, errp);
break;
case MONITOR_MODE_READLINE:
if (!allow_hmp) {
@@ -743,7 +766,7 @@ int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
error_setg(errp, "'pretty' is not compatible with HMP monitors");
return -1;
}
monitor_new_hmp(chr, true, errp);
monitor_new_hmp(opts->id, chr, true, errp);
break;
default:
g_assert_not_reached();

View File

@@ -166,12 +166,12 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
int64_t cpu_index, Error **errp)
{
char *output = NULL;
MonitorHMP hmp = {};
MonitorHMP *hmp = MONITOR_HMP(object_new(TYPE_MONITOR_HMP));
monitor_data_init(&hmp.parent_obj, false, true, false);
monitor_data_init(&hmp->parent_obj, false, true, false);
if (has_cpu_index) {
int ret = monitor_set_cpu(&hmp.parent_obj, cpu_index);
int ret = monitor_set_cpu(&hmp->parent_obj, cpu_index);
if (ret < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
"a CPU number");
@@ -179,14 +179,15 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
}
}
handle_hmp_command(&hmp, command_line);
handle_hmp_command(hmp, command_line);
WITH_QEMU_LOCK_GUARD(&hmp.parent_obj.mon_lock) {
output = g_strdup(hmp.parent_obj.outbuf->str);
WITH_QEMU_LOCK_GUARD(&hmp->parent_obj.mon_lock) {
output = g_strdup(hmp->parent_obj.outbuf->str);
}
out:
monitor_data_destroy(&hmp.parent_obj);
monitor_data_destroy(&hmp->parent_obj);
object_unref(hmp);
return output;
}

View File

@@ -71,6 +71,20 @@ typedef struct QMPRequest QMPRequest;
QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
OBJECT_DEFINE_TYPE(MonitorQMP, monitor_qmp, MONITOR_QMP, MONITOR);
static void monitor_qmp_finalize(Object *obj)
{
}
static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
{
}
static void monitor_qmp_init(Object *obj)
{
}
static bool qmp_oob_enabled(MonitorQMP *mon)
{
return mon->capab[QMP_CAPABILITY_OOB];
@@ -513,12 +527,23 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
monitor_list_append(&mon->parent_obj);
}
void monitor_new_qmp(Chardev *chr, bool pretty, Error **errp)
void monitor_new_qmp(const char *id, Chardev *chr,
bool pretty, Error **errp)
{
MonitorQMP *mon = g_new0(MonitorQMP, 1);
MonitorQMP *mon;
g_autofree char *autoid = id ? NULL : monitor_compat_id();
Object *obj = object_new_with_props(TYPE_MONITOR_QMP,
object_get_objects_root(),
id ? id : autoid,
errp,
NULL);
if (!obj) {
return;
}
mon = MONITOR_QMP(obj);
if (!qemu_chr_fe_init(&mon->parent_obj.chr, chr, errp)) {
g_free(mon);
object_unparent(OBJECT(mon));
return;
}
qemu_chr_fe_set_echo(&mon->parent_obj.chr, true);

View File

@@ -8,6 +8,7 @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
return -1;
}
void monitor_new_hmp(Chardev *chr, bool use_readline, Error **errp)
void monitor_new_hmp(const char *id, Chardev *chr,
bool use_readline, Error **errp)
{
}

View File

@@ -1252,7 +1252,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
static void monitor_parse(const char *str, const char *mode, bool pretty)
{
static int monitor_device_index = 0;
QemuOpts *opts;
const char *p;
char label[32];
@@ -1260,8 +1259,9 @@ static void monitor_parse(const char *str, const char *mode, bool pretty)
if (strstart(str, "chardev:", &p)) {
snprintf(label, sizeof(label), "%s", p);
} else {
snprintf(label, sizeof(label), "compat_monitor%d",
monitor_device_index);
g_autofree char *id = monitor_compat_id();
assert(strlen(id) < sizeof(label));
memcpy(label, id, strlen(id) + 1);
opts = qemu_chr_parse_compat(label, str, true);
if (!opts) {
error_report("parse error: %s", str);
@@ -1277,7 +1277,6 @@ static void monitor_parse(const char *str, const char *mode, bool pretty)
} else {
assert(pretty == false);
}
monitor_device_index++;
}
struct device_config {