diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-06-24 13:06:13 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-06-24 13:06:13 +0100 |
commit | 089a39486f2c47994c6c0d34ac7abf34baf40d9d (patch) | |
tree | 07bf9220989162df8d29b99568d13ce6d5261822 /monitor.c | |
parent | 27acb9dd2407f41550e453b85aa5ebf1bd618b79 (diff) | |
parent | d622cb5879ca8006d5482158e4e3b272a068c301 (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.c | 227 |
1 files changed, 92 insertions, 135 deletions
@@ -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; } |