summaryrefslogtreecommitdiff
path: root/monitor.c
diff options
context:
space:
mode:
authorChanho Park <chanho61.park@samsung.com>2014-09-05 20:35:53 +0900
committerChanho Park <chanho61.park@samsung.com>2014-09-05 20:35:53 +0900
commit16b1353a36171ae06d63fd309f4772dbfb1da113 (patch)
treecf6c297ee81aba0d9b47f23d78a889667e7bce48 /monitor.c
parenta15119db2ff5c2fdfdeb913b297bf8aa3399132e (diff)
downloadqemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.gz
qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.bz2
qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.zip
Imported Upstream version 2.1.0upstream/2.1.0
Diffstat (limited to 'monitor.c')
-rw-r--r--monitor.c691
1 files changed, 494 insertions, 197 deletions
diff --git a/monitor.c b/monitor.c
index 342e83bae..5bc70a642 100644
--- a/monitor.c
+++ b/monitor.c
@@ -66,9 +66,13 @@
#include "trace/simple.h"
#endif
#include "exec/memory.h"
+#include "exec/cpu_ldst.h"
#include "qmp-commands.h"
#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)
@@ -137,6 +141,7 @@ typedef struct mon_cmd_t {
* used, and mhandler of 1st level plays the role of help function.
*/
struct mon_cmd_t *sub_table;
+ void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
} mon_cmd_t;
/* file descriptors passed via SCM_RIGHTS */
@@ -176,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;
@@ -207,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;
@@ -265,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;
@@ -302,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|G_IO_HUP,
+ 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')
@@ -323,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)
@@ -352,33 +379,6 @@ void monitor_printf(Monitor *mon, const char *fmt, ...)
va_end(ap);
}
-void monitor_print_filename(Monitor *mon, const char *filename)
-{
- int i;
-
- for (i = 0; filename[i]; i++) {
- switch (filename[i]) {
- case ' ':
- case '"':
- case '\\':
- monitor_printf(mon, "\\%c", filename[i]);
- break;
- case '\t':
- monitor_printf(mon, "\\t");
- break;
- case '\r':
- monitor_printf(mon, "\\r");
- break;
- case '\n':
- monitor_printf(mon, "\\n");
- break;
- default:
- monitor_printf(mon, "%c", filename[i]);
- break;
- }
- }
-}
-
static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream,
const char *fmt, ...)
{
@@ -463,65 +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",
-};
-QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
-
-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;
@@ -533,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,
@@ -554,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;
@@ -571,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
@@ -613,65 +561,36 @@ 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;
+ assert(rate * SCALE_MS <= INT64_MAX);
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)
-{
- /* 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 */
- 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)
+static void monitor_qapi_event_init(void)
{
- QDict *qmp;
- const char *event_name;
-
- assert(event < QEVENT_MAX);
+ /* 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);
+ 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);
- 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);
+ qmp_event_set_func_emit(monitor_qapi_event_queue);
}
static int do_qmp_capabilities(Monitor *mon, const QDict *params,
@@ -690,6 +609,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;
@@ -698,6 +618,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,
@@ -725,11 +646,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);
@@ -1068,10 +991,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));
@@ -1309,6 +1232,10 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
}
}
#endif
+#ifdef TARGET_PPC
+ flags = msr_le << 16;
+ flags |= env->bfd_mach;
+#endif
monitor_disas(mon, env, addr, count, is_physical, flags);
return;
}
@@ -2031,7 +1958,7 @@ static void do_info_numa(Monitor *mon, const QDict *qdict)
}
monitor_printf(mon, "\n");
monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
- node_mem[i] >> 20);
+ numa_info[i].node_mem >> 20);
}
}
@@ -2254,6 +2181,7 @@ void qmp_getfd(const char *fdname, Error **errp)
}
if (qemu_isdigit(fdname[0])) {
+ close(fd);
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
"a name not starting with a digit");
return;
@@ -2636,16 +2564,33 @@ int monitor_handle_fd_param(Monitor *mon, const char *fdname)
int fd;
Error *local_err = NULL;
- if (!qemu_isdigit(fdname[0]) && mon) {
+ fd = monitor_handle_fd_param2(mon, fdname, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ }
+ return fd;
+}
+int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp)
+{
+ int fd;
+ Error *local_err = NULL;
+
+ if (!qemu_isdigit(fdname[0]) && mon) {
fd = monitor_get_fd(mon, fdname, &local_err);
+ } else {
+ fd = qemu_parse_fd(fdname);
if (fd == -1) {
- qerror_report_err(local_err);
- error_free(local_err);
- return -1;
+ error_setg(&local_err, "Invalid file descriptor number '%s'",
+ fdname);
}
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ assert(fd == -1);
} else {
- fd = qemu_parse_fd(fdname);
+ assert(fd != -1);
}
return fd;
@@ -2966,6 +2911,13 @@ static mon_cmd_t info_cmds[] = {
.mhandler.cmd = hmp_info_tpm,
},
{
+ .name = "memdev",
+ .args_type = "",
+ .params = "",
+ .help = "show memory backends",
+ .mhandler.cmd = hmp_info_memdev,
+ },
+ {
.name = NULL,
},
};
@@ -4277,11 +4229,64 @@ static const char *next_arg_type(const char *typestr)
return (p != NULL ? ++p : typestr);
}
-static void device_add_completion(ReadLineState *rs, const char *str)
+static void add_completion_option(ReadLineState *rs, const char *str,
+ const char *option)
+{
+ if (!str || !option) {
+ return;
+ }
+ if (!strncmp(option, str, strlen(str))) {
+ readline_add_completion(rs, option);
+ }
+}
+
+void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+ ChardevBackendInfoList *list, *start;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ start = list = qmp_query_chardev_backends(NULL);
+ while (list) {
+ const char *chr_name = list->value->name;
+
+ if (!strncmp(chr_name, str, len)) {
+ readline_add_completion(rs, chr_name);
+ }
+ list = list->next;
+ }
+ qapi_free_ChardevBackendInfoList(start);
+}
+
+void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+ int i;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
+ add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
+ }
+}
+
+void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
GSList *list, *elt;
size_t len;
+ if (nb_args != 2) {
+ return;
+ }
+
len = strlen(str);
readline_set_completion_index(rs, len);
list = elt = object_class_get_list(TYPE_DEVICE, false);
@@ -4290,7 +4295,9 @@ static void device_add_completion(ReadLineState *rs, const char *str)
DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
TYPE_DEVICE);
name = object_class_get_name(OBJECT_CLASS(dc));
- if (!strncmp(name, str, len)) {
+
+ if (!dc->cannot_instantiate_with_device_add_yet
+ && !strncmp(name, str, len)) {
readline_add_completion(rs, name);
}
elt = elt->next;
@@ -4298,11 +4305,15 @@ static void device_add_completion(ReadLineState *rs, const char *str)
g_slist_free(list);
}
-static void object_add_completion(ReadLineState *rs, const char *str)
+void object_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
GSList *list, *elt;
size_t len;
+ if (nb_args != 2) {
+ return;
+ }
+
len = strlen(str);
readline_set_completion_index(rs, len);
list = elt = object_class_get_list(TYPE_USER_CREATABLE, false);
@@ -4318,8 +4329,8 @@ static void object_add_completion(ReadLineState *rs, const char *str)
g_slist_free(list);
}
-static void device_del_completion(ReadLineState *rs, BusState *bus,
- const char *str, size_t len)
+static void device_del_bus_completion(ReadLineState *rs, BusState *bus,
+ const char *str, size_t len)
{
BusChild *kid;
@@ -4332,16 +4343,94 @@ static void device_del_completion(ReadLineState *rs, BusState *bus,
}
QLIST_FOREACH(dev_child, &dev->child_bus, sibling) {
- device_del_completion(rs, dev_child, str, len);
+ device_del_bus_completion(rs, dev_child, str, len);
}
}
}
-static void object_del_completion(ReadLineState *rs, const char *str)
+void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+ ChardevInfoList *list, *start;
+
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ start = list = qmp_query_chardev(NULL);
+ while (list) {
+ ChardevInfo *chr = list->value;
+
+ if (!strncmp(chr->label, str, len)) {
+ readline_add_completion(rs, chr->label);
+ }
+ list = list->next;
+ }
+ qapi_free_ChardevInfoList(start);
+}
+
+static void ringbuf_completion(ReadLineState *rs, const char *str)
+{
+ size_t len;
+ ChardevInfoList *list, *start;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+
+ start = list = qmp_query_chardev(NULL);
+ while (list) {
+ ChardevInfo *chr_info = list->value;
+
+ if (!strncmp(chr_info->label, str, len)) {
+ CharDriverState *chr = qemu_chr_find(chr_info->label);
+ if (chr && chr_is_ringbuf(chr)) {
+ readline_add_completion(rs, chr_info->label);
+ }
+ }
+ list = list->next;
+ }
+ qapi_free_ChardevInfoList(start);
+}
+
+void ringbuf_read_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args != 2) {
+ return;
+ }
+ ringbuf_completion(rs, str);
+}
+
+void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args != 2) {
+ return;
+ }
+ ringbuf_completion(rs, str);
+}
+
+void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+
+ if (nb_args != 2) {
+ return;
+ }
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ device_del_bus_completion(rs, sysbus_get_default(), str, len);
+}
+
+void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
{
ObjectPropertyInfoList *list, *start;
size_t len;
+ if (nb_args != 2) {
+ return;
+ }
len = strlen(str);
readline_set_completion_index(rs, len);
@@ -4358,6 +4447,213 @@ static void object_del_completion(ReadLineState *rs, const char *str)
qapi_free_ObjectPropertyInfoList(start);
}
+void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int i;
+ char *sep;
+ size_t len;
+
+ if (nb_args != 2) {
+ return;
+ }
+ sep = strrchr(str, '-');
+ if (sep) {
+ str = sep + 1;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ if (!strncmp(str, QKeyCode_lookup[i], len)) {
+ readline_add_completion(rs, QKeyCode_lookup[i]);
+ }
+ }
+}
+
+void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ NetClientState *ncs[255];
+ int count, i;
+ count = qemu_find_net_clients_except(NULL, ncs,
+ NET_CLIENT_OPTIONS_KIND_NONE, 255);
+ for (i = 0; i < count; i++) {
+ const char *name = ncs[i]->name;
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ } else if (nb_args == 3) {
+ add_completion_option(rs, str, "on");
+ add_completion_option(rs, str, "off");
+ }
+}
+
+void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int len, count, i;
+ NetClientState *ncs[255];
+
+ if (nb_args != 2) {
+ return;
+ }
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
+ 255);
+ for (i = 0; i < count; i++) {
+ QemuOpts *opts;
+ const char *name = ncs[i]->name;
+ if (strncmp(str, name, len)) {
+ continue;
+ }
+ opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
+ if (opts) {
+ readline_add_completion(rs, name);
+ }
+ }
+}
+
+void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args != 2) {
+ return;
+ }
+ readline_set_completion_index(rs, strlen(str));
+ add_completion_option(rs, str, "reset");
+ add_completion_option(rs, str, "shutdown");
+ add_completion_option(rs, str, "poweroff");
+ add_completion_option(rs, str, "pause");
+ add_completion_option(rs, str, "debug");
+ add_completion_option(rs, str, "none");
+}
+
+void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
+ const char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ int i;
+ for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ const char *name = MigrationCapability_lookup[i];
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ } else if (nb_args == 3) {
+ add_completion_option(rs, str, "on");
+ add_completion_option(rs, str, "off");
+ }
+}
+
+void host_net_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ int i;
+ size_t len;
+ if (nb_args != 2) {
+ return;
+ }
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ for (i = 0; host_net_devices[i]; i++) {
+ if (!strncmp(host_net_devices[i], str, len)) {
+ readline_add_completion(rs, host_net_devices[i]);
+ }
+ }
+}
+
+void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ NetClientState *ncs[255];
+ int count, i, len;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ if (nb_args == 2) {
+ count = qemu_find_net_clients_except(NULL, ncs,
+ NET_CLIENT_OPTIONS_KIND_NONE, 255);
+ for (i = 0; i < count; i++) {
+ int id;
+ char name[16];
+
+ if (net_hub_id_for_client(ncs[i], &id)) {
+ continue;
+ }
+ snprintf(name, sizeof(name), "%d", id);
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ return;
+ } else if (nb_args == 3) {
+ count = qemu_find_net_clients_except(NULL, ncs,
+ NET_CLIENT_OPTIONS_KIND_NIC, 255);
+ for (i = 0; i < count; i++) {
+ const char *name;
+
+ name = ncs[i]->name;
+ if (!strncmp(str, name, len)) {
+ readline_add_completion(rs, name);
+ }
+ }
+ return;
+ }
+}
+
+static void vm_completion(ReadLineState *rs, const char *str)
+{
+ size_t len;
+ BlockDriverState *bs = NULL;
+
+ len = strlen(str);
+ readline_set_completion_index(rs, len);
+ while ((bs = bdrv_next(bs))) {
+ SnapshotInfoList *snapshots, *snapshot;
+
+ if (!bdrv_can_snapshot(bs)) {
+ continue;
+ }
+ if (bdrv_query_snapshot_info_list(bs, &snapshots, NULL)) {
+ continue;
+ }
+ snapshot = snapshots;
+ while (snapshot) {
+ char *completion = snapshot->value->name;
+ if (!strncmp(str, completion, len)) {
+ readline_add_completion(rs, completion);
+ }
+ completion = snapshot->value->id;
+ if (!strncmp(str, completion, len)) {
+ readline_add_completion(rs, completion);
+ }
+ snapshot = snapshot->next;
+ }
+ qapi_free_SnapshotInfoList(snapshots);
+ }
+
+}
+
+void delvm_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args == 2) {
+ vm_completion(rs, str);
+ }
+}
+
+void loadvm_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+ if (nb_args == 2) {
+ vm_completion(rs, str);
+ }
+}
+
static void monitor_find_completion_by_table(Monitor *mon,
const mon_cmd_t *cmd_table,
char **args,
@@ -4395,6 +4691,9 @@ static void monitor_find_completion_by_table(Monitor *mon,
return monitor_find_completion_by_table(mon, cmd->sub_table,
&args[1], nb_args - 1);
}
+ if (cmd->command_completion) {
+ return cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]);
+ }
ptype = next_arg_type(cmd->args_type);
for(i = 0; i < nb_args - 2; i++) {
@@ -4421,32 +4720,11 @@ static void monitor_find_completion_by_table(Monitor *mon,
readline_set_completion_index(mon->rs, strlen(str));
bdrv_iterate(block_completion_it, &mbs);
break;
- case 'O':
- if (!strcmp(cmd->name, "device_add") && nb_args == 2) {
- device_add_completion(mon->rs, str);
- } else if (!strcmp(cmd->name, "object_add") && nb_args == 2) {
- object_add_completion(mon->rs, str);
- }
- break;
case 's':
case 'S':
- if (!strcmp(cmd->name, "sendkey")) {
- char *sep = strrchr(str, '-');
- if (sep)
- str = sep + 1;
- readline_set_completion_index(mon->rs, strlen(str));
- for (i = 0; i < Q_KEY_CODE_MAX; i++) {
- cmd_completion(mon, str, QKeyCode_lookup[i]);
- }
- } else if (!strcmp(cmd->name, "help|?")) {
+ if (!strcmp(cmd->name, "help|?")) {
monitor_find_completion_by_table(mon, cmd_table,
&args[1], nb_args - 1);
- } else if (!strcmp(cmd->name, "device_del") && nb_args == 2) {
- size_t len = strlen(str);
- readline_set_completion_index(mon->rs, len);
- device_del_completion(mon->rs, sysbus_get_default(), str, len);
- } else if (!strcmp(cmd->name, "object_del") && nb_args == 2) {
- object_del_completion(mon->rs, str);
}
break;
default:
@@ -4934,7 +5212,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);
@@ -4954,7 +5234,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:
@@ -5019,13 +5301,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;
}
@@ -5056,7 +5343,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;
}
@@ -5151,3 +5441,10 @@ QemuOptsList qemu_mon_opts = {
{ /* end of list */ }
},
};
+
+#ifndef TARGET_I386
+void qmp_rtc_reset_reinjection(Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
+}
+#endif