[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 05/13] qapi: add a top-unit 'target' schema
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH 05/13] qapi: add a top-unit 'target' schema |
Date: |
Sun, 16 Dec 2018 18:08:54 +0400 |
Add a 'target' top-unit to be compiled seperately from the common qapi
modules. This will allow poisoned target #ifdef usage.
The generated commands must be registered seperately.
The events have a different enum, and must thus use a different
emitter/limiter.
The DUMMY event is there to force the visit of target, ensuring files
are built. It is removed in next commit.
Signed-off-by: Marc-André Lureau <address@hidden>
---
qapi/qapi-schema.json | 1 +
qapi/target.json | 13 +++
include/qapi/qmp-event.h | 4 +
monitor.c | 216 ++++++++++++++++++++++++++-------------
qapi/qmp-event.c | 11 ++
Makefile | 7 +-
Makefile.target | 2 +
7 files changed, 181 insertions(+), 73 deletions(-)
create mode 100644 qapi/target.json
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 65b6dc2f6f..4a836d6c9f 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -94,3 +94,4 @@
{ 'include': 'trace.json' }
{ 'include': 'introspect.json' }
{ 'include': 'misc.json' }
+{ 'include': 'target.json' }
diff --git a/qapi/target.json b/qapi/target.json
new file mode 100644
index 0000000000..be2360ca34
--- /dev/null
+++ b/qapi/target.json
@@ -0,0 +1,13 @@
+# -*- Mode: Python -*-
+#
+
+##
+# = Target-specific commands & events
+##
+
+{ 'pragma': { 'top-unit': 'target' } }
+
+##
+# @DUMMY:
+##
+{ 'event': 'DUMMY' }
diff --git a/include/qapi/qmp-event.h b/include/qapi/qmp-event.h
index 23e588ccf8..da752f8371 100644
--- a/include/qapi/qmp-event.h
+++ b/include/qapi/qmp-event.h
@@ -20,5 +20,9 @@ void qmp_event_set_func_emit(QMPEventFuncEmit emit);
QMPEventFuncEmit qmp_event_get_func_emit(void);
+void target_qmp_event_set_func_emit(QMPEventFuncEmit emit);
+
+QMPEventFuncEmit target_qmp_event_get_func_emit(void);
+
QDict *qmp_event_build_dict(const char *event_name);
#endif
diff --git a/monitor.c b/monitor.c
index 720d8d98a7..86f3193158 100644
--- a/monitor.c
+++ b/monitor.c
@@ -76,6 +76,8 @@
#include "block/qapi.h"
#include "qapi/qapi-commands.h"
#include "qapi/qapi-events.h"
+#include "qapi/target-qapi-commands.h"
+#include "qapi/target-qapi-events.h"
#include "qapi/error.h"
#include "qapi/qmp-event.h"
#include "qapi/qapi-introspect.h"
@@ -185,22 +187,25 @@ typedef struct {
GQueue *qmp_requests;
} MonitorQMP;
+typedef struct {
+ GHashTable *state;
+ const size_t size; /* size of array == number of events */
+ const int64_t rate[]; /* Minimum time (in ns) between two events */
+} MonitorEventRateLimit;
+
/*
* To prevent flooding clients, events can be throttled. The
* throttling is calculated globally, rather than per-Monitor
* instance.
*/
typedef struct MonitorQAPIEventState {
- QAPIEvent event; /* Throttling state for this event type and... */
+ const MonitorEventRateLimit *limiter;
+ unsigned event; /* Throttling state for this event type and... */
QDict *data; /* ... data, see qapi_event_throttle_equal() */
QEMUTimer *timer; /* Timer for handling delayed events */
QDict *qdict; /* Delayed event (if any) */
} MonitorQAPIEventState;
-typedef struct {
- int64_t rate; /* Minimum time (in ns) between two events */
-} MonitorQAPIEventConf;
-
struct Monitor {
CharBackend chr;
int reset_seen;
@@ -263,9 +268,8 @@ typedef struct QMPRequest QMPRequest;
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
-/* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */
+/* Protects mon_list, limiter, monitor_qapi_event_state, monitor_destroyed. */
static QemuMutex monitor_lock;
-static GHashTable *monitor_qapi_event_state;
static QTAILQ_HEAD(mon_list, Monitor) mon_list;
static bool monitor_destroyed;
@@ -500,22 +504,12 @@ static void qmp_send_response(Monitor *mon, const QDict
*rsp)
qobject_unref(json);
}
-static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
- /* Limit guest-triggerable events to 1 per second */
- [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
- [QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS },
- [QAPI_EVENT_BALLOON_CHANGE] = { 1000 * SCALE_MS },
- [QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS },
- [QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS },
- [QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS },
-};
-
/*
* Broadcast an event to all monitors.
* @qdict is the event object. Its member "event" must match @event.
* Caller must hold monitor_lock.
*/
-static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict)
+static void monitor_qapi_event_emit(unsigned event, QDict *qdict)
{
Monitor *mon;
@@ -535,30 +529,31 @@ static void monitor_qapi_event_handler(void *opaque);
* applying any rate limiting if required.
*/
static void
-monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
+monitor_qapi_event_queue_no_reenter(const MonitorEventRateLimit *limiter,
+ unsigned event, QDict *qdict)
{
- MonitorQAPIEventConf *evconf;
+ int64_t rate;
MonitorQAPIEventState *evstate;
- assert(event < QAPI_EVENT__MAX);
- evconf = &monitor_qapi_event_conf[event];
- trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
+ assert(event < limiter->size);
+ rate = limiter->rate[event];
+ trace_monitor_protocol_event_queue(event, qdict, rate);
qemu_mutex_lock(&monitor_lock);
- if (!evconf->rate) {
+ if (!rate) {
/* Unthrottled event */
monitor_qapi_event_emit(event, qdict);
} else {
QDict *data = qobject_to(QDict, qdict_get(qdict, "data"));
MonitorQAPIEventState key = { .event = event, .data = data };
- evstate = g_hash_table_lookup(monitor_qapi_event_state, &key);
+ evstate = g_hash_table_lookup(limiter->state, &key);
assert(!evstate || timer_pending(evstate->timer));
if (evstate) {
/*
- * Timer is pending for (at least) evconf->rate ns after
+ * Timer is pending for (at least) rate ns after
* last send. Store event for sending when timer fires,
* replacing a prior stored event if any.
*/
@@ -566,9 +561,9 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict
*qdict)
evstate->qdict = qobject_ref(qdict);
} else {
/*
- * Last send was (at least) evconf->rate ns ago.
+ * Last send was (at least) rate ns ago.
* Send immediately, and arm the timer to call
- * monitor_qapi_event_handler() in evconf->rate ns. Any
+ * monitor_qapi_event_handler() in rate ns. Any
* events arriving before then will be delayed until then.
*/
int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
@@ -576,14 +571,15 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event,
QDict *qdict)
monitor_qapi_event_emit(event, qdict);
evstate = g_new(MonitorQAPIEventState, 1);
+ evstate->limiter = limiter;
evstate->event = event;
evstate->data = qobject_ref(data);
evstate->qdict = NULL;
evstate->timer = timer_new_ns(monitor_get_event_clock(),
monitor_qapi_event_handler,
evstate);
- g_hash_table_add(monitor_qapi_event_state, evstate);
- timer_mod_ns(evstate->timer, now + evconf->rate);
+ g_hash_table_add(limiter->state, evstate);
+ timer_mod_ns(evstate->timer, now + rate);
}
}
@@ -591,7 +587,8 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict
*qdict)
}
static void
-monitor_qapi_event_queue(QAPIEvent event, QDict *qdict)
+monitor_qapi_event_queue_limit(const MonitorEventRateLimit *limiter,
+ QAPIEvent event, QDict *qdict)
{
/*
* monitor_qapi_event_queue_no_reenter() is not reentrant: it
@@ -624,7 +621,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict)
while ((ev = QSIMPLEQ_FIRST(&event_queue)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&event_queue, entry);
- monitor_qapi_event_queue_no_reenter(ev->event, ev->qdict);
+ monitor_qapi_event_queue_no_reenter(limiter, ev->event, ev->qdict);
qobject_unref(ev->qdict);
g_free(ev);
}
@@ -632,36 +629,6 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict)
reentered = false;
}
-/*
- * This function runs evconf->rate ns after sending a throttled
- * event.
- * If another event has since been stored, send it.
- */
-static void monitor_qapi_event_handler(void *opaque)
-{
- MonitorQAPIEventState *evstate = opaque;
- MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
-
- trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
- qemu_mutex_lock(&monitor_lock);
-
- if (evstate->qdict) {
- int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
-
- monitor_qapi_event_emit(evstate->event, evstate->qdict);
- qobject_unref(evstate->qdict);
- evstate->qdict = NULL;
- timer_mod_ns(evstate->timer, now + evconf->rate);
- } else {
- g_hash_table_remove(monitor_qapi_event_state, evstate);
- qobject_unref(evstate->data);
- timer_free(evstate->timer);
- g_free(evstate);
- }
-
- qemu_mutex_unlock(&monitor_lock);
-}
-
static unsigned int qapi_event_throttle_hash(const void *key)
{
const MonitorQAPIEventState *evstate = key;
@@ -700,11 +667,103 @@ static gboolean qapi_event_throttle_equal(const void *a,
const void *b)
return TRUE;
}
+static void
+monitor_qapi_event_queue(unsigned event, QDict *qdict)
+{
+ static MonitorEventRateLimit limiter = {
+ .size = QAPI_EVENT__MAX,
+ .rate = {
+ /* Limit guest-triggerable events to 1 per second */
+ [QAPI_EVENT_RTC_CHANGE] = 1000 * SCALE_MS,
+ [QAPI_EVENT_WATCHDOG] = 1000 * SCALE_MS,
+ [QAPI_EVENT_BALLOON_CHANGE] = 1000 * SCALE_MS,
+ [QAPI_EVENT_QUORUM_REPORT_BAD] = 1000 * SCALE_MS,
+ [QAPI_EVENT_QUORUM_FAILURE] = 1000 * SCALE_MS,
+ [QAPI_EVENT_VSERPORT_CHANGE] = 1000 * SCALE_MS,
+ [QAPI_EVENT__MAX] = 0,
+ },
+ };
+
+ if (!limiter.state) {
+ limiter.state = g_hash_table_new(qapi_event_throttle_hash,
+ qapi_event_throttle_equal);
+ }
+
+ monitor_qapi_event_queue_limit(&limiter, event, qdict);
+}
+
+static unsigned int target_qapi_event_throttle_hash(const void *key)
+{
+ const MonitorQAPIEventState *evstate = key;
+ unsigned int hash = evstate->event * 255;
+
+ return hash;
+}
+
+static gboolean target_qapi_event_throttle_equal(const void *a, const void *b)
+{
+ const MonitorQAPIEventState *eva = a;
+ const MonitorQAPIEventState *evb = b;
+
+ if (eva->event != evb->event) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+target_monitor_qapi_event_queue(unsigned event, QDict *qdict)
+{
+ static MonitorEventRateLimit limiter = {
+ .size = TARGET_QAPI_EVENT__MAX,
+ .rate = {
+ [TARGET_QAPI_EVENT__MAX] = 0,
+ },
+ };
+
+ if (!limiter.state) {
+ limiter.state = g_hash_table_new(target_qapi_event_throttle_hash,
+ target_qapi_event_throttle_equal);
+ }
+ monitor_qapi_event_queue_limit(&limiter, event, qdict);
+}
+
+/*
+ * This function runs evconf->rate ns after sending a throttled
+ * event.
+ * If another event has since been stored, send it.
+ */
+static void monitor_qapi_event_handler(void *opaque)
+{
+ MonitorQAPIEventState *evstate = opaque;
+ const MonitorEventRateLimit *limiter = evstate->limiter;
+ int64_t rate = limiter->rate[evstate->event];
+
+ trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
+ qemu_mutex_lock(&monitor_lock);
+
+ if (evstate->qdict) {
+ int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
+
+ monitor_qapi_event_emit(evstate->event, evstate->qdict);
+ qobject_unref(evstate->qdict);
+ evstate->qdict = NULL;
+ timer_mod_ns(evstate->timer, now + rate);
+ } else {
+ g_hash_table_remove(limiter->state, evstate);
+ qobject_unref(evstate->data);
+ timer_free(evstate->timer);
+ g_free(evstate);
+ }
+
+ qemu_mutex_unlock(&monitor_lock);
+}
+
static void monitor_qapi_event_init(void)
{
- monitor_qapi_event_state = g_hash_table_new(qapi_event_throttle_hash,
- qapi_event_throttle_equal);
qmp_event_set_func_emit(monitor_qapi_event_queue);
+ target_qmp_event_set_func_emit(target_monitor_qapi_event_queue);
}
static void handle_hmp_command(Monitor *mon, const char *cmdline);
@@ -1099,9 +1158,10 @@ CommandInfoList *qmp_query_commands(Error **errp)
return list;
}
-EventInfoList *qmp_query_events(Error **errp)
+static void qmp_query_events_list(EventInfoList **list,
+ const QEnumLookup *qenum, int max)
{
- EventInfoList *info, *ev_list = NULL;
+ EventInfoList *info;
QAPIEvent e;
for (e = 0 ; e < QAPI_EVENT__MAX ; e++) {
@@ -1111,11 +1171,22 @@ EventInfoList *qmp_query_events(Error **errp)
info->value = g_malloc0(sizeof(*info->value));
info->value->name = g_strdup(event_name);
- info->next = ev_list;
- ev_list = info;
+ info->next = *list;
+ *list = info;
}
- return ev_list;
+}
+
+EventInfoList *qmp_query_events(Error **errp)
+{
+ EventInfoList *list = NULL;
+
+ qmp_query_events_list(&list, &QAPIEvent_lookup,
+ QAPI_EVENT__MAX);
+ qmp_query_events_list(&list, &target_QAPIEvent_lookup,
+ TARGET_QAPI_EVENT__MAX);
+
+ return list;
}
/*
@@ -1183,6 +1254,7 @@ static void monitor_init_qmp_commands(void)
QTAILQ_INIT(&qmp_commands);
qmp_register_commands(&qmp_commands);
+ target_qmp_register_commands(&qmp_commands);
qmp_register_command(&qmp_commands, "query-qmp-schema",
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
@@ -2941,11 +3013,11 @@ static int default_fmt_size = 4;
static int is_valid_option(const char *c, const char *typestr)
{
char option[3];
-
+
option[0] = '-';
option[1] = *c;
option[2] = '\0';
-
+
typestr = strstr(typestr, option);
return (typestr != NULL);
}
@@ -3318,7 +3390,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
p++;
if(c != *p) {
if(!is_valid_option(p, typestr)) {
-
+
monitor_printf(mon, "%s: unsupported option -%c\n",
cmd->name, *p);
goto fail;
diff --git a/qapi/qmp-event.c b/qapi/qmp-event.c
index 5b8854043e..a0f7dd8ac2 100644
--- a/qapi/qmp-event.c
+++ b/qapi/qmp-event.c
@@ -20,6 +20,7 @@
#include "qapi/qmp/qjson.h"
static QMPEventFuncEmit qmp_emit;
+static QMPEventFuncEmit target_qmp_emit;
void qmp_event_set_func_emit(QMPEventFuncEmit emit)
{
@@ -31,6 +32,16 @@ QMPEventFuncEmit qmp_event_get_func_emit(void)
return qmp_emit;
}
+void target_qmp_event_set_func_emit(QMPEventFuncEmit emit)
+{
+ target_qmp_emit = emit;
+}
+
+QMPEventFuncEmit target_qmp_event_get_func_emit(void)
+{
+ return target_qmp_emit;
+}
+
static void timestamp_put(QDict *qdict)
{
int err;
diff --git a/Makefile b/Makefile
index c8b9efdad4..01a31e2ea5 100644
--- a/Makefile
+++ b/Makefile
@@ -92,16 +92,20 @@ GENERATED_FILES = qemu-version.h config-host.h
qemu-options.def
#see Makefile.objs for the definition of QAPI_MODULES
GENERATED_QAPI_FILES = qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c
GENERATED_QAPI_FILES += qapi/qapi-types.h qapi/qapi-types.c
+GENERATED_QAPI_FILES += qapi/target-qapi-types.h qapi/target-qapi-types.c
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-types-%.h)
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-types-%.c)
GENERATED_QAPI_FILES += qapi/qapi-builtin-visit.h qapi/qapi-builtin-visit.c
GENERATED_QAPI_FILES += qapi/qapi-visit.h qapi/qapi-visit.c
+GENERATED_QAPI_FILES += qapi/target-qapi-visit.h qapi/target-qapi-visit.c
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.h)
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.c)
GENERATED_QAPI_FILES += qapi/qapi-commands.h qapi/qapi-commands.c
+GENERATED_QAPI_FILES += qapi/target-qapi-commands.h qapi/target-qapi-commands.c
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.h)
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.c)
GENERATED_QAPI_FILES += qapi/qapi-events.h qapi/qapi-events.c
+GENERATED_QAPI_FILES += qapi/target-qapi-events.h qapi/target-qapi-events.c
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.h)
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.c)
GENERATED_QAPI_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
@@ -528,7 +532,8 @@ qga/qapi-generated/qapi-gen-timestamp:
$(SRC_PATH)/qga/qapi-schema.json $(qapi-p
@>$@
qapi-modules = $(SRC_PATH)/qapi/qapi-schema.json \
- $(QAPI_MODULES:%=$(SRC_PATH)/qapi/%.json)
+ $(QAPI_MODULES:%=$(SRC_PATH)/qapi/%.json) \
+ $(SRC_PATH)/qapi/target.json
$(GENERATED_QAPI_FILES): qapi-gen-timestamp ;
qapi-gen-timestamp: $(qapi-modules) $(qapi-py)
diff --git a/Makefile.target b/Makefile.target
index c882292ae1..95ebaf1fa7 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -156,6 +156,8 @@ endif
GENERATED_FILES += hmp-commands.h hmp-commands-info.h
+obj-y += qapi/target-qapi-types.o qapi/target-qapi-visit.o
+obj-y += qapi/target-qapi-events.o qapi/target-qapi-commands.o
obj-y += qapi/qapi-introspect.o
endif # CONFIG_SOFTMMU
--
2.20.0
- [Qemu-devel] [PATCH 00/13] qapi: add #if pre-processor conditions to generated code (part 3), Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 01/13] build-sys: move qmp-introspect per target, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 02/13] qapi-commands: don't initialize command list in qmp_init_marshall(), Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 03/13] qapi-commands: rename init_marshal() to register_commands(), Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 04/13] RFC: qapi: learn to split the schema by 'top-unit', Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 05/13] qapi: add a top-unit 'target' schema,
Marc-André Lureau <=
- [Qemu-devel] [PATCH 06/13] qapi: make rtc-reset-reinjection and SEV depend on TARGET_I386, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 07/13] qapi: make s390 commands depend on TARGET_S390X, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 08/13] target.json: add a note about query-cpu* not being s390x-specific, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 09/13] qapi: make query-gic-capabilities depend on TARGET_ARM, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 10/13] qapi: make query-cpu-model-expansion depend on s390 or x86, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 11/13] qapi: make query-cpu-definitions depend on specific targets, Marc-André Lureau, 2018/12/16
- [Qemu-devel] [PATCH 12/13] qapi: remove qmp_unregister_command(), Marc-André Lureau, 2018/12/16