#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/json-streamer.h"
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/qlist.h"
#include "qom/object_interfaces.h"
#include "sysemu/cpus.h"
#include "sysemu/iothread.h"
#include "qemu/cutils.h"
+#include "tcg/tcg.h"
#if defined(TARGET_S390X)
#include "hw/s390x/storage-keys.h"
QemuMutex qmp_queue_lock;
/* Input queue that holds all the parsed QMP requests */
GQueue *qmp_requests;
- /* Output queue contains all the QMP responses in order */
- GQueue *qmp_responses;
} MonitorQMP;
/*
/* Bottom half to dispatch the requests received from I/O thread */
QEMUBH *qmp_dispatcher_bh;
-/* Bottom half to deliver the responses back to clients */
-QEMUBH *qmp_respond_bh;
-
struct QMPRequest {
/* Owner of the request */
Monitor *mon;
*/
QObject *req;
Error *err;
- /*
- * Whether we need to resume the monitor afterward. This flag is
- * used to emulate the old QMP server behavior that the current
- * command must be completed before execution of the next one.
- */
- bool need_resume;
};
typedef struct QMPRequest QMPRequest;
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
-/* Protects mon_list, monitor_qapi_event_state. */
+/* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */
static QemuMutex monitor_lock;
static GHashTable *monitor_qapi_event_state;
static QTAILQ_HEAD(mon_list, Monitor) mon_list;
+static bool monitor_destroyed;
/* Protects mon_fdsets */
static QemuMutex mon_fdsets_lock;
}
}
-/* Caller must hold the mon->qmp.qmp_queue_lock */
-static void monitor_qmp_cleanup_resp_queue_locked(Monitor *mon)
-{
- while (!g_queue_is_empty(mon->qmp.qmp_responses)) {
- qobject_unref((QDict *)g_queue_pop_head(mon->qmp.qmp_responses));
- }
-}
-
static void monitor_qmp_cleanup_queues(Monitor *mon)
{
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
monitor_qmp_cleanup_req_queue_locked(mon);
- monitor_qmp_cleanup_resp_queue_locked(mon);
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
}
return 0;
}
-static void qmp_send_response(Monitor *mon, QDict *rsp)
+static void qmp_send_response(Monitor *mon, const QDict *rsp)
{
- QObject *data = QOBJECT(rsp);
+ const QObject *data = QOBJECT(rsp);
QString *json;
json = mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data) :
qobject_unref(json);
}
-static void qmp_queue_response(Monitor *mon, QDict *rsp)
-{
- if (mon->use_io_thread) {
- /*
- * Push a reference to the response queue. The I/O thread
- * drains that queue and emits.
- */
- qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
- g_queue_push_tail(mon->qmp.qmp_responses, qobject_ref(rsp));
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
- qemu_bh_schedule(qmp_respond_bh);
- } else {
- /*
- * Not using monitor I/O thread, i.e. we are in the main thread.
- * Emit right away.
- */
- qmp_send_response(mon, rsp);
- }
-}
-
-struct QMPResponse {
- Monitor *mon;
- QDict *data;
-};
-typedef struct QMPResponse QMPResponse;
-
-static QDict *monitor_qmp_response_pop_one(Monitor *mon)
-{
- QDict *data;
-
- qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
- data = g_queue_pop_head(mon->qmp.qmp_responses);
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
-
- return data;
-}
-
-static void monitor_qmp_response_flush(Monitor *mon)
-{
- QDict *data;
-
- while ((data = monitor_qmp_response_pop_one(mon))) {
- qmp_send_response(mon, data);
- qobject_unref(data);
- }
-}
-
-/*
- * Pop a QMPResponse from any monitor's response queue into @response.
- * Return false if all the queues are empty; else true.
- */
-static bool monitor_qmp_response_pop_any(QMPResponse *response)
-{
- Monitor *mon;
- QDict *data = NULL;
-
- qemu_mutex_lock(&monitor_lock);
- QTAILQ_FOREACH(mon, &mon_list, entry) {
- data = monitor_qmp_response_pop_one(mon);
- if (data) {
- response->mon = mon;
- response->data = data;
- break;
- }
- }
- qemu_mutex_unlock(&monitor_lock);
- return data != NULL;
-}
-
-static void monitor_qmp_bh_responder(void *opaque)
-{
- QMPResponse response;
-
- while (monitor_qmp_response_pop_any(&response)) {
- qmp_send_response(response.mon, response.data);
- qobject_unref(response.data);
- }
-}
-
static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
/* Limit guest-triggerable events to 1 per second */
[QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
QTAILQ_FOREACH(mon, &mon_list, entry) {
if (monitor_is_qmp(mon)
&& mon->qmp.commands != &qmp_cap_negotiation_commands) {
- qmp_queue_response(mon, qdict);
+ qmp_send_response(mon, qdict);
}
}
}
}
static void
-monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
+monitor_qapi_event_queue(QAPIEvent event, QDict *qdict)
{
/*
* monitor_qapi_event_queue_no_reenter() is not reentrant: it
static void handle_hmp_command(Monitor *mon, const char *cmdline);
+static void monitor_iothread_init(void);
+
static void monitor_data_init(Monitor *mon, bool skip_flush,
bool use_io_thread)
{
+ if (use_io_thread && !mon_iothread) {
+ monitor_iothread_init();
+ }
memset(mon, 0, sizeof(Monitor));
qemu_mutex_init(&mon->mon_lock);
qemu_mutex_init(&mon->qmp.qmp_queue_lock);
mon->skip_flush = skip_flush;
mon->use_io_thread = use_io_thread;
mon->qmp.qmp_requests = g_queue_new();
- mon->qmp.qmp_responses = g_queue_new();
}
static void monitor_data_destroy(Monitor *mon)
qemu_mutex_destroy(&mon->mon_lock);
qemu_mutex_destroy(&mon->qmp.qmp_queue_lock);
monitor_qmp_cleanup_req_queue_locked(mon);
- monitor_qmp_cleanup_resp_queue_locked(mon);
g_queue_free(mon->qmp.qmp_requests);
- g_queue_free(mon->qmp.qmp_responses);
}
char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
char **args, int nb_args, int arg_index)
{
const mon_cmd_t *cmd;
+ size_t i;
/* No valid arg need to compare with, dump all in *cmds */
if (arg_index >= nb_args) {
} else {
help_cmd_dump_one(mon, cmd, args, arg_index);
}
- break;
+ return;
}
}
+
+ /* Command not found */
+ monitor_printf(mon, "unknown command: '");
+ for (i = 0; i <= arg_index; i++) {
+ monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
+ }
}
static void help_cmd(Monitor *mon, const char *name)
*/
static void qmp_unregister_commands_hack(void)
{
-#ifndef CONFIG_REPLICATION
- qmp_unregister_command(&qmp_commands, "xen-set-replication");
- qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
- qmp_unregister_command(&qmp_commands, "xen-colo-do-checkpoint");
-#endif
#ifndef TARGET_I386
qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
qmp_unregister_command(&qmp_commands, "query-sev");
if (l > line_size)
l = line_size;
if (is_physical) {
- cpu_physical_memory_read(addr, buf, l);
+ AddressSpace *as = cs ? cs->as : &address_space_memory;
+ MemTxResult r = address_space_read(as, addr,
+ MEMTXATTRS_UNSPECIFIED, buf, l);
+ if (r != MEMTX_OK) {
+ monitor_printf(mon, " Cannot access memory\n");
+ break;
+ }
} else {
if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) {
monitor_printf(mon, " Cannot access memory\n");
#ifdef CONFIG_PROFILER
-int64_t tcg_time;
int64_t dev_time;
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
{
+ static int64_t last_cpu_exec_time;
+ int64_t cpu_exec_time;
+ int64_t delta;
+
+ cpu_exec_time = tcg_cpu_exec_time();
+ delta = cpu_exec_time - last_cpu_exec_time;
+
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
- tcg_time, tcg_time / (double)NANOSECONDS_PER_SECOND);
- tcg_time = 0;
+ delta, delta / (double)NANOSECONDS_PER_SECOND);
+ last_cpu_exec_time = cpu_exec_time;
dev_time = 0;
}
#else
{
int ret;
uint64_t val;
- char *end;
+ const char *end;
while (qemu_isspace(*p)) {
p++;
qdict_put_obj(rsp, "id", qobject_ref(id));
}
- qmp_queue_response(mon, rsp);
+ qmp_send_response(mon, rsp);
}
}
* processing commands only on a very busy monitor. To achieve that,
* when we process one request on a specific monitor, we put that
* monitor to the end of mon_list queue.
+ *
+ * Note: if the function returned with non-NULL, then the caller will
+ * be with mon->qmp.qmp_queue_lock held, and the caller is responsible
+ * to release it.
*/
-static QMPRequest *monitor_qmp_requests_pop_any(void)
+static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
{
QMPRequest *req_obj = NULL;
Monitor *mon;
QTAILQ_FOREACH(mon, &mon_list, entry) {
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
req_obj = g_queue_pop_head(mon->qmp.qmp_requests);
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
if (req_obj) {
+ /* With the lock of corresponding queue held */
break;
}
+ qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
}
if (req_obj) {
static void monitor_qmp_bh_dispatcher(void *data)
{
- QMPRequest *req_obj = monitor_qmp_requests_pop_any();
+ QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
QDict *rsp;
+ bool need_resume;
+ Monitor *mon;
if (!req_obj) {
return;
}
+ mon = req_obj->mon;
+ /* qmp_oob_enabled() might change after "qmp_capabilities" */
+ need_resume = !qmp_oob_enabled(mon) ||
+ mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+ qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
if (req_obj->req) {
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
- monitor_qmp_dispatch(req_obj->mon, req_obj->req, req_obj->id);
+ monitor_qmp_dispatch(mon, req_obj->req, req_obj->id);
} else {
assert(req_obj->err);
rsp = qmp_error_response(req_obj->err);
req_obj->err = NULL;
- monitor_qmp_respond(req_obj->mon, rsp, NULL);
+ monitor_qmp_respond(mon, rsp, NULL);
qobject_unref(rsp);
}
- if (req_obj->need_resume) {
+ if (need_resume) {
/* Pairs with the monitor_suspend() in handle_qmp_command() */
- monitor_resume(req_obj->mon);
+ monitor_resume(mon);
}
qmp_request_free(req_obj);
qemu_bh_schedule(qmp_dispatcher_bh);
}
-#define QMP_REQ_QUEUE_LEN_MAX (8)
-
-static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
+static void handle_qmp_command(void *opaque, QObject *req, Error *err)
{
- QObject *req, *id = NULL;
+ Monitor *mon = opaque;
+ QObject *id = NULL;
QDict *qdict;
- MonitorQMP *mon_qmp = container_of(parser, MonitorQMP, parser);
- Monitor *mon = container_of(mon_qmp, Monitor, qmp);
- Error *err = NULL;
QMPRequest *req_obj;
- req = json_parser_parse_err(tokens, NULL, &err);
- if (!req && !err) {
- /* json_parser_parse_err() sucks: can fail without setting @err */
- error_setg(&err, QERR_JSON_PARSING);
- }
+ assert(!req != !err);
qdict = qobject_to(QDict, req);
if (qdict) {
req_obj->id = id;
req_obj->req = req;
req_obj->err = err;
- req_obj->need_resume = false;
/* Protect qmp_requests and fetching its length. */
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
/*
- * If OOB is not enabled on the current monitor, we'll emulate the
- * old behavior that we won't process the current monitor any more
- * until it has responded. This helps make sure that as long as
- * OOB is not enabled, the server will never drop any command.
+ * Suspend the monitor when we can't queue more requests after
+ * this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume
+ * it. Note that when OOB is disabled, we queue at most one
+ * command, for backward compatibility.
*/
- if (!qmp_oob_enabled(mon)) {
+ if (!qmp_oob_enabled(mon) ||
+ mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
monitor_suspend(mon);
- req_obj->need_resume = true;
- } else {
- /* Drop the request if queue is full. */
- if (mon->qmp.qmp_requests->length >= QMP_REQ_QUEUE_LEN_MAX) {
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
- /*
- * FIXME @id's scope is just @mon, and broadcasting it is
- * wrong. If another monitor's client has a command with
- * the same ID in flight, the event will incorrectly claim
- * that command was dropped.
- */
- qapi_event_send_command_dropped(id,
- COMMAND_DROP_REASON_QUEUE_FULL,
- &error_abort);
- qmp_request_free(req_obj);
- return;
- }
}
/*
* handled in time order. Ownership for req_obj, req, id,
* etc. will be delivered to the handler side.
*/
+ assert(mon->qmp.qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
g_queue_push_tail(mon->qmp.qmp_requests, req_obj);
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
atomic_inc(&mon->suspend_cnt);
- if (monitor_is_qmp(mon)) {
+ if (mon->use_io_thread) {
/*
* Kick I/O thread to make sure this takes effect. It'll be
* evaluated again in prepare() of the watch object.
return 0;
}
+static void monitor_accept_input(void *opaque)
+{
+ Monitor *mon = opaque;
+
+ qemu_chr_fe_accept_input(&mon->chr);
+}
+
void monitor_resume(Monitor *mon)
{
if (monitor_is_hmp_non_interactive(mon)) {
}
if (atomic_dec_fetch(&mon->suspend_cnt) == 0) {
- if (monitor_is_qmp(mon)) {
- /*
- * For QMP monitors that are running in the I/O thread,
- * let's kick the thread in case it's sleeping.
- */
- if (mon->use_io_thread) {
- aio_notify(iothread_get_aio_context(mon_iothread));
- }
+ AioContext *ctx;
+
+ if (mon->use_io_thread) {
+ ctx = iothread_get_aio_context(mon_iothread);
} else {
+ ctx = qemu_get_aio_context();
+ }
+
+ if (!monitor_is_qmp(mon)) {
assert(mon->rs);
readline_show_prompt(mon->rs);
}
+
+ aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon);
}
+
trace_monitor_suspend(mon, -1);
}
mon->qmp.commands = &qmp_cap_negotiation_commands;
monitor_qmp_caps_reset(mon);
data = qmp_greeting(mon);
- qmp_queue_response(mon, data);
+ qmp_send_response(mon, data);
qobject_unref(data);
mon_refcount++;
break;
* stdio, it's possible that stdout is still open when stdin
* is closed.
*/
- monitor_qmp_response_flush(mon);
monitor_qmp_cleanup_queues(mon);
json_message_parser_destroy(&mon->qmp.parser);
- json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
+ json_message_parser_init(&mon->qmp.parser, handle_qmp_command,
+ mon, NULL);
mon_refcount--;
monitor_fdsets_cleanup();
break;
qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
}
-static GMainContext *monitor_get_io_context(void)
-{
- return iothread_get_g_main_context(mon_iothread);
-}
-
-static AioContext *monitor_get_aio_context(void)
+static void monitor_iothread_init(void)
{
- return iothread_get_aio_context(mon_iothread);
+ mon_iothread = iothread_create("mon_iothread", &error_abort);
}
-static void monitor_iothread_init(void)
+void monitor_init_globals(void)
{
- mon_iothread = iothread_create("mon_iothread", &error_abort);
+ monitor_init_qmp_commands();
+ monitor_qapi_event_init();
+ sortcmdlist();
+ qemu_mutex_init(&monitor_lock);
+ qemu_mutex_init(&mon_fdsets_lock);
/*
* The dispatcher BH must run in the main loop thread, since we
qmp_dispatcher_bh = aio_bh_new(iohandler_get_aio_context(),
monitor_qmp_bh_dispatcher,
NULL);
-
- /*
- * The responder BH must be run in the monitor I/O thread, so that
- * monitors that are using the I/O thread have their output
- * written by the I/O thread.
- */
- qmp_respond_bh = aio_bh_new(monitor_get_aio_context(),
- monitor_qmp_bh_responder,
- NULL);
-}
-
-void monitor_init_globals(void)
-{
- monitor_init_qmp_commands();
- monitor_qapi_event_init();
- sortcmdlist();
- qemu_mutex_init(&monitor_lock);
- qemu_mutex_init(&mon_fdsets_lock);
- monitor_iothread_init();
}
/* These functions just adapt the readline interface in a typesafe way. We
}
/*
- * Print to current monitor if we have one, else to stderr.
+ * Print to current monitor if we have one, else to stream.
* TODO should return int, so callers can calculate width, but that
* requires surgery to monitor_vprintf(). Left for another day.
*/
-void error_vprintf(const char *fmt, va_list ap)
+void monitor_vfprintf(FILE *stream, const char *fmt, va_list ap)
{
if (cur_mon && !monitor_cur_is_qmp()) {
monitor_vprintf(cur_mon, fmt, ap);
} else {
- vfprintf(stderr, fmt, ap);
+ vfprintf(stream, fmt, ap);
}
}
+/*
+ * Print to current monitor if we have one, else to stderr.
+ * TODO should return int, so callers can calculate width, but that
+ * requires surgery to monitor_vprintf(). Left for another day.
+ */
+void error_vprintf(const char *fmt, va_list ap)
+{
+ monitor_vfprintf(stderr, fmt, ap);
+}
+
void error_vprintf_unless_qmp(const char *fmt, va_list ap)
{
if (cur_mon && !monitor_cur_is_qmp()) {
static void monitor_list_append(Monitor *mon)
{
qemu_mutex_lock(&monitor_lock);
- QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
+ /*
+ * This prevents inserting new monitors during monitor_cleanup().
+ * A cleaner solution would involve the main thread telling other
+ * threads to terminate, waiting for their termination.
+ */
+ if (!monitor_destroyed) {
+ QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
+ mon = NULL;
+ }
qemu_mutex_unlock(&monitor_lock);
+
+ if (mon) {
+ monitor_data_destroy(mon);
+ g_free(mon);
+ }
}
static void monitor_qmp_setup_handlers_bh(void *opaque)
Monitor *mon = opaque;
GMainContext *context;
- if (mon->use_io_thread) {
- /* Use @mon_iothread context */
- context = monitor_get_io_context();
- assert(context);
- } else {
- /* Use default main loop context */
- context = NULL;
- }
-
+ assert(mon->use_io_thread);
+ context = iothread_get_g_main_context(mon_iothread);
+ assert(context);
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
monitor_qmp_event, NULL, mon, context, true);
monitor_list_append(mon);
{
Monitor *mon = g_malloc(sizeof(*mon));
bool use_readline = flags & MONITOR_USE_READLINE;
- bool use_oob = flags & MONITOR_USE_OOB;
-
- if (use_oob) {
- if (CHARDEV_IS_MUX(chr)) {
- error_report("Monitor out-of-band is not supported with "
- "MUX typed chardev backend");
- exit(1);
- }
- if (use_readline) {
- error_report("Monitor out-of-band is only supported by QMP");
- exit(1);
- }
- }
- monitor_data_init(mon, false, use_oob);
+ /* Note: we run QMP monitor in I/O thread when @chr supports that */
+ monitor_data_init(mon, false,
+ (flags & MONITOR_USE_CONTROL)
+ && qemu_chr_has_feature(chr,
+ QEMU_CHAR_FEATURE_GCONTEXT));
qemu_chr_fe_init(&mon->chr, chr, &error_abort);
mon->flags = flags;
if (monitor_is_qmp(mon)) {
qemu_chr_fe_set_echo(&mon->chr, true);
- json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
+ json_message_parser_init(&mon->qmp.parser, handle_qmp_command,
+ mon, NULL);
if (mon->use_io_thread) {
/*
* Make sure the old iowatch is gone. It's possible when
* since chardev might be running in the monitor I/O
* thread. Schedule a bottom half.
*/
- aio_bh_schedule_oneshot(monitor_get_aio_context(),
+ aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread),
monitor_qmp_setup_handlers_bh, mon);
/* The bottom half will add @mon to @mon_list */
return;
* we need to unregister from chardev below in
* monitor_data_destroy(), and chardev is not thread-safe yet
*/
- iothread_stop(mon_iothread);
-
- /*
- * Flush all response queues. Note that even after this flush,
- * data may remain in output buffers.
- */
- monitor_qmp_bh_responder(NULL);
+ if (mon_iothread) {
+ iothread_stop(mon_iothread);
+ }
/* Flush output buffers and destroy monitors */
qemu_mutex_lock(&monitor_lock);
+ monitor_destroyed = true;
QTAILQ_FOREACH_SAFE(mon, &mon_list, entry, next) {
QTAILQ_REMOVE(&mon_list, mon, entry);
+ /* Permit QAPI event emission from character frontend release */
+ qemu_mutex_unlock(&monitor_lock);
monitor_flush(mon);
monitor_data_destroy(mon);
+ qemu_mutex_lock(&monitor_lock);
g_free(mon);
}
qemu_mutex_unlock(&monitor_lock);
/* QEMUBHs needs to be deleted before destroying the I/O thread */
qemu_bh_delete(qmp_dispatcher_bh);
qmp_dispatcher_bh = NULL;
- qemu_bh_delete(qmp_respond_bh);
- qmp_respond_bh = NULL;
-
- iothread_destroy(mon_iothread);
- mon_iothread = NULL;
+ if (mon_iothread) {
+ iothread_destroy(mon_iothread);
+ mon_iothread = NULL;
+ }
}
QemuOptsList qemu_mon_opts = {
},{
.name = "pretty",
.type = QEMU_OPT_BOOL,
- },{
- .name = "x-oob",
- .type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},