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;
/* 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;
}
}
+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;
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')
}
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)
/*
* 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)
{
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;
evstate->last = now;
}
}
+ qemu_mutex_unlock(&monitor_lock);
}
/*
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);
}
/*
trace_monitor_protocol_event_throttle(event, rate);
evstate->event = event;
+ assert(rate * SCALE_MS <= INT64_MAX);
evstate->rate = rate * SCALE_MS;
evstate->last = 0;
evstate->data = NULL;
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);
+ monitor_qapi_event_throttle(QAPI_EVENT_VSERPORT_CHANGE, 1000);
qmp_event_set_func_emit(monitor_qapi_event_queue);
}
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;
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,
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);
.name = "memdev",
.args_type = "",
.params = "",
- .help = "show the memory device",
+ .help = "show memory backends",
.mhandler.cmd = hmp_info_memdev,
},
{
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);
} 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:
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_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;
}
{ /* end of list */ }
},
};
+
+#ifndef TARGET_I386
+void qmp_rtc_reset_reinjection(Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
+}
+#endif