aboutsummaryrefslogtreecommitdiff
path: root/monitor.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-24 13:06:13 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-06-24 13:06:13 +0100
commit089a39486f2c47994c6c0d34ac7abf34baf40d9d (patch)
tree07bf9220989162df8d29b99568d13ce6d5261822 /monitor.c
parent27acb9dd2407f41550e453b85aa5ebf1bd618b79 (diff)
parentd622cb5879ca8006d5482158e4e3b272a068c301 (diff)
Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging
* remotes/qmp-unstable/queue/qmp: (43 commits) monitor: protect event emission monitor: protect outbuf and mux_out with mutex qemu-char: make writes thread-safe qemu-char: move pty_chr_update_read_handler around qemu-char: do not call chr_write directly qemu-char: introduce qemu_chr_alloc qapi event: clean up qapi event: convert QUORUM events qapi event: convert GUEST_PANICKED qapi event: convert BALLOON_CHANGE qmp: convert ACPI_DEVICE_OST event qapi event: convert SPICE events qapi event: convert VNC events qapi event: convert NIC_RX_FILTER_CHANGED qapi event: convert other BLOCK_JOB events qapi event: convert BLOCK_IMAGE_CORRUPTED qapi event: convert BLOCK_IO_ERROR and BLOCK_JOB_ERROR qapi event: convert DEVICE_TRAY_MOVED qapi event: convert DEVICE_DELETED qapi event: convert WATCHDOG ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'monitor.c')
-rw-r--r--monitor.c227
1 files changed, 92 insertions, 135 deletions
diff --git a/monitor.c b/monitor.c
index 8c17f899b3..a8ab600c88 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)
@@ -179,23 +181,28 @@ 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 */
+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 */
-} MonitorEventState;
+} 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;
@@ -210,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;
@@ -268,17 +278,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;
@@ -305,18 +320,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')
@@ -326,9 +349,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)
@@ -439,66 +463,14 @@ 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",
- [QEVENT_ACPI_OST] = "ACPI_DEVICE_OST",
-};
-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
+ * Emits the event to every monitor instance, @event is only used for trace
+ * Called with monitor_lock held.
*/
-static void
-monitor_protocol_event_emit(MonitorEvent event,
- QObject *data)
+static void monitor_qapi_event_emit(QAPIEvent event, QObject *data)
{
Monitor *mon;
@@ -510,20 +482,18 @@ monitor_protocol_event_emit(MonitorEvent event,
}
}
-
/*
* 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)
+monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp)
{
- MonitorEventState *evstate;
+ MonitorQAPIEventState *evstate;
+ assert(event < QAPI_EVENT_MAX);
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
- assert(event < QEVENT_MAX);
- evstate = &(monitor_event_state[event]);
+ evstate = &(monitor_qapi_event_state[event]);
trace_monitor_protocol_event_queue(event,
data,
evstate->rate,
@@ -531,8 +501,9 @@ monitor_protocol_event_queue(MonitorEvent event,
now);
/* Rate limit of 0 indicates no throttling */
+ qemu_mutex_lock(&monitor_lock);
if (!evstate->rate) {
- monitor_protocol_event_emit(event, data);
+ monitor_qapi_event_emit(event, QOBJECT(data));
evstate->last = now;
} else {
int64_t delta = now - evstate->last;
@@ -548,39 +519,39 @@ monitor_protocol_event_queue(MonitorEvent event,
int64_t then = evstate->last + evstate->rate;
timer_mod_ns(evstate->timer, then);
}
- evstate->data = data;
+ evstate->data = QOBJECT(data);
qobject_incref(evstate->data);
} else {
- monitor_protocol_event_emit(event, data);
+ monitor_qapi_event_emit(event, QOBJECT(data));
evstate->last = now;
}
}
+ qemu_mutex_unlock(&monitor_lock);
}
-
/*
* The callback invoked by QemuTimer when a delayed
* event is ready to be emitted
*/
-static void monitor_protocol_event_handler(void *opaque)
+static void monitor_qapi_event_handler(void *opaque)
{
- MonitorEventState *evstate = 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);
+ qemu_mutex_lock(&monitor_lock);
if (evstate->data) {
- monitor_protocol_event_emit(evstate->event, 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);
}
-
/*
* @event: the event ID to be limited
* @rate: the rate limit in milliseconds
@@ -590,65 +561,35 @@ static void monitor_protocol_event_handler(void *opaque)
* milliseconds
*/
static void
-monitor_protocol_event_throttle(MonitorEvent event,
- int64_t rate)
+monitor_qapi_event_throttle(QAPIEvent event, int64_t rate)
{
- MonitorEventState *evstate;
- assert(event < QEVENT_MAX);
+ MonitorQAPIEventState *evstate;
+ assert(event < QAPI_EVENT_MAX);
- evstate = &(monitor_event_state[event]);
+ evstate = &(monitor_qapi_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;
+ evstate->timer = timer_new(QEMU_CLOCK_REALTIME,
+ SCALE_MS,
+ monitor_qapi_event_handler,
+ evstate);
}
-
-/* Global, one-time initializer to configure the rate limiting
- * and initialize state */
-static void monitor_protocol_event_init(void)
+static void monitor_qapi_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 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);
/* 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);
-}
-
-/**
- * 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);
- }
+ monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_REPORT_BAD, 1000);
+ monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_FAILURE, 1000);
- trace_monitor_protocol_event(event, event_name, qmp);
- monitor_protocol_event_queue(event, QOBJECT(qmp));
- QDECREF(qmp);
+ qmp_event_set_func_emit(monitor_qapi_event_queue);
}
static int do_qmp_capabilities(Monitor *mon, const QDict *params,
@@ -667,6 +608,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;
@@ -675,6 +617,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,
@@ -702,11 +645,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);
@@ -1045,10 +990,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));
@@ -5266,7 +5211,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);
@@ -5286,7 +5233,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:
@@ -5351,13 +5300,18 @@ 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;
Monitor *mon;
if (is_first_init) {
- monitor_protocol_event_init();
+ monitor_qapi_event_init();
sortcmdlist();
is_first_init = 0;
}
@@ -5388,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;
}