qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]