From patchwork Mon Mar 26 15:09:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 10308147 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E6C5C600CC for ; Mon, 26 Mar 2018 15:45:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D7E8129692 for ; Mon, 26 Mar 2018 15:45:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CC9C029697; Mon, 26 Mar 2018 15:45:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 324B029692 for ; Mon, 26 Mar 2018 15:45:26 +0000 (UTC) Received: from localhost ([::1]:57483 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f0UJJ-0004la-8Z for patchwork-qemu-devel@patchwork.kernel.org; Mon, 26 Mar 2018 11:45:25 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55517) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f0Tm8-0006g0-Rc for qemu-devel@nongnu.org; Mon, 26 Mar 2018 11:11:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f0Tm5-0003fR-LV for qemu-devel@nongnu.org; Mon, 26 Mar 2018 11:11:08 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:36690 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1f0Tm5-0003fA-G9 for qemu-devel@nongnu.org; Mon, 26 Mar 2018 11:11:05 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2B22B406E971; Mon, 26 Mar 2018 15:11:05 +0000 (UTC) Received: from localhost (ovpn-112-61.ams2.redhat.com [10.36.112.61]) by smtp.corp.redhat.com (Postfix) with ESMTP id C9CA3D7DFA; Mon, 26 Mar 2018 15:10:59 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Mon, 26 Mar 2018 17:09:15 +0200 Message-Id: <20180326150916.9602-38-marcandre.lureau@redhat.com> In-Reply-To: <20180326150916.9602-1-marcandre.lureau@redhat.com> References: <20180326150916.9602-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 26 Mar 2018 15:11:05 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 26 Mar 2018 15:11:05 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eduardo Habkost , Juan Quintela , Markus Armbruster , "Dr. David Alan Gilbert" , Gerd Hoffmann , Cleber Rosa , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Michael Roth Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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); }