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(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index c7f8797..2c0b747 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.1 From e010ad8f1e14def33117576916a954d7a3778458 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 18 Jun 2014 08:43:41 +0200 Subject: qapi event: convert RTC_CHANGE This patch also eliminates build time warning caused by no caller of monitor_qapi_event_throttle(). Signed-off-by: Wenchao Xia Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- monitor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index 2c0b747..41ef40e 100644 --- a/monitor.c +++ b/monitor.c @@ -614,6 +614,9 @@ monitor_qapi_event_throttle(QAPIEvent event, int64_t rate) static void monitor_qapi_event_init(void) { + /* Limit guest-triggerable events to 1 per second */ + monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000); + qmp_event_set_func_emit(monitor_qapi_event_queue); } @@ -740,7 +743,6 @@ monitor_protocol_event_throttle(MonitorEvent event, static void monitor_protocol_event_init(void) { /* Limit RTC & BALLOON events to 1 per second */ - monitor_protocol_event_throttle(QEVENT_RTC_CHANGE, 1000); monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000); monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000); /* limit the rate of quorum events to avoid hammering the management */ -- cgit v1.1 From 99eaf09c73b213e32e297b1d08d035abb5b268e9 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 18 Jun 2014 08:43:42 +0200 Subject: qapi event: convert WATCHDOG Signed-off-by: Wenchao Xia Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index 41ef40e..0b4a4b4 100644 --- a/monitor.c +++ b/monitor.c @@ -616,6 +616,7 @@ static void monitor_qapi_event_init(void) { /* Limit guest-triggerable events to 1 per second */ monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000); + monitor_qapi_event_throttle(QAPI_EVENT_WATCHDOG, 1000); qmp_event_set_func_emit(monitor_qapi_event_queue); } @@ -744,7 +745,6 @@ static void monitor_protocol_event_init(void) { /* Limit RTC & BALLOON events to 1 per second */ monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000); - monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000); /* limit the rate of quorum events to avoid hammering the management */ monitor_protocol_event_throttle(QEVENT_QUORUM_REPORT_BAD, 1000); monitor_protocol_event_throttle(QEVENT_QUORUM_FAILURE, 1000); -- cgit v1.1 From 5f41fbba903fc4e55b94c54cd97ea2d904371351 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 23 Jun 2014 15:26:57 +0200 Subject: qmp: convert ACPI_DEVICE_OST event ... using new QAPI event infrastructure Signed-off-by: Igor Mammedov Signed-off-by: Luiz Capitulino --- monitor.c | 1 - 1 file changed, 1 deletion(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index 0b4a4b4..2f64195 100644 --- a/monitor.c +++ b/monitor.c @@ -497,7 +497,6 @@ static const char *monitor_event_names[] = { [QEVENT_BLOCK_IMAGE_CORRUPTED] = "BLOCK_IMAGE_CORRUPTED", [QEVENT_QUORUM_FAILURE] = "QUORUM_FAILURE", [QEVENT_QUORUM_REPORT_BAD] = "QUORUM_REPORT_BAD", - [QEVENT_ACPI_OST] = "ACPI_DEVICE_OST", }; QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) -- cgit v1.1 From aef9d3115fbaf2b1b904e333b46fe2b070fcbe96 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 18 Jun 2014 08:43:51 +0200 Subject: qapi event: convert BALLOON_CHANGE Signed-off-by: Wenchao Xia Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- monitor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index 2f64195..eacef61 100644 --- a/monitor.c +++ b/monitor.c @@ -616,6 +616,7 @@ static void monitor_qapi_event_init(void) /* Limit guest-triggerable events to 1 per second */ monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000); monitor_qapi_event_throttle(QAPI_EVENT_WATCHDOG, 1000); + monitor_qapi_event_throttle(QAPI_EVENT_BALLOON_CHANGE, 1000); qmp_event_set_func_emit(monitor_qapi_event_queue); } @@ -742,8 +743,6 @@ monitor_protocol_event_throttle(MonitorEvent event, * and initialize state */ static void monitor_protocol_event_init(void) { - /* Limit RTC & BALLOON events to 1 per second */ - monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000); /* limit the rate of quorum events to avoid hammering the management */ monitor_protocol_event_throttle(QEVENT_QUORUM_REPORT_BAD, 1000); monitor_protocol_event_throttle(QEVENT_QUORUM_FAILURE, 1000); -- cgit v1.1 From fe069d9d5946df0414b149acf49bce127e546f6b Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 18 Jun 2014 08:43:53 +0200 Subject: qapi event: convert QUORUM events Signed-off-by: Wenchao Xia Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- monitor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index eacef61..aebe868 100644 --- a/monitor.c +++ b/monitor.c @@ -617,6 +617,9 @@ static void monitor_qapi_event_init(void) monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000); monitor_qapi_event_throttle(QAPI_EVENT_WATCHDOG, 1000); monitor_qapi_event_throttle(QAPI_EVENT_BALLOON_CHANGE, 1000); + /* limit the rate of quorum events to avoid hammering the management */ + monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_REPORT_BAD, 1000); + monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_FAILURE, 1000); qmp_event_set_func_emit(monitor_qapi_event_queue); } @@ -743,9 +746,6 @@ monitor_protocol_event_throttle(MonitorEvent event, * and initialize state */ static void monitor_protocol_event_init(void) { - /* limit the rate of quorum events to avoid hammering the management */ - monitor_protocol_event_throttle(QEVENT_QUORUM_REPORT_BAD, 1000); - monitor_protocol_event_throttle(QEVENT_QUORUM_FAILURE, 1000); } /** -- cgit v1.1 From 751751732c48d8fc2facf76d72fc56ba68494f45 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Wed, 18 Jun 2014 08:43:54 +0200 Subject: qapi event: clean up Signed-off-by: Wenchao Xia Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Luiz Capitulino --- monitor.c | 220 ++------------------------------------------------------------ 1 file changed, 4 insertions(+), 216 deletions(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index aebe868..5c9eec1 100644 --- a/monitor.c +++ b/monitor.c @@ -181,14 +181,6 @@ typedef struct MonitorControl { * throttling is calculated globally, rather than per-Monitor * instance. */ -typedef struct MonitorEventState { - MonitorEvent event; /* Event being tracked */ - int64_t rate; /* Period over which to throttle. 0 to disable */ - int64_t last; /* Time at which event was last emitted */ - QEMUTimer *timer; /* Timer for handling delayed events */ - 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 */ @@ -449,58 +441,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data) QDECREF(qmp); } -static void timestamp_put(QDict *qdict) -{ - int err; - QObject *obj; - qemu_timeval tv; - - err = qemu_gettimeofday(&tv); - if (err < 0) - return; - - obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", " - "'microseconds': %" PRId64 " }", - (int64_t) tv.tv_sec, (int64_t) tv.tv_usec); - qdict_put_obj(qdict, "timestamp", obj); -} - - -static const char *monitor_event_names[] = { - [QEVENT_SHUTDOWN] = "SHUTDOWN", - [QEVENT_RESET] = "RESET", - [QEVENT_POWERDOWN] = "POWERDOWN", - [QEVENT_STOP] = "STOP", - [QEVENT_RESUME] = "RESUME", - [QEVENT_VNC_CONNECTED] = "VNC_CONNECTED", - [QEVENT_VNC_INITIALIZED] = "VNC_INITIALIZED", - [QEVENT_VNC_DISCONNECTED] = "VNC_DISCONNECTED", - [QEVENT_BLOCK_IO_ERROR] = "BLOCK_IO_ERROR", - [QEVENT_RTC_CHANGE] = "RTC_CHANGE", - [QEVENT_WATCHDOG] = "WATCHDOG", - [QEVENT_SPICE_CONNECTED] = "SPICE_CONNECTED", - [QEVENT_SPICE_INITIALIZED] = "SPICE_INITIALIZED", - [QEVENT_SPICE_DISCONNECTED] = "SPICE_DISCONNECTED", - [QEVENT_BLOCK_JOB_COMPLETED] = "BLOCK_JOB_COMPLETED", - [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED", - [QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR", - [QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY", - [QEVENT_DEVICE_DELETED] = "DEVICE_DELETED", - [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED", - [QEVENT_NIC_RX_FILTER_CHANGED] = "NIC_RX_FILTER_CHANGED", - [QEVENT_SUSPEND] = "SUSPEND", - [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", - [QEVENT_WAKEUP] = "WAKEUP", - [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", - [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED", - [QEVENT_GUEST_PANICKED] = "GUEST_PANICKED", - [QEVENT_BLOCK_IMAGE_CORRUPTED] = "BLOCK_IMAGE_CORRUPTED", - [QEVENT_QUORUM_FAILURE] = "QUORUM_FAILURE", - [QEVENT_QUORUM_REPORT_BAD] = "QUORUM_REPORT_BAD", -}; -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]; /* @@ -592,7 +533,7 @@ static void monitor_qapi_event_handler(void *opaque) * more than 1 event will be emitted within @rate * milliseconds */ -static void __attribute__((__unused__)) +static void monitor_qapi_event_throttle(QAPIEvent event, int64_t rate) { MonitorQAPIEventState *evstate; @@ -624,158 +565,6 @@ static void monitor_qapi_event_init(void) qmp_event_set_func_emit(monitor_qapi_event_queue); } - -/* - * Emits the event to every monitor instance - */ -static void -monitor_protocol_event_emit(MonitorEvent 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_protocol_event_queue(MonitorEvent event, - QObject *data) -{ - MonitorEventState *evstate; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - assert(event < QEVENT_MAX); - - evstate = &(monitor_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_protocol_event_emit(event, 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 = data; - qobject_incref(evstate->data); - } else { - monitor_protocol_event_emit(event, data); - evstate->last = now; - } - } -} - - -/* - * The callback invoked by QemuTimer when a delayed - * event is ready to be emitted - */ -static void monitor_protocol_event_handler(void *opaque) -{ - MonitorEventState *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_protocol_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_protocol_event_throttle(MonitorEvent event, - int64_t rate) -{ - MonitorEventState *evstate; - assert(event < QEVENT_MAX); - - evstate = &(monitor_event_state[event]); - - trace_monitor_protocol_event_throttle(event, rate); - evstate->event = event; - evstate->rate = rate * SCALE_MS; - evstate->timer = timer_new(QEMU_CLOCK_REALTIME, - SCALE_MS, - monitor_protocol_event_handler, - evstate); - evstate->last = 0; - evstate->data = NULL; -} - - -/* Global, one-time initializer to configure the rate limiting - * and initialize state */ -static void monitor_protocol_event_init(void) -{ -} - -/** - * monitor_protocol_event(): Generate a Monitor event - * - * Event-specific data can be emitted through the (optional) 'data' parameter. - */ -void monitor_protocol_event(MonitorEvent event, QObject *data) -{ - QDict *qmp; - const char *event_name; - - assert(event < QEVENT_MAX); - - event_name = monitor_event_names[event]; - assert(event_name != NULL); - - qmp = qdict_new(); - timestamp_put(qmp); - qdict_put(qmp, "event", qstring_from_str(event_name)); - if (data) { - qobject_incref(data); - qdict_put_obj(qmp, "data", data); - } - - trace_monitor_protocol_event(event, event_name, qmp); - monitor_protocol_event_queue(event, QOBJECT(qmp)); - QDECREF(qmp); -} - static int do_qmp_capabilities(Monitor *mon, const QDict *params, QObject **ret_data) { @@ -1170,10 +959,10 @@ CommandInfoList *qmp_query_commands(Error **errp) EventInfoList *qmp_query_events(Error **errp) { EventInfoList *info, *ev_list = NULL; - MonitorEvent e; + QAPIEvent e; - for (e = 0 ; e < QEVENT_MAX ; e++) { - const char *event_name = monitor_event_names[e]; + for (e = 0 ; e < QAPI_EVENT_MAX ; e++) { + const char *event_name = QAPIEvent_lookup[e]; assert(event_name != NULL); info = g_malloc0(sizeof(*info)); info->value = g_malloc0(sizeof(*info->value)); @@ -5482,7 +5271,6 @@ void monitor_init(CharDriverState *chr, int flags) Monitor *mon; if (is_first_init) { - monitor_protocol_event_init(); monitor_qapi_event_init(); sortcmdlist(); is_first_init = 0; -- cgit v1.1 From 6cff3e8594cd974a507d531da09455d1c7aeb30d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 18 Jun 2014 08:43:59 +0200 Subject: monitor: protect outbuf and mux_out with mutex This lets the block layer emit QMP events from outside the I/O thread. Reviewed-by: Luiz Capitulino Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- monitor.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index 5c9eec1..4f2e4d9 100644 --- a/monitor.c +++ b/monitor.c @@ -191,13 +191,18 @@ typedef struct MonitorQAPIEventState { struct Monitor { CharDriverState *chr; - int mux_out; int reset_seen; int flags; int suspend_cnt; bool skip_flush; + + QemuMutex out_lock; QString *outbuf; - guint watch; + guint out_watch; + + /* Read under either BQL or out_lock, written with BQL+out_lock. */ + int mux_out; + ReadLineState *rs; MonitorControl *mc; CPUState *mon_cpu; @@ -270,17 +275,22 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, } } +static void monitor_flush_locked(Monitor *mon); + static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, void *opaque) { Monitor *mon = opaque; - mon->watch = 0; - monitor_flush(mon); + qemu_mutex_lock(&mon->out_lock); + mon->out_watch = 0; + monitor_flush_locked(mon); + qemu_mutex_unlock(&mon->out_lock); return FALSE; } -void monitor_flush(Monitor *mon) +/* Called with mon->out_lock held. */ +static void monitor_flush_locked(Monitor *mon) { int rc; size_t len; @@ -307,18 +317,26 @@ void monitor_flush(Monitor *mon) QDECREF(mon->outbuf); mon->outbuf = tmp; } - if (mon->watch == 0) { - mon->watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, - monitor_unblocked, mon); + if (mon->out_watch == 0) { + mon->out_watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, + monitor_unblocked, mon); } } } +void monitor_flush(Monitor *mon) +{ + qemu_mutex_lock(&mon->out_lock); + monitor_flush_locked(mon); + qemu_mutex_unlock(&mon->out_lock); +} + /* flush at every end of line */ static void monitor_puts(Monitor *mon, const char *str) { char c; + qemu_mutex_lock(&mon->out_lock); for(;;) { c = *str++; if (c == '\0') @@ -328,9 +346,10 @@ static void monitor_puts(Monitor *mon, const char *str) } qstring_append_chr(mon->outbuf, c); if (c == '\n') { - monitor_flush(mon); + monitor_flush_locked(mon); } } + qemu_mutex_unlock(&mon->out_lock); } void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) @@ -581,6 +600,7 @@ static void handle_user_command(Monitor *mon, const char *cmdline); static void monitor_data_init(Monitor *mon) { memset(mon, 0, sizeof(Monitor)); + qemu_mutex_init(&mon->out_lock); mon->outbuf = qstring_new(); /* Use *mon_cmds by default. */ mon->cmd_table = mon_cmds; @@ -589,6 +609,7 @@ static void monitor_data_init(Monitor *mon) static void monitor_data_destroy(Monitor *mon) { QDECREF(mon->outbuf); + qemu_mutex_destroy(&mon->out_lock); } char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, @@ -616,11 +637,13 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, handle_user_command(&hmp, command_line); cur_mon = old_mon; + qemu_mutex_lock(&hmp.out_lock); if (qstring_get_length(hmp.outbuf) > 0) { output = g_strdup(qstring_get_str(hmp.outbuf)); } else { output = g_strdup(""); } + qemu_mutex_unlock(&hmp.out_lock); out: monitor_data_destroy(&hmp); @@ -5180,7 +5203,9 @@ static void monitor_event(void *opaque, int event) switch (event) { case CHR_EVENT_MUX_IN: + qemu_mutex_lock(&mon->out_lock); mon->mux_out = 0; + qemu_mutex_unlock(&mon->out_lock); if (mon->reset_seen) { readline_restart(mon->rs); monitor_resume(mon); @@ -5200,7 +5225,9 @@ static void monitor_event(void *opaque, int event) } else { mon->suspend_cnt++; } + qemu_mutex_lock(&mon->out_lock); mon->mux_out = 1; + qemu_mutex_unlock(&mon->out_lock); break; case CHR_EVENT_OPENED: -- cgit v1.1 From d622cb5879ca8006d5482158e4e3b272a068c301 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 18 Jun 2014 08:44:00 +0200 Subject: monitor: protect event emission Event emission must be protected by a mutex because of access to the shared rate-limiting state, and to guard against concurrent monitor "hot-plug" by means of human-monitor-command. Reviewed-by: Luiz Capitulino Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- monitor.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'monitor.c') diff --git a/monitor.c b/monitor.c index 4f2e4d9..224b32e 100644 --- a/monitor.c +++ b/monitor.c @@ -217,6 +217,9 @@ struct Monitor { /* QMP checker flags */ #define QMP_ACCEPT_UNKNOWNS 1 +/* Protects mon_list, monitor_event_state. */ +static QemuMutex monitor_lock; + static QLIST_HEAD(mon_list, Monitor) mon_list; static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets; static int mon_refcount; @@ -465,6 +468,7 @@ static MonitorQAPIEventState monitor_qapi_event_state[QAPI_EVENT_MAX]; /* * Emits the event to every monitor instance, @event is only used for trace + * Called with monitor_lock held. */ static void monitor_qapi_event_emit(QAPIEvent event, QObject *data) { @@ -497,6 +501,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp) now); /* Rate limit of 0 indicates no throttling */ + qemu_mutex_lock(&monitor_lock); if (!evstate->rate) { monitor_qapi_event_emit(event, QOBJECT(data)); evstate->last = now; @@ -521,6 +526,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp) evstate->last = now; } } + qemu_mutex_unlock(&monitor_lock); } /* @@ -536,12 +542,14 @@ static void monitor_qapi_event_handler(void *opaque) evstate->data, evstate->last, now); + qemu_mutex_lock(&monitor_lock); if (evstate->data) { monitor_qapi_event_emit(evstate->event, evstate->data); qobject_decref(evstate->data); evstate->data = NULL; } evstate->last = now; + qemu_mutex_unlock(&monitor_lock); } /* @@ -5292,6 +5300,11 @@ static void monitor_readline_flush(void *opaque) monitor_flush(opaque); } +static void __attribute__((constructor)) monitor_lock_init(void) +{ + qemu_mutex_init(&monitor_lock); +} + void monitor_init(CharDriverState *chr, int flags) { static int is_first_init = 1; @@ -5329,7 +5342,10 @@ void monitor_init(CharDriverState *chr, int flags) monitor_event, mon); } + qemu_mutex_lock(&monitor_lock); QLIST_INSERT_HEAD(&mon_list, mon, entry); + qemu_mutex_unlock(&monitor_lock); + if (!default_mon || (flags & MONITOR_IS_DEFAULT)) default_mon = mon; } -- cgit v1.1