X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=monitor.c;h=e3799f925edf927e2ab7b7c7034fd62bae2689cc;hb=6a1fa9f5a62937a8552dbc380c5418c696bf7762;hp=5c9eec109fea244283a11c07a82644f9cc76cc0c;hpb=751751732c48d8fc2facf76d72fc56ba68494f45;p=mirror_qemu.git diff --git a/monitor.c b/monitor.c index 5c9eec109f..e3799f925e 100644 --- a/monitor.c +++ b/monitor.c @@ -191,17 +191,22 @@ 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; - BlockDriverCompletionFunc *password_completion_cb; + BlockCompletionFunc *password_completion_cb; void *password_opaque; mon_cmd_t *cmd_table; QError *error; @@ -212,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; @@ -270,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; @@ -307,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') @@ -328,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) @@ -446,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) { @@ -478,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; @@ -502,6 +526,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp) evstate->last = now; } } + qemu_mutex_unlock(&monitor_lock); } /* @@ -517,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); } /* @@ -543,6 +570,7 @@ monitor_qapi_event_throttle(QAPIEvent event, int64_t rate) 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; @@ -558,9 +586,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); + monitor_qapi_event_throttle(QAPI_EVENT_VSERPORT_CHANGE, 1000); qmp_event_set_func_emit(monitor_qapi_event_queue); } @@ -581,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; @@ -589,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, @@ -616,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); @@ -854,19 +886,12 @@ static void do_trace_event_set_state(Monitor *mon, const QDict *qdict) { const char *tp_name = qdict_get_str(qdict, "name"); bool new_state = qdict_get_bool(qdict, "option"); + Error *local_err = NULL; - bool found = false; - TraceEvent *ev = NULL; - while ((ev = trace_event_pattern(tp_name, ev)) != NULL) { - found = true; - if (!trace_event_get_state_static(ev)) { - monitor_printf(mon, "event \"%s\" is not traceable\n", tp_name); - } else { - trace_event_set_state_dynamic(ev, new_state); - } - } - if (!trace_event_is_pattern(tp_name) && !found) { - monitor_printf(mon, "unknown event name \"%s\"\n", tp_name); + qmp_trace_event_set_state(tp_name, new_state, true, true, &local_err); + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); } } @@ -1015,6 +1040,7 @@ static void do_info_registers(Monitor *mon, const QDict *qdict) static void do_info_jit(Monitor *mon, const QDict *qdict) { dump_exec_info((FILE *)mon, monitor_fprintf); + dump_drift_info((FILE *)mon, monitor_fprintf); } static void do_info_history(Monitor *mon, const QDict *qdict) @@ -1046,7 +1072,15 @@ static void do_info_cpu_stats(Monitor *mon, const QDict *qdict) static void do_trace_print_events(Monitor *mon, const QDict *qdict) { - trace_print_events((FILE *)mon, &monitor_fprintf); + TraceEventInfoList *events = qmp_trace_event_get_state("*", NULL); + TraceEventInfoList *elem; + + for (elem = events; elem != NULL; elem = elem->next) { + monitor_printf(mon, "%s : state %u\n", + elem->value->name, + elem->value->state == TRACE_EVENT_STATE_ENABLED ? 1 : 0); + } + qapi_free_TraceEventInfoList(events); } static int client_migrate_info(Monitor *mon, const QDict *qdict, @@ -2509,8 +2543,10 @@ static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) if (QLIST_EMPTY(&mon_fdset->dup_fds)) { monitor_fdset_cleanup(mon_fdset); } + return -1; + } else { + return mon_fdset->id; } - return mon_fdset->id; } } } @@ -2522,9 +2558,9 @@ int monitor_fdset_dup_fd_find(int dup_fd) return monitor_fdset_dup_fd_find_remove(dup_fd, false); } -int monitor_fdset_dup_fd_remove(int dup_fd) +void monitor_fdset_dup_fd_remove(int dup_fd) { - return monitor_fdset_dup_fd_find_remove(dup_fd, true); + monitor_fdset_dup_fd_find_remove(dup_fd, true); } int monitor_handle_fd_param(Monitor *mon, const char *fdname) @@ -2882,9 +2918,16 @@ static mon_cmd_t info_cmds[] = { .name = "memdev", .args_type = "", .params = "", - .help = "show the memory device", + .help = "show memory backends", .mhandler.cmd = hmp_info_memdev, }, + { + .name = "memory-devices", + .args_type = "", + .params = "", + .help = "show memory devices", + .mhandler.cmd = hmp_info_memory_devices, + }, { .name = NULL, }, @@ -4173,24 +4216,6 @@ static void file_completion(Monitor *mon, const char *input) closedir(ffs); } -typedef struct MonitorBlockComplete { - Monitor *mon; - const char *input; -} MonitorBlockComplete; - -static void block_completion_it(void *opaque, BlockDriverState *bs) -{ - const char *name = bdrv_get_device_name(bs); - MonitorBlockComplete *mbc = opaque; - Monitor *mon = mbc->mon; - const char *input = mbc->input; - - if (input[0] == '\0' || - !strncmp(name, (char *)input, strlen(input))) { - readline_add_completion(mon->rs, name); - } -} - static const char *next_arg_type(const char *typestr) { const char *p = strchr(typestr, ':'); @@ -4316,6 +4341,31 @@ static void device_del_bus_completion(ReadLineState *rs, BusState *bus, } } +static void peripheral_device_del_completion(ReadLineState *rs, + const char *str, size_t len) +{ + Object *peripheral; + GSList *list = NULL, *item; + + peripheral = object_resolve_path("/machine/peripheral/", NULL); + if (peripheral == NULL) { + return; + } + + object_child_foreach(peripheral, qdev_build_hotpluggable_device_list, + &list); + + for (item = list; item; item = g_slist_next(item)) { + DeviceState *dev = item->data; + + if (dev->id && !strncmp(str, dev->id, len)) { + readline_add_completion(rs, dev->id); + } + } + + g_slist_free(list); +} + void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; @@ -4389,6 +4439,7 @@ void device_del_completion(ReadLineState *rs, int nb_args, const char *str) len = strlen(str); readline_set_completion_index(rs, len); device_del_bus_completion(rs, sysbus_get_default(), str, len); + peripheral_device_del_completion(rs, str, len); } void object_del_completion(ReadLineState *rs, int nb_args, const char *str) @@ -4488,16 +4539,15 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) { + int i; + 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"); + for (i = 0; WatchdogExpirationAction_lookup[i]; i++) { + add_completion_option(rs, str, WatchdogExpirationAction_lookup[i]); + } } void migrate_set_capability_completion(ReadLineState *rs, int nb_args, @@ -4629,9 +4679,9 @@ static void monitor_find_completion_by_table(Monitor *mon, { const char *cmdname; int i; - const char *ptype, *str; + const char *ptype, *str, *name; const mon_cmd_t *cmd; - MonitorBlockComplete mbs; + BlockDriverState *bs; if (nb_args <= 1) { /* command completion */ @@ -4683,10 +4733,14 @@ static void monitor_find_completion_by_table(Monitor *mon, break; case 'B': /* block device name completion */ - mbs.mon = mon; - mbs.input = str; readline_set_completion_index(mon->rs, strlen(str)); - bdrv_iterate(block_completion_it, &mbs); + for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { + name = bdrv_get_device_name(bs); + if (str[0] == '\0' || + !strncmp(name, str, strlen(str))) { + readline_add_completion(mon->rs, name); + } + } break; case 's': case 'S': @@ -4713,8 +4767,11 @@ static void monitor_find_completion(void *opaque, return; } #ifdef DEBUG_COMPLETION - for (i = 0; i < nb_args; i++) { - monitor_printf(mon, "arg%d = '%s'\n", i, args[i]); + { + int i; + for (i = 0; i < nb_args; i++) { + monitor_printf(mon, "arg%d = '%s'\n", i, args[i]); + } } #endif @@ -5180,7 +5237,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,13 +5259,16 @@ 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: monitor_printf(mon, "QEMU %s monitor - type 'help' for more " "information\n", QEMU_VERSION); if (!mon->mux_out) { + readline_restart(mon->rs); readline_show_prompt(mon->rs); } mon->reset_seen = 1; @@ -5265,6 +5327,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; @@ -5302,7 +5369,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; } @@ -5330,7 +5400,7 @@ ReadLineState *monitor_get_rs(Monitor *mon) } int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, - BlockDriverCompletionFunc *completion_cb, + BlockCompletionFunc *completion_cb, void *opaque) { int err; @@ -5362,7 +5432,7 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, } int monitor_read_block_device_key(Monitor *mon, const char *device, - BlockDriverCompletionFunc *completion_cb, + BlockCompletionFunc *completion_cb, void *opaque) { BlockDriverState *bs; @@ -5397,3 +5467,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