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;
}
}
-/* 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
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)
qdict_put_obj(rsp, "id", qobject_ref(id));
}
- qmp_queue_response(mon, rsp);
+ qmp_send_response(mon, rsp);
}
}
{
QMPRequest *req_obj = monitor_qmp_requests_pop_any();
QDict *rsp;
+ bool need_resume;
if (!req_obj) {
return;
}
+ /* qmp_oob_enabled() might change after "qmp_capabilities" */
+ need_resume = !qmp_oob_enabled(req_obj->mon);
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);
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);
}
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 (!qmp_oob_enabled(mon)) {
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) {
* that command was dropped.
*/
qapi_event_send_command_dropped(id,
- COMMAND_DROP_REASON_QUEUE_FULL,
- &error_abort);
+ COMMAND_DROP_REASON_QUEUE_FULL);
qmp_request_free(req_obj);
return;
}
assert(mon->rs);
readline_show_prompt(mon->rs);
}
+ qemu_chr_fe_accept_input(&mon->chr);
}
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,
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)
}
/*
- * 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()) {
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 = monitor_get_io_context();
+ 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);
*/
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);
-
/* Flush output buffers and destroy monitors */
qemu_mutex_lock(&monitor_lock);
QTAILQ_FOREACH_SAFE(mon, &mon_list, entry, next) {
/* 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;