From 43a14cfc0f122f3a18fdfe9e16538a6798b95b59 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 18 Jun 2014 08:43:31 +0200 Subject: monitor: add an implemention of qapi event emit method The monitor is now hooked on the new event mechanism, so that later patches can convert event callers one by one. Most code are copied from old monitor_protocol_* functions with some modification. Note that two build time warnings will be raised after this patch. One is caused by no caller of monitor_qapi_event_throttle(), the other one is caused by QAPI_EVENT_MAX = 0. They will be fixed automatically after full event conversion later. Signed-off-by: Wenchao Xia Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- monitor.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index c7f879713e..2c0b747fe8 100644 --- a/monitor.c +++ b/monitor.c @@ -71,6 +71,8 @@ #include "hmp.h" #include "qemu/thread.h" #include "block/qapi.h" +#include "qapi/qmp-event.h" +#include "qapi-event.h" /* for pic/irq_info */ #if defined(TARGET_SPARC) @@ -187,6 +189,14 @@ typedef struct MonitorEventState { QObject *data; /* Event pending delayed dispatch */ } MonitorEventState; +typedef struct MonitorQAPIEventState { + QAPIEvent event; /* Event being tracked */ + int64_t rate; /* Minimum time (in ns) between two events */ + int64_t last; /* QEMU_CLOCK_REALTIME value at last emission */ + QEMUTimer *timer; /* Timer for handling delayed events */ + QObject *data; /* Event pending delayed dispatch */ +} MonitorQAPIEventState; + struct Monitor { CharDriverState *chr; int mux_out; @@ -492,6 +502,121 @@ static const char *monitor_event_names[] = { QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) static MonitorEventState monitor_event_state[QEVENT_MAX]; +static MonitorQAPIEventState monitor_qapi_event_state[QAPI_EVENT_MAX]; + +/* + * Emits the event to every monitor instance, @event is only used for trace + */ +static void monitor_qapi_event_emit(QAPIEvent event, QObject *data) +{ + Monitor *mon; + + trace_monitor_protocol_event_emit(event, data); + QLIST_FOREACH(mon, &mon_list, entry) { + if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) { + monitor_json_emitter(mon, data); + } + } +} + +/* + * Queue a new event for emission to Monitor instances, + * applying any rate limiting if required. + */ +static void +monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp) +{ + MonitorQAPIEventState *evstate; + assert(event < QAPI_EVENT_MAX); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + evstate = &(monitor_qapi_event_state[event]); + trace_monitor_protocol_event_queue(event, + data, + evstate->rate, + evstate->last, + now); + + /* Rate limit of 0 indicates no throttling */ + if (!evstate->rate) { + monitor_qapi_event_emit(event, QOBJECT(data)); + evstate->last = now; + } else { + int64_t delta = now - evstate->last; + if (evstate->data || + delta < evstate->rate) { + /* If there's an existing event pending, replace + * it with the new event, otherwise schedule a + * timer for delayed emission + */ + if (evstate->data) { + qobject_decref(evstate->data); + } else { + int64_t then = evstate->last + evstate->rate; + timer_mod_ns(evstate->timer, then); + } + evstate->data = QOBJECT(data); + qobject_incref(evstate->data); + } else { + monitor_qapi_event_emit(event, QOBJECT(data)); + evstate->last = now; + } + } +} + +/* + * The callback invoked by QemuTimer when a delayed + * event is ready to be emitted + */ +static void monitor_qapi_event_handler(void *opaque) +{ + MonitorQAPIEventState *evstate = opaque; + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + trace_monitor_protocol_event_handler(evstate->event, + evstate->data, + evstate->last, + now); + if (evstate->data) { + monitor_qapi_event_emit(evstate->event, evstate->data); + qobject_decref(evstate->data); + evstate->data = NULL; + } + evstate->last = now; +} + +/* + * @event: the event ID to be limited + * @rate: the rate limit in milliseconds + * + * Sets a rate limit on a particular event, so no + * more than 1 event will be emitted within @rate + * milliseconds + */ +static void __attribute__((__unused__)) +monitor_qapi_event_throttle(QAPIEvent event, int64_t rate) +{ + MonitorQAPIEventState *evstate; + assert(event < QAPI_EVENT_MAX); + + evstate = &(monitor_qapi_event_state[event]); + + trace_monitor_protocol_event_throttle(event, rate); + evstate->event = event; + evstate->rate = rate * SCALE_MS; + evstate->last = 0; + evstate->data = NULL; + evstate->timer = timer_new(QEMU_CLOCK_REALTIME, + SCALE_MS, + monitor_qapi_event_handler, + evstate); +} + +static void monitor_qapi_event_init(void) +{ + qmp_event_set_func_emit(monitor_qapi_event_queue); +} + /* * Emits the event to every monitor instance @@ -589,7 +714,7 @@ static void monitor_protocol_event_handler(void *opaque) * more than 1 event will be emitted within @rate * milliseconds */ -static void +static void __attribute__((__unused__)) monitor_protocol_event_throttle(MonitorEvent event, int64_t rate) { @@ -5358,6 +5483,7 @@ void monitor_init(CharDriverState *chr, int flags) if (is_first_init) { monitor_protocol_event_init(); + monitor_qapi_event_init(); sortcmdlist(); is_first_init = 0; } -- cgit v1.2.3