diff options
-rw-r--r-- | docs/devel/qapi-code-gen.txt | 4 | ||||
-rw-r--r-- | monitor/hmp.c | 37 | ||||
-rw-r--r-- | monitor/monitor-internal.h | 1 |
3 files changed, 35 insertions, 7 deletions
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 4a41e36a75..c6438c6aa9 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -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 diff --git a/monitor/hmp.c b/monitor/hmp.c index abaf939b2d..c5cd9d372b 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -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); } diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index b55d6df07f..ad2e64be13 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -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 |