mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:17 +00:00
monitor: implement "user creatable" interface for adding monitors
Implement the user creatable QOM interface and define the monitor-qmp and monitor-hmp types in QAPI. This unlocks the ability to create them on the command line with -object or in HMP/QMP with object_add. For example: $QEMU -chardev stdio,id=monchr0 -object monitor-hmp,id=mon0,chrdev=monchr0 Initially the "prepare_delete" callback is hardcoded to return an error which means -object and object_add can be used, but object_del will fail. Support for deleting monitors will be introduced in subsequent commits. Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Tested-by: Peter Krempa <pkrempa@redhat.com> Acked-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-ID: <20260706135824.2623960-24-berrange@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
committed by
Markus Armbruster
parent
b465a08b0c
commit
75f31e3a8a
@@ -40,6 +40,7 @@
|
||||
#include "qemu/target-info.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "system/block-backend.h"
|
||||
#include "trace.h"
|
||||
@@ -71,10 +72,13 @@ static void monitor_hmp_set_readline(Object *obj, bool val, Error **errp)
|
||||
int monitor_hmp_vprintf(Monitor *mon, const char *fmt, va_list ap)
|
||||
G_GNUC_PRINTF(2, 0);
|
||||
static void monitor_hmp_accept_input(Monitor *mon);
|
||||
static void monitor_hmp_complete(UserCreatable *uc, Error **errp);
|
||||
static bool monitor_hmp_prepare_delete(UserCreatable *uc, Error **errp);
|
||||
|
||||
static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
|
||||
{
|
||||
MonitorClass *moncls = MONITOR_CLASS(cls);
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(cls);
|
||||
|
||||
object_class_property_add_bool(cls, "readline",
|
||||
monitor_hmp_get_readline,
|
||||
@@ -82,6 +86,9 @@ static void monitor_hmp_class_init(ObjectClass *cls, const void *data)
|
||||
|
||||
moncls->vprintf = monitor_hmp_vprintf;
|
||||
moncls->accept_input = monitor_hmp_accept_input;
|
||||
|
||||
ucc->complete = monitor_hmp_complete;
|
||||
ucc->prepare_delete = monitor_hmp_prepare_delete;
|
||||
}
|
||||
|
||||
static void monitor_hmp_init(Object *obj)
|
||||
@@ -1605,29 +1612,31 @@ static void monitor_readline_flush(void *opaque)
|
||||
void monitor_new_hmp(const char *id, const char *chardev_id,
|
||||
bool use_readline, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
MonitorHMP *mon;
|
||||
g_autofree char *autoid = id ? NULL : monitor_compat_id();
|
||||
Object *obj = object_new_with_props(TYPE_MONITOR_HMP,
|
||||
object_new_with_props(TYPE_MONITOR_HMP,
|
||||
object_get_objects_root(),
|
||||
id ? id : autoid,
|
||||
errp,
|
||||
"chardev", chardev_id,
|
||||
"readline", use_readline ? "yes" : "no",
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
static void monitor_hmp_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
MonitorHMP *mon = MONITOR_HMP(uc);
|
||||
UserCreatableClass *ucc_parent =
|
||||
USER_CREATABLE_CLASS(
|
||||
object_class_get_parent(
|
||||
OBJECT_CLASS(MONITOR_HMP_GET_CLASS(mon))));
|
||||
ERRP_GUARD();
|
||||
|
||||
mon = MONITOR_HMP(obj);
|
||||
|
||||
monitor_complete(MONITOR(mon), errp);
|
||||
ucc_parent->complete(uc, errp);
|
||||
if (*errp) {
|
||||
object_unparent(OBJECT(mon));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mon->parent_obj.chardev_id) {
|
||||
if (mon->use_readline) {
|
||||
mon->rs = readline_init(monitor_readline_printf,
|
||||
monitor_readline_flush,
|
||||
@@ -1637,9 +1646,18 @@ void monitor_new_hmp(const char *id, const char *chardev_id,
|
||||
}
|
||||
|
||||
qemu_chr_fe_set_handlers(&mon->parent_obj.chr,
|
||||
monitor_can_read, monitor_read, monitor_event,
|
||||
NULL, &mon->parent_obj, NULL, true);
|
||||
monitor_can_read,
|
||||
monitor_read,
|
||||
monitor_event, NULL,
|
||||
&mon->parent_obj, NULL, true);
|
||||
monitor_list_append(&mon->parent_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static bool monitor_hmp_prepare_delete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Deleting HMP monitors is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -204,7 +204,6 @@ extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
|
||||
extern QemuMutex monitor_lock;
|
||||
extern MonitorList mon_list;
|
||||
|
||||
void monitor_complete(Monitor *mon, Error **errp);
|
||||
bool monitor_requires_iothread(const Monitor *mon);
|
||||
int monitor_can_read(void *opaque);
|
||||
void monitor_list_append(Monitor *mon);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "qapi/qapi-emit-events.h"
|
||||
#include "qapi/qapi-visit-control.h"
|
||||
#include "qobject/qdict.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "system/qtest.h"
|
||||
@@ -75,7 +76,8 @@ static bool monitor_destroyed;
|
||||
|
||||
int monitor_device_index;
|
||||
|
||||
OBJECT_DEFINE_ABSTRACT_TYPE(Monitor, monitor, MONITOR, OBJECT);
|
||||
OBJECT_DEFINE_TYPE_EXTENDED(Monitor, monitor, MONITOR, OBJECT, true,
|
||||
{ TYPE_USER_CREATABLE }, {});
|
||||
|
||||
static void monitor_finalize(Object *obj)
|
||||
{
|
||||
@@ -103,11 +105,17 @@ static void monitor_set_chardev_id(Object *obj, const char *str, Error **errp)
|
||||
mon->chardev_id = g_strdup(str);
|
||||
}
|
||||
|
||||
static void monitor_complete(UserCreatable *uc, Error **errp);
|
||||
|
||||
static void monitor_class_init(ObjectClass *cls, const void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(cls);
|
||||
|
||||
object_class_property_add_str(cls, "chardev",
|
||||
monitor_get_chardev_id,
|
||||
monitor_set_chardev_id);
|
||||
|
||||
ucc->complete = monitor_complete;
|
||||
}
|
||||
|
||||
static void monitor_init(Object *obj)
|
||||
@@ -689,8 +697,10 @@ char *monitor_compat_id(void)
|
||||
return g_strdup_printf("compat_monitor%d", monitor_device_index++);
|
||||
}
|
||||
|
||||
void monitor_complete(Monitor *mon, Error **errp)
|
||||
static void monitor_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
Monitor *mon = MONITOR(uc);
|
||||
|
||||
if (mon->chardev_id) {
|
||||
Chardev *chr = qemu_chr_find(mon->chardev_id);
|
||||
if (chr == NULL) {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "qobject/qdict.h"
|
||||
#include "qobject/qjson.h"
|
||||
#include "qobject/qlist.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
@@ -101,10 +102,13 @@ static void monitor_qmp_set_pretty(Object *obj, bool val, Error **errp)
|
||||
|
||||
static void monitor_qmp_emit_event(Monitor *mon, QAPIEvent event, QDict *qdict);
|
||||
static bool monitor_qmp_requires_iothread(const Monitor *mon);
|
||||
static void monitor_qmp_complete(UserCreatable *uc, Error **errp);
|
||||
static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp);
|
||||
|
||||
static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
|
||||
{
|
||||
MonitorClass *moncls = MONITOR_CLASS(cls);
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(cls);
|
||||
|
||||
object_class_property_add_bool(cls, "pretty",
|
||||
monitor_qmp_get_pretty,
|
||||
@@ -112,6 +116,9 @@ static void monitor_qmp_class_init(ObjectClass *cls, const void *data)
|
||||
|
||||
moncls->emit_event = monitor_qmp_emit_event;
|
||||
moncls->requires_iothread = monitor_qmp_requires_iothread;
|
||||
|
||||
ucc->complete = monitor_qmp_complete;
|
||||
ucc->prepare_delete = monitor_qmp_prepare_delete;
|
||||
}
|
||||
|
||||
static void handle_qmp_command(void *opaque, QObject *req, Error *err);
|
||||
@@ -583,25 +590,27 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
|
||||
void monitor_new_qmp(const char *id, const char *chardev_id,
|
||||
bool pretty, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
MonitorQMP *mon;
|
||||
g_autofree char *autoid = id ? NULL : monitor_compat_id();
|
||||
Object *obj = object_new_with_props(TYPE_MONITOR_QMP,
|
||||
object_new_with_props(TYPE_MONITOR_QMP,
|
||||
object_get_objects_root(),
|
||||
id ? id : autoid,
|
||||
errp,
|
||||
"chardev", chardev_id,
|
||||
"pretty", pretty ? "yes" : "no",
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
static void monitor_qmp_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
MonitorQMP *mon = MONITOR_QMP(uc);
|
||||
UserCreatableClass *ucc_parent =
|
||||
USER_CREATABLE_CLASS(
|
||||
object_class_get_parent(
|
||||
OBJECT_CLASS(MONITOR_QMP_GET_CLASS(mon))));
|
||||
ERRP_GUARD();
|
||||
|
||||
mon = MONITOR_QMP(obj);
|
||||
monitor_complete(MONITOR(mon), errp);
|
||||
ucc_parent->complete(uc, errp);
|
||||
if (*errp) {
|
||||
object_unparent(OBJECT(mon));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -633,3 +642,9 @@ void monitor_new_qmp(const char *id, const char *chardev_id,
|
||||
monitor_list_append(&mon->parent_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Deleting QMP monitors is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1187,6 +1187,45 @@
|
||||
'data': { '*cpu-affinity': ['uint16'],
|
||||
'*node-affinity': ['uint16'] } }
|
||||
|
||||
##
|
||||
# @MonitorProperties:
|
||||
#
|
||||
# Properties for all monitors
|
||||
#
|
||||
# @chardev: ID of the character device providing the monitor transport
|
||||
#
|
||||
# Since: 11.1
|
||||
##
|
||||
{ 'struct': 'MonitorProperties',
|
||||
'data': { 'chardev': 'str' }}
|
||||
|
||||
##
|
||||
# @MonitorHMPProperties:
|
||||
#
|
||||
# Properties for the HMP monitor
|
||||
#
|
||||
# @readline: whether to enable readline for line editing
|
||||
# (default: true)
|
||||
#
|
||||
# Since: 11.1
|
||||
##
|
||||
{ 'struct': 'MonitorHMPProperties',
|
||||
'base': 'MonitorProperties',
|
||||
'data': { '*readline': 'bool' } }
|
||||
|
||||
##
|
||||
# @MonitorQMPProperties:
|
||||
#
|
||||
# Properties for the QMP monitor
|
||||
#
|
||||
# @pretty: whether to pretty print JSON responses (default: false)
|
||||
#
|
||||
# Since: 11.1
|
||||
##
|
||||
{ 'struct': 'MonitorQMPProperties',
|
||||
'base': 'MonitorProperties',
|
||||
'data': { '*pretty': 'bool' } }
|
||||
|
||||
##
|
||||
# @ObjectType:
|
||||
#
|
||||
@@ -1237,6 +1276,8 @@
|
||||
'memory-backend-ram',
|
||||
{ 'name': 'memory-backend-shm',
|
||||
'if': 'CONFIG_POSIX' },
|
||||
'monitor-hmp',
|
||||
'monitor-qmp',
|
||||
'pef-guest',
|
||||
{ 'name': 'pr-manager-helper',
|
||||
'if': 'CONFIG_LINUX' },
|
||||
@@ -1315,6 +1356,8 @@
|
||||
'memory-backend-ram': 'MemoryBackendProperties',
|
||||
'memory-backend-shm': { 'type': 'MemoryBackendShmProperties',
|
||||
'if': 'CONFIG_POSIX' },
|
||||
'monitor-hmp': 'MonitorHMPProperties',
|
||||
'monitor-qmp': 'MonitorQMPProperties',
|
||||
'pr-manager-helper': { 'type': 'PrManagerHelperProperties',
|
||||
'if': 'CONFIG_LINUX' },
|
||||
'qtest': 'QtestProperties',
|
||||
|
||||
@@ -11,4 +11,5 @@ int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
|
||||
void monitor_new_hmp(const char *id, const char *chardev_id,
|
||||
bool use_readline, Error **errp)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
@@ -1829,6 +1829,10 @@ static void object_option_add_visitor(Visitor *v)
|
||||
{
|
||||
ObjectOption *opt = g_new0(ObjectOption, 1);
|
||||
visit_type_ObjectOptions(v, NULL, &opt->opts, &error_fatal);
|
||||
if (opt->opts->qom_type == OBJECT_TYPE_MONITOR_HMP ||
|
||||
opt->opts->qom_type == OBJECT_TYPE_MONITOR_QMP) {
|
||||
default_monitor = 0;
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&object_opts, opt, next);
|
||||
}
|
||||
|
||||
@@ -1970,7 +1974,9 @@ static bool object_create_early(const char *type)
|
||||
|
||||
/* Reason: property "chardev" */
|
||||
if (g_str_equal(type, "rng-egd") ||
|
||||
g_str_equal(type, "qtest")) {
|
||||
g_str_equal(type, "qtest") ||
|
||||
g_str_equal(type, "monitor-hmp") ||
|
||||
g_str_equal(type, "monitor-qmp")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user