Bladeren bron

hmp: Add support for coroutine command handlers

Often, QMP command handlers are not only called to handle QMP commands,
but also from a corresponding HMP command handler. In order to give them
a consistent environment, optionally run HMP command handlers in a
coroutine, too.

The implementation is a lot simpler than in QMP because for HMP, we
still block the VM while the coroutine is running.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-Id: <20201005155855.256490-11-kwolf@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Kevin Wolf 4 jaren geleden
bovenliggende
commit
bb4b9ead95
3 gewijzigde bestanden met toevoegingen van 35 en 7 verwijderingen
  1. 2 2
      docs/devel/qapi-code-gen.txt
  2. 32 5
      monitor/hmp.c
  3. 1 0
      monitor/monitor-internal.h

+ 2 - 2
docs/devel/qapi-code-gen.txt

@@ -617,8 +617,8 @@ pitfalls are:
 
 
 Since the command handler may assume coroutine context, any callers
 Since the command handler may assume coroutine context, any callers
 other than the QMP dispatcher must also call it in coroutine context.
 other than the QMP dispatcher must also call it in coroutine context.
-In particular, HMP commands calling such a QMP command handler must
-enter coroutine context before calling the handler.
+In particular, HMP commands calling such a QMP command handler must be
+marked .coroutine = true in hmp-commands.hx.
 
 
 It is an error to specify both 'coroutine': true and 'allow-oob': true
 It is an error to specify both 'coroutine': true and 'allow-oob': true
 for a command.  We don't currently have a use case for both together and
 for a command.  We don't currently have a use case for both together and

+ 32 - 5
monitor/hmp.c

@@ -1056,12 +1056,26 @@ fail:
     return NULL;
     return NULL;
 }
 }
 
 
+typedef struct HandleHmpCommandCo {
+    Monitor *mon;
+    const HMPCommand *cmd;
+    QDict *qdict;
+    bool done;
+} HandleHmpCommandCo;
+
+static void handle_hmp_command_co(void *opaque)
+{
+    HandleHmpCommandCo *data = opaque;
+    data->cmd->cmd(data->mon, data->qdict);
+    monitor_set_cur(qemu_coroutine_self(), NULL);
+    data->done = true;
+}
+
 void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
 void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
 {
 {
     QDict *qdict;
     QDict *qdict;
     const HMPCommand *cmd;
     const HMPCommand *cmd;
     const char *cmd_start = cmdline;
     const char *cmd_start = cmdline;
-    Monitor *old_mon;
 
 
     trace_handle_hmp_command(mon, cmdline);
     trace_handle_hmp_command(mon, cmdline);
 
 
@@ -1080,10 +1094,23 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
         return;
         return;
     }
     }
 
 
-    /* old_mon is non-NULL when called from qmp_human_monitor_command() */
-    old_mon = monitor_set_cur(qemu_coroutine_self(), &mon->common);
-    cmd->cmd(&mon->common, qdict);
-    monitor_set_cur(qemu_coroutine_self(), old_mon);
+    if (!cmd->coroutine) {
+        /* old_mon is non-NULL when called from qmp_human_monitor_command() */
+        Monitor *old_mon = monitor_set_cur(qemu_coroutine_self(), &mon->common);
+        cmd->cmd(&mon->common, qdict);
+        monitor_set_cur(qemu_coroutine_self(), old_mon);
+    } else {
+        HandleHmpCommandCo data = {
+            .mon = &mon->common,
+            .cmd = cmd,
+            .qdict = qdict,
+            .done = false,
+        };
+        Coroutine *co = qemu_coroutine_create(handle_hmp_command_co, &data);
+        monitor_set_cur(co, &mon->common);
+        aio_co_enter(qemu_get_aio_context(), co);
+        AIO_WAIT_WHILE(qemu_get_aio_context(), !data.done);
+    }
 
 
     qobject_unref(qdict);
     qobject_unref(qdict);
 }
 }

+ 1 - 0
monitor/monitor-internal.h

@@ -74,6 +74,7 @@ typedef struct HMPCommand {
     const char *help;
     const char *help;
     const char *flags; /* p=preconfig */
     const char *flags; /* p=preconfig */
     void (*cmd)(Monitor *mon, const QDict *qdict);
     void (*cmd)(Monitor *mon, const QDict *qdict);
+    bool coroutine;
     /*
     /*
      * @sub_table is a list of 2nd level of commands. If it does not exist,
      * @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
      * cmd should be used. If it exists, sub_table[?].cmd should be