Skip to content

Commit

Permalink
hmp: Add support for coroutine command handlers
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Dr. David Alan Gilbert <[email protected]>
Message-Id: <[email protected]>
Reviewed-by: Markus Armbruster <[email protected]>
Reviewed-by: Stefan Hajnoczi <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
  • Loading branch information
kevmw authored and Markus Armbruster committed Oct 9, 2020
1 parent 9ce44e2 commit bb4b9ea
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 7 deletions.
4 changes: 2 additions & 2 deletions docs/devel/qapi-code-gen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 32 additions & 5 deletions monitor/hmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,12 +1056,26 @@ static QDict *monitor_parse_arguments(Monitor *mon,
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);

Expand All @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions monitor/monitor-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bb4b9ea

Please sign in to comment.