[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous comm
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands |
Date: |
Mon, 26 Mar 2018 17:09:15 +0200 |
Similar to how we handle both synchronous and asynchronous commands in
QMP, HMP gains a new async_cmd() that will allow the command to
complete asynchronously. For interactive reasons, and command
ordering, the HMP monitor is suspended until the asynchronous command
completes.
Note that QMP human-monitor-command is modified to deal with it, by
using a specialized QmpSession return callback to destroy the
temporary HMP monitor.
Signed-off-by: Marc-André Lureau <address@hidden>
---
monitor.c | 106 ++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 79 insertions(+), 27 deletions(-)
diff --git a/monitor.c b/monitor.c
index e11c0abdca..018bd9280f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -127,13 +127,17 @@ typedef struct mon_cmd_t {
const char *args_type;
const char *params;
const char *help;
- void (*cmd)(Monitor *mon, const QDict *qdict);
+ union {
+ void (*cmd)(Monitor *mon, const QDict *qdict);
+ void (*async_cmd)(Monitor *mon, const QDict *qdict, QmpReturn *qret);
+ };
/* @sub_table is a list of 2nd level of commands. If it does not exist,
* cmd should be used. If it exists, sub_table[?].cmd should be
* used, and cmd 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);
+ bool async;
} mon_cmd_t;
/* file descriptors passed via SCM_RIGHTS */
@@ -203,6 +207,7 @@ struct Monitor {
int suspend_cnt; /* Needs to be accessed atomically */
bool skip_flush;
bool use_io_thr;
+ QmpReturn *for_qmp_command;
QemuMutex out_lock;
QString *outbuf;
@@ -607,7 +612,7 @@ static void monitor_qapi_event_init(void)
qmp_event_set_func_emit(monitor_qapi_event_queue);
}
-static void handle_hmp_command(Monitor *mon, const char *cmdline);
+static bool handle_hmp_command(Monitor *mon, const char *cmdline);
static void monitor_data_init(Monitor *mon, bool skip_flush,
bool use_io_thr)
@@ -637,16 +642,68 @@ static void monitor_data_destroy(Monitor *mon)
g_queue_free(mon->qmp.qmp_requests);
}
+static void free_temporary_hmp(void *opaque)
+{
+ Monitor *hmp = opaque;
+
+ qmp_session_destroy(&hmp->qmp.session);
+ monitor_data_destroy(hmp);
+ g_free(hmp);
+}
+
+static AioContext *monitor_get_aio_context(void)
+{
+ return iothread_get_aio_context(mon_global.mon_iothread);
+}
+
+static void qmp_human_monitor_command_finish(Monitor *hmp, QmpReturn *qret)
+{
+ char *output;
+
+ if (qstring_get_length(hmp->outbuf) > 0) {
+ output = g_strdup(qstring_get_str(hmp->outbuf));
+ } else {
+ output = g_strdup("");
+ }
+
+ qmp_human_monitor_command_return(qret, output);
+
+ if (hmp->for_qmp_command) {
+ aio_bh_schedule_oneshot(monitor_get_aio_context(),
+ free_temporary_hmp, hmp);
+ }
+}
+
+static void hmp_dispatch_return_cb(QmpSession *session, QDict *rsp)
+{
+ Monitor *hmp = container_of(session, Monitor, qmp.session);
+ QDict *err = qdict_get_qdict(rsp, "error");
+ Monitor *old_mon = cur_mon;
+
+ cur_mon = hmp;
+ if (err) {
+ error_report("%s", qdict_get_str(err, "desc"));
+ } /* XXX: else, report depending on command */
+
+ if (hmp->for_qmp_command) {
+ qmp_human_monitor_command_finish(hmp, hmp->for_qmp_command);
+ } else {
+ monitor_resume(hmp);
+ }
+ cur_mon = old_mon;
+}
+
void qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
int64_t cpu_index, QmpReturn *qret)
{
- char *output = NULL;
- Monitor *old_mon, hmp;
+ Monitor *old_mon, *hmp = g_new0(Monitor, 1);
- monitor_data_init(&hmp, true, false);
+ monitor_data_init(hmp, true, false);
+ qmp_session_init(&hmp->qmp.session, NULL, NULL, hmp_dispatch_return_cb);
+ hmp->for_qmp_command = qret;
old_mon = cur_mon;
- cur_mon = &hmp;
+ cur_mon = hmp;
if (has_cpu_index) {
int ret = monitor_set_cpu(cpu_index);
@@ -659,20 +716,11 @@ void qmp_human_monitor_command(const char *command_line,
bool has_cpu_index,
}
}
- handle_hmp_command(&hmp, command_line);
-
- 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("");
+ if (!handle_hmp_command(hmp, command_line)) {
+ qmp_human_monitor_command_finish(hmp, qret);
}
- qemu_mutex_unlock(&hmp.out_lock);
-
- qmp_human_monitor_command_return(qret, output);
out:
- monitor_data_destroy(&hmp);
cur_mon = old_mon;
}
@@ -3244,7 +3292,7 @@ fail:
return NULL;
}
-static void handle_hmp_command(Monitor *mon, const char *cmdline)
+static bool handle_hmp_command(Monitor *mon, const char *cmdline)
{
QDict *qdict;
const mon_cmd_t *cmd;
@@ -3253,18 +3301,25 @@ static void handle_hmp_command(Monitor *mon, const char
*cmdline)
cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
if (!cmd) {
- return;
+ return false;
}
qdict = monitor_parse_arguments(mon, &cmdline, cmd);
if (!qdict) {
monitor_printf(mon, "Try \"help %s\" for more information\n",
cmd->name);
- return;
+ return false;
+ }
+ if (cmd->async) {
+ QmpReturn *qret = qmp_return_new(&mon->qmp.session, NULL);
+ monitor_suspend(mon);
+ cmd->async_cmd(mon, qdict, qret);
+ } else {
+ cmd->cmd(mon, qdict);
}
-
- cmd->cmd(mon, qdict);
QDECREF(qdict);
+
+ return cmd->async;
}
static void cmd_completion(Monitor *mon, const char *name, const char *list)
@@ -4296,11 +4351,6 @@ static GMainContext *monitor_get_io_context(void)
return iothread_get_g_main_context(mon_global.mon_iothread);
}
-static AioContext *monitor_get_aio_context(void)
-{
- return iothread_get_aio_context(mon_global.mon_iothread);
-}
-
static void monitor_iothread_init(void)
{
mon_global.mon_iothread = iothread_create("mon_iothread",
@@ -4439,6 +4489,8 @@ void monitor_init(Chardev *chr, int flags)
NULL, mon, NULL, true);
}
} else {
+ qmp_session_init(&mon->qmp.session,
+ NULL, NULL, hmp_dispatch_return_cb);
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
monitor_event, NULL, mon, NULL, true);
}
--
2.17.0.rc1.1.g4c4f2b46a3
- [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf(), (continued)
- [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf(), Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 28/38] QmpSession: return orderly, Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 30/38] scripts: learn 'async' qapi commands, Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 29/38] qmp: introduce asynchronous command type, Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 31/38] qmp: add qmp_return_is_cancelled(), Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 33/38] console: graphic_hw_update return true if async, Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 34/38] console: add graphic_hw_update_done(), Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous, Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 36/38] monitor: start making qmp_human_monitor_command() asynchronous, Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 32/38] monitor: add qmp_return_get_monitor(), Marc-André Lureau, 2018/03/26
- [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands,
Marc-André Lureau <=
- [Qemu-devel] [PATCH v3 38/38] hmp: call the asynchronous QMP screendump to fix outdated/glitches, Marc-André Lureau, 2018/03/26
- Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type, Dr. David Alan Gilbert, 2018/03/26
- Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type, no-reply, 2018/03/26
- Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type, no-reply, 2018/03/27