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>
This commit is contained in:
parent
9ce44e2ce2
commit
bb4b9ead95
@ -617,8 +617,8 @@ pitfalls are:
|
||||
|
||||
Since the command handler may assume coroutine context, any callers
|
||||
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
|
||||
for a command. We don't currently have a use case for both together and
|
||||
|
@ -1056,12 +1056,26 @@ fail:
|
||||
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)
|
||||
{
|
||||
QDict *qdict;
|
||||
const HMPCommand *cmd;
|
||||
const char *cmd_start = cmdline;
|
||||
Monitor *old_mon;
|
||||
|
||||
trace_handle_hmp_command(mon, cmdline);
|
||||
|
||||
@ -1080,10 +1094,23 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
|
||||
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);
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ typedef struct HMPCommand {
|
||||
const char *help;
|
||||
const char *flags; /* p=preconfig */
|
||||
void (*cmd)(Monitor *mon, const QDict *qdict);
|
||||
bool coroutine;
|
||||
/*
|
||||
* @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
|
||||
|
Loading…
Reference in New Issue
Block a user