From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444802; cv=none; d=zoho.com; s=zohoarc; b=Ena8PHwnPpx0wPSd3pva6WmLQeH0R0tiK9H7MFy+ySv/rT4NOUrUDV+hfpic1fbBkoCKtt+K1z1iJ4DFuxFqzQQqgOh87a06/lb3ujFCabkSwiRzl3JOk5BqhBt7dH36xjJ6gRS/7ZMVCCOPfE9pCcaRkOjzQfudzVyn/LUpbmo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444802; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=qNjuhY/7kNrnCSMNKTQZpa41PVdxU19FxH7fBf93Yqg=; b=IGKKK4qNOeGqf01MrzAUrAjylobWVJtJMxW+qFkq6o77P/Wd7L0NSdX726hwpgY0NqhyhTenC6+2HTfBleDasRBZYHBClC/nFW6WFxT4urAFj7SdmZgOO/eM2ndihNa4Kk1iTZ40dngj8ZgZYykR1cu0MgR7O4xwJbatgbpG6Q8= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560444802662509.38370477994897; Thu, 13 Jun 2019 09:53:22 -0700 (PDT) Received: from localhost ([::1]:41790 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSyX-0006bu-Gh for importer@patchew.org; Thu, 13 Jun 2019 12:53:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59650) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRkF-00006R-4S for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:34:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkD-0002un-NN for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:34:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39198) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkA-0002lO-GE; Thu, 13 Jun 2019 11:34:26 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4C1B386674; Thu, 13 Jun 2019 15:34:23 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id BE3D660C44; Thu, 13 Jun 2019 15:34:21 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:51 +0200 Message-Id: <20190613153405.24769-2-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 13 Jun 2019 15:34:25 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 01/15] monitor: Remove unused password prompting fields X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Commit 788cf9f8c removed the code for password prompting from the monitor. Since then, the Monitor fields password_completion_cb and password_opaque have been unused. Remove them. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- monitor.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/monitor.c b/monitor.c index 5c5cbe254a..9846a5623b 100644 --- a/monitor.c +++ b/monitor.c @@ -222,8 +222,6 @@ struct Monitor { =20 MonitorQMP qmp; gchar *mon_cpu_path; - BlockCompletionFunc *password_completion_cb; - void *password_opaque; mon_cmd_t *cmd_table; QTAILQ_ENTRY(Monitor) entry; =20 --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444111; cv=none; d=zoho.com; s=zohoarc; b=N1SmhFj4pG+rE6vnjSyQZCZ9X3ceUGI93R8jw9zxkLQ+wA3rGuAKsvfTDfvV2NANbvO8F36qTMXtcbEcbn4Igqimv4JcxysPFL1OIcILQ7g7iS/zz4nn1sLkenw3P9kdFHFhchVbsQ5yf4Eeupi2HZdnXiZyLq4BTHoZKXwHZrU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444111; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=vhMJMkXp7FV0Dp9iW2Q//L2Py40uU1DiwVZBkHrs3OM=; b=RHX1mgRxTyTZ93YGx/MIilocAsc/GYXEMcTVNkEurkpxJn1SNn8CVxTA4E531wYE295s2roZAiUaq+zYvOpfwoc6iOjjteUXJRoS3vLlCFwb3sMLfZCPr6MfPzyJp7mJEgdCgWDv7aXHze/xWuXX6AWq5YZmV94UqZZhXUFTGY4= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560444111925764.4572041951385; Thu, 13 Jun 2019 09:41:51 -0700 (PDT) Received: from localhost ([::1]:41618 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSnI-0005qa-Oe for importer@patchew.org; Thu, 13 Jun 2019 12:41:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59833) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRkl-0000M8-Bn for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkg-0003Go-Hd for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:00 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48056) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkU-00033T-Lv; Thu, 13 Jun 2019 11:34:46 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 06DAEC1EB217; Thu, 13 Jun 2019 15:34:26 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 97BFD61090; Thu, 13 Jun 2019 15:34:23 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:52 +0200 Message-Id: <20190613153405.24769-3-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Thu, 13 Jun 2019 15:34:31 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Instead of mixing HMP and QMP monitors in the same function, separate the monitor creation function for both. While in theory, one could pass both MONITOR_USE_CONTROL and MONITOR_USE_READLINE before this patch and both flags would do something, readline support is tightly coupled with HMP: QMP never feeds its input to readline, and the tab completion function treats the input as an HMP command. Therefore, this configuration is useless. After this patch, the QMP path asserts that MONITOR_USE_READLINE is not set. The HMP path can be used with or without MONITOR_USE_READLINE, like before. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- monitor.c | 89 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/monitor.c b/monitor.c index 9846a5623b..a70c1283b1 100644 --- a/monitor.c +++ b/monitor.c @@ -704,7 +704,7 @@ static void handle_hmp_command(Monitor *mon, const char= *cmdline); =20 static void monitor_iothread_init(void); =20 -static void monitor_data_init(Monitor *mon, bool skip_flush, +static void monitor_data_init(Monitor *mon, int flags, bool skip_flush, bool use_io_thread) { if (use_io_thread && !mon_iothread) { @@ -719,6 +719,7 @@ static void monitor_data_init(Monitor *mon, bool skip_f= lush, mon->skip_flush =3D skip_flush; mon->use_io_thread =3D use_io_thread; mon->qmp.qmp_requests =3D g_queue_new(); + mon->flags =3D flags; } =20 static void monitor_data_destroy(Monitor *mon) @@ -742,7 +743,7 @@ char *qmp_human_monitor_command(const char *command_lin= e, bool has_cpu_index, char *output =3D NULL; Monitor *old_mon, hmp; =20 - monitor_data_init(&hmp, true, false); + monitor_data_init(&hmp, 0, true, false); =20 old_mon =3D cur_mon; cur_mon =3D &hmp; @@ -4605,19 +4606,51 @@ static void monitor_qmp_setup_handlers_bh(void *opa= que) monitor_list_append(mon); } =20 -void monitor_init(Chardev *chr, int flags) +static void monitor_init_qmp(Chardev *chr, int flags) { Monitor *mon =3D g_malloc(sizeof(*mon)); - bool use_readline =3D flags & MONITOR_USE_READLINE; + + /* Only HMP supports readline */ + assert(!(flags & MONITOR_USE_READLINE)); =20 /* Note: we run QMP monitor in I/O thread when @chr supports that */ - monitor_data_init(mon, false, - (flags & MONITOR_USE_CONTROL) - && qemu_chr_has_feature(chr, - QEMU_CHAR_FEATURE_GCONTEXT)); + monitor_data_init(mon, flags, false, + qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); =20 qemu_chr_fe_init(&mon->chr, chr, &error_abort); - mon->flags =3D flags; + qemu_chr_fe_set_echo(&mon->chr, true); + + json_message_parser_init(&mon->qmp.parser, handle_qmp_command, mon, NU= LL); + if (mon->use_io_thread) { + /* + * Make sure the old iowatch is gone. It's possible when + * e.g. the chardev is in client mode, with wait=3Don. + */ + remove_fd_in_watch(chr); + /* + * We can't call qemu_chr_fe_set_handlers() directly here + * since chardev might be running in the monitor I/O + * thread. Schedule a bottom half. + */ + aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), + monitor_qmp_setup_handlers_bh, mon); + /* The bottom half will add @mon to @mon_list */ + } else { + qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, + monitor_qmp_read, monitor_qmp_event, + NULL, mon, NULL, true); + monitor_list_append(mon); + } +} + +static void monitor_init_hmp(Chardev *chr, int flags) +{ + Monitor *mon =3D g_malloc(sizeof(*mon)); + bool use_readline =3D flags & MONITOR_USE_READLINE; + + monitor_data_init(mon, flags, false, false); + qemu_chr_fe_init(&mon->chr, chr, &error_abort); + if (use_readline) { mon->rs =3D readline_init(monitor_readline_printf, monitor_readline_flush, @@ -4626,36 +4659,18 @@ void monitor_init(Chardev *chr, int flags) monitor_read_command(mon, 0); } =20 - if (monitor_is_qmp(mon)) { - qemu_chr_fe_set_echo(&mon->chr, true); - json_message_parser_init(&mon->qmp.parser, handle_qmp_command, - mon, NULL); - if (mon->use_io_thread) { - /* - * Make sure the old iowatch is gone. It's possible when - * e.g. the chardev is in client mode, with wait=3Don. - */ - remove_fd_in_watch(chr); - /* - * We can't call qemu_chr_fe_set_handlers() directly here - * since chardev might be running in the monitor I/O - * thread. Schedule a bottom half. - */ - aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), - monitor_qmp_setup_handlers_bh, mon); - /* The bottom half will add @mon to @mon_list */ - return; - } else { - qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, - monitor_qmp_read, monitor_qmp_event, - NULL, mon, NULL, true); - } + qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read, + monitor_event, NULL, mon, NULL, true); + monitor_list_append(mon); +} + +void monitor_init(Chardev *chr, int flags) +{ + if (flags & MONITOR_USE_CONTROL) { + monitor_init_qmp(chr, flags); } else { - qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read, - monitor_event, NULL, mon, NULL, true); + monitor_init_hmp(chr, flags); } - - monitor_list_append(mon); } =20 void monitor_cleanup(void) --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444113; cv=none; d=zoho.com; s=zohoarc; b=M5fjmmtrMD+TrQK4voVfGPhyng1KvHXScro56XRYUy1ifrQBJx7riy194ZNkUzmExlOS/vpGvF6ZgqsFQrIDCHJStOZKKjhGU5zV+JZLtNN8cQ3NS1NWpv9M5l17ozcCnQDRIn7S1OifmDnHjbzVEzKSqcTcS6DHwuxerfyP3lk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444113; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=nqiICLjYrqI0y+mZ+U7ucpNx8jktLOYVANdraUivmpQ=; b=gf66wt1pSuWV8RMvpb5AF5I3kbSx77MMOe5JqMnv0ybGZyngpJiXq1iBxpxzPviDjWi4+c7x+Vkujo8ONSxf5y8zXjPV9vu+gC9xa68+hPjiIvrEUZ0k7YcJbQZmVWnjKr0SjS2Mbp/rU0Sh+luElVDYVaR7kjdq67xpGtOudhI= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 156044411337346.45832927070626; Thu, 13 Jun 2019 09:41:53 -0700 (PDT) Received: from localhost ([::1]:41620 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSnN-0005tc-8n for importer@patchew.org; Thu, 13 Jun 2019 12:41:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59856) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRkm-0000MY-EP for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkg-0003HK-N1 for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:02 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52348) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkU-00036Y-SZ; Thu, 13 Jun 2019 11:34:48 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3959430917AA; Thu, 13 Jun 2019 15:34:33 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 520EA60C44; Thu, 13 Jun 2019 15:34:26 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:53 +0200 Message-Id: <20190613153405.24769-4-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.41]); Thu, 13 Jun 2019 15:34:41 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Currently, struct Monitor mixes state that is only relevant for HMP, state that is only relevant for QMP, and some actually shared state. In particular, a MonitorQMP field is present in the state of any monitor, even if it's not a QMP monitor and therefore doesn't use the state. As a first step towards a clean separation between QMP and HMP, let MonitorQMP extend Monitor and create a MonitorQMP object only when the monitor is actually a QMP monitor. Some places accessed Monitor.qmp unconditionally, even for HMP monitors. They can't keep doing this now, so during the conversion, they are either changed to become conditional on monitor_is_qmp() or to assert() that they always get a QMP monitor. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- monitor.c | 220 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 124 insertions(+), 96 deletions(-) diff --git a/monitor.c b/monitor.c index a70c1283b1..855a147723 100644 --- a/monitor.c +++ b/monitor.c @@ -168,26 +168,6 @@ struct MonFdset { QLIST_ENTRY(MonFdset) next; }; =20 -typedef struct { - JSONMessageParser parser; - /* - * When a client connects, we're in capabilities negotiation mode. - * @commands is &qmp_cap_negotiation_commands then. When command - * qmp_capabilities succeeds, we go into command mode, and - * @command becomes &qmp_commands. - */ - QmpCommandList *commands; - bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ - bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ - /* - * Protects qmp request/response queue. - * Take monitor_lock first when you need both. - */ - QemuMutex qmp_queue_lock; - /* Input queue that holds all the parsed QMP requests */ - GQueue *qmp_requests; -} MonitorQMP; - /* * To prevent flooding clients, events can be throttled. The * throttling is calculated globally, rather than per-Monitor @@ -220,7 +200,6 @@ struct Monitor { */ ReadLineState *rs; =20 - MonitorQMP qmp; gchar *mon_cpu_path; mon_cmd_t *cmd_table; QTAILQ_ENTRY(Monitor) entry; @@ -241,6 +220,27 @@ struct Monitor { int mux_out; }; =20 +typedef struct { + Monitor common; + JSONMessageParser parser; + /* + * When a client connects, we're in capabilities negotiation mode. + * @commands is &qmp_cap_negotiation_commands then. When command + * qmp_capabilities succeeds, we go into command mode, and + * @command becomes &qmp_commands. + */ + QmpCommandList *commands; + bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ + bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ + /* + * Protects qmp request/response queue. + * Take monitor_lock first when you need both. + */ + QemuMutex qmp_queue_lock; + /* Input queue that holds all the parsed QMP requests */ + GQueue *qmp_requests; +} MonitorQMP; + /* Shared monitor I/O thread */ IOThread *mon_iothread; =20 @@ -249,7 +249,7 @@ QEMUBH *qmp_dispatcher_bh; =20 struct QMPRequest { /* Owner of the request */ - Monitor *mon; + MonitorQMP *mon; /* * Request object to be handled or Error to be reported * (exactly one of them is non-null) @@ -357,18 +357,18 @@ static void qmp_request_free(QMPRequest *req) } =20 /* Caller must hold mon->qmp.qmp_queue_lock */ -static void monitor_qmp_cleanup_req_queue_locked(Monitor *mon) +static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon) { - while (!g_queue_is_empty(mon->qmp.qmp_requests)) { - qmp_request_free(g_queue_pop_head(mon->qmp.qmp_requests)); + while (!g_queue_is_empty(mon->qmp_requests)) { + qmp_request_free(g_queue_pop_head(mon->qmp_requests)); } } =20 -static void monitor_qmp_cleanup_queues(Monitor *mon) +static void monitor_qmp_cleanup_queues(MonitorQMP *mon) { - qemu_mutex_lock(&mon->qmp.qmp_queue_lock); + qemu_mutex_lock(&mon->qmp_queue_lock); monitor_qmp_cleanup_req_queue_locked(mon); - qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); + qemu_mutex_unlock(&mon->qmp_queue_lock); } =20 =20 @@ -480,17 +480,17 @@ int monitor_printf(Monitor *mon, const char *fmt, ...) return ret; } =20 -static void qmp_send_response(Monitor *mon, const QDict *rsp) +static void qmp_send_response(MonitorQMP *mon, const QDict *rsp) { const QObject *data =3D QOBJECT(rsp); QString *json; =20 - json =3D mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data= ) : - qobject_to_json(data); + json =3D mon->common.flags & MONITOR_USE_PRETTY ? + qobject_to_json_pretty(data) : qobject_to_json(data); assert(json !=3D NULL); =20 qstring_append_chr(json, '\n'); - monitor_puts(mon, qstring_get_str(json)); + monitor_puts(&mon->common, qstring_get_str(json)); =20 qobject_unref(json); } @@ -513,12 +513,17 @@ static MonitorQAPIEventConf monitor_qapi_event_conf[Q= API_EVENT__MAX] =3D { static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) { Monitor *mon; + MonitorQMP *qmp_mon; =20 trace_monitor_protocol_event_emit(event, qdict); QTAILQ_FOREACH(mon, &mon_list, entry) { - if (monitor_is_qmp(mon) - && mon->qmp.commands !=3D &qmp_cap_negotiation_commands) { - qmp_send_response(mon, qdict); + if (!monitor_is_qmp(mon)) { + continue; + } + + qmp_mon =3D container_of(mon, MonitorQMP, common); + if (qmp_mon->commands !=3D &qmp_cap_negotiation_commands) { + qmp_send_response(qmp_mon, qdict); } } } @@ -712,29 +717,33 @@ static void monitor_data_init(Monitor *mon, int flags= , bool skip_flush, } memset(mon, 0, sizeof(Monitor)); qemu_mutex_init(&mon->mon_lock); - qemu_mutex_init(&mon->qmp.qmp_queue_lock); mon->outbuf =3D qstring_new(); /* Use *mon_cmds by default. */ mon->cmd_table =3D mon_cmds; mon->skip_flush =3D skip_flush; mon->use_io_thread =3D use_io_thread; - mon->qmp.qmp_requests =3D g_queue_new(); mon->flags =3D flags; } =20 +static void monitor_data_destroy_qmp(MonitorQMP *mon) +{ + json_message_parser_destroy(&mon->parser); + qemu_mutex_destroy(&mon->qmp_queue_lock); + monitor_qmp_cleanup_req_queue_locked(mon); + g_queue_free(mon->qmp_requests); +} + static void monitor_data_destroy(Monitor *mon) { g_free(mon->mon_cpu_path); qemu_chr_fe_deinit(&mon->chr, false); if (monitor_is_qmp(mon)) { - json_message_parser_destroy(&mon->qmp.parser); + MonitorQMP *qmp_mon =3D container_of(mon, MonitorQMP, common); + monitor_data_destroy_qmp(qmp_mon); } readline_free(mon->rs); qobject_unref(mon->outbuf); qemu_mutex_destroy(&mon->mon_lock); - qemu_mutex_destroy(&mon->qmp.qmp_queue_lock); - monitor_qmp_cleanup_req_queue_locked(mon); - g_queue_free(mon->qmp.qmp_requests); } =20 char *qmp_human_monitor_command(const char *command_line, bool has_cpu_ind= ex, @@ -1087,8 +1096,12 @@ static void query_commands_cb(QmpCommand *cmd, void = *opaque) CommandInfoList *qmp_query_commands(Error **errp) { CommandInfoList *list =3D NULL; + MonitorQMP *mon; + + assert(monitor_is_qmp(cur_mon)); + mon =3D container_of(cur_mon, MonitorQMP, common); =20 - qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list); + qmp_for_each_command(mon->commands, query_commands_cb, &list); =20 return list; } @@ -1155,16 +1168,16 @@ static void monitor_init_qmp_commands(void) qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG= ); } =20 -static bool qmp_oob_enabled(Monitor *mon) +static bool qmp_oob_enabled(MonitorQMP *mon) { - return mon->qmp.capab[QMP_CAPABILITY_OOB]; + return mon->capab[QMP_CAPABILITY_OOB]; } =20 -static void monitor_qmp_caps_reset(Monitor *mon) +static void monitor_qmp_caps_reset(MonitorQMP *mon) { - memset(mon->qmp.capab_offered, 0, sizeof(mon->qmp.capab_offered)); - memset(mon->qmp.capab, 0, sizeof(mon->qmp.capab)); - mon->qmp.capab_offered[QMP_CAPABILITY_OOB] =3D mon->use_io_thread; + memset(mon->capab_offered, 0, sizeof(mon->capab_offered)); + memset(mon->capab, 0, sizeof(mon->capab)); + mon->capab_offered[QMP_CAPABILITY_OOB] =3D mon->common.use_io_thread; } =20 /* @@ -1172,7 +1185,7 @@ static void monitor_qmp_caps_reset(Monitor *mon) * On success, set mon->qmp.capab[], and return true. * On error, set @errp, and return false. */ -static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list, +static bool qmp_caps_accept(MonitorQMP *mon, QMPCapabilityList *list, Error **errp) { GString *unavailable =3D NULL; @@ -1181,7 +1194,7 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabili= tyList *list, memset(capab, 0, sizeof(capab)); =20 for (; list; list =3D list->next) { - if (!mon->qmp.capab_offered[list->value]) { + if (!mon->capab_offered[list->value]) { if (!unavailable) { unavailable =3D g_string_new(QMPCapability_str(list->value= )); } else { @@ -1198,25 +1211,30 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabi= lityList *list, return false; } =20 - memcpy(mon->qmp.capab, capab, sizeof(capab)); + memcpy(mon->capab, capab, sizeof(capab)); return true; } =20 void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, Error **errp) { - if (cur_mon->qmp.commands =3D=3D &qmp_commands) { + MonitorQMP *mon; + + assert(monitor_is_qmp(cur_mon)); + mon =3D container_of(cur_mon, MonitorQMP, common); + + if (mon->commands =3D=3D &qmp_commands) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "Capabilities negotiation is already complete, command " "ignored"); return; } =20 - if (!qmp_caps_accept(cur_mon, enable, errp)) { + if (!qmp_caps_accept(mon, enable, errp)) { return; } =20 - cur_mon->qmp.commands =3D &qmp_commands; + mon->commands =3D &qmp_commands; } =20 /* Set the current CPU defined by the user. Callers must hold BQL. */ @@ -4123,27 +4141,27 @@ static int monitor_can_read(void *opaque) * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. * Nothing is emitted then. */ -static void monitor_qmp_respond(Monitor *mon, QDict *rsp) +static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) { if (rsp) { qmp_send_response(mon, rsp); } } =20 -static void monitor_qmp_dispatch(Monitor *mon, QObject *req) +static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) { Monitor *old_mon; QDict *rsp; QDict *error; =20 old_mon =3D cur_mon; - cur_mon =3D mon; + cur_mon =3D &mon->common; =20 - rsp =3D qmp_dispatch(mon->qmp.commands, req, qmp_oob_enabled(mon)); + rsp =3D qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon)); =20 cur_mon =3D old_mon; =20 - if (mon->qmp.commands =3D=3D &qmp_cap_negotiation_commands) { + if (mon->commands =3D=3D &qmp_cap_negotiation_commands) { error =3D qdict_get_qdict(rsp, "error"); if (error && !g_strcmp0(qdict_get_try_str(error, "class"), @@ -4168,24 +4186,30 @@ static void monitor_qmp_dispatch(Monitor *mon, QObj= ect *req) * monitor to the end of mon_list queue. * * Note: if the function returned with non-NULL, then the caller will - * be with mon->qmp.qmp_queue_lock held, and the caller is responsible + * be with qmp_mon->qmp_queue_lock held, and the caller is responsible * to release it. */ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void) { QMPRequest *req_obj =3D NULL; Monitor *mon; + MonitorQMP *qmp_mon; =20 qemu_mutex_lock(&monitor_lock); =20 QTAILQ_FOREACH(mon, &mon_list, entry) { - qemu_mutex_lock(&mon->qmp.qmp_queue_lock); - req_obj =3D g_queue_pop_head(mon->qmp.qmp_requests); + if (!monitor_is_qmp(mon)) { + continue; + } + + qmp_mon =3D container_of(mon, MonitorQMP, common); + qemu_mutex_lock(&qmp_mon->qmp_queue_lock); + req_obj =3D g_queue_pop_head(qmp_mon->qmp_requests); if (req_obj) { /* With the lock of corresponding queue held */ break; } - qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); + qemu_mutex_unlock(&qmp_mon->qmp_queue_lock); } =20 if (req_obj) { @@ -4207,7 +4231,7 @@ static void monitor_qmp_bh_dispatcher(void *data) QMPRequest *req_obj =3D monitor_qmp_requests_pop_any_with_lock(); QDict *rsp; bool need_resume; - Monitor *mon; + MonitorQMP *mon; =20 if (!req_obj) { return; @@ -4216,8 +4240,8 @@ static void monitor_qmp_bh_dispatcher(void *data) mon =3D req_obj->mon; /* qmp_oob_enabled() might change after "qmp_capabilities" */ need_resume =3D !qmp_oob_enabled(mon) || - mon->qmp.qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1; - qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); + mon->qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1; + qemu_mutex_unlock(&mon->qmp_queue_lock); if (req_obj->req) { QDict *qdict =3D qobject_to(QDict, req_obj->req); QObject *id =3D qdict ? qdict_get(qdict, "id") : NULL; @@ -4233,7 +4257,7 @@ static void monitor_qmp_bh_dispatcher(void *data) =20 if (need_resume) { /* Pairs with the monitor_suspend() in handle_qmp_command() */ - monitor_resume(mon); + monitor_resume(&mon->common); } qmp_request_free(req_obj); =20 @@ -4243,7 +4267,7 @@ static void monitor_qmp_bh_dispatcher(void *data) =20 static void handle_qmp_command(void *opaque, QObject *req, Error *err) { - Monitor *mon =3D opaque; + MonitorQMP *mon =3D opaque; QObject *id =3D NULL; QDict *qdict; QMPRequest *req_obj; @@ -4275,7 +4299,7 @@ static void handle_qmp_command(void *opaque, QObject = *req, Error *err) req_obj->err =3D err; =20 /* Protect qmp_requests and fetching its length. */ - qemu_mutex_lock(&mon->qmp.qmp_queue_lock); + qemu_mutex_lock(&mon->qmp_queue_lock); =20 /* * Suspend the monitor when we can't queue more requests after @@ -4284,8 +4308,8 @@ static void handle_qmp_command(void *opaque, QObject = *req, Error *err) * command, for backward compatibility. */ if (!qmp_oob_enabled(mon) || - mon->qmp.qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1) { - monitor_suspend(mon); + mon->qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1) { + monitor_suspend(&mon->common); } =20 /* @@ -4293,9 +4317,9 @@ static void handle_qmp_command(void *opaque, QObject = *req, Error *err) * handled in time order. Ownership for req_obj, req, * etc. will be delivered to the handler side. */ - assert(mon->qmp.qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); - g_queue_push_tail(mon->qmp.qmp_requests, req_obj); - qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); + assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); + g_queue_push_tail(mon->qmp_requests, req_obj); + qemu_mutex_unlock(&mon->qmp_queue_lock); =20 /* Kick the dispatcher routine */ qemu_bh_schedule(qmp_dispatcher_bh); @@ -4303,9 +4327,9 @@ static void handle_qmp_command(void *opaque, QObject = *req, Error *err) =20 static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) { - Monitor *mon =3D opaque; + MonitorQMP *mon =3D opaque; =20 - json_message_parser_feed(&mon->qmp.parser, (const char *) buf, size); + json_message_parser_feed(&mon->parser, (const char *) buf, size); } =20 static void monitor_read(void *opaque, const uint8_t *buf, int size) @@ -4391,7 +4415,7 @@ void monitor_resume(Monitor *mon) trace_monitor_suspend(mon, -1); } =20 -static QDict *qmp_greeting(Monitor *mon) +static QDict *qmp_greeting(MonitorQMP *mon) { QList *cap_list =3D qlist_new(); QObject *ver =3D NULL; @@ -4400,7 +4424,7 @@ static QDict *qmp_greeting(Monitor *mon) qmp_marshal_query_version(NULL, &ver, NULL); =20 for (cap =3D 0; cap < QMP_CAPABILITY__MAX; cap++) { - if (mon->qmp.capab_offered[cap]) { + if (mon->capab_offered[cap]) { qlist_append_str(cap_list, QMPCapability_str(cap)); } } @@ -4413,11 +4437,11 @@ static QDict *qmp_greeting(Monitor *mon) static void monitor_qmp_event(void *opaque, int event) { QDict *data; - Monitor *mon =3D opaque; + MonitorQMP *mon =3D opaque; =20 switch (event) { case CHR_EVENT_OPENED: - mon->qmp.commands =3D &qmp_cap_negotiation_commands; + mon->commands =3D &qmp_cap_negotiation_commands; monitor_qmp_caps_reset(mon); data =3D qmp_greeting(mon); qmp_send_response(mon, data); @@ -4432,8 +4456,8 @@ static void monitor_qmp_event(void *opaque, int event) * is closed. */ monitor_qmp_cleanup_queues(mon); - json_message_parser_destroy(&mon->qmp.parser); - json_message_parser_init(&mon->qmp.parser, handle_qmp_command, + json_message_parser_destroy(&mon->parser); + json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); mon_refcount--; monitor_fdsets_cleanup(); @@ -4595,33 +4619,37 @@ static void monitor_list_append(Monitor *mon) =20 static void monitor_qmp_setup_handlers_bh(void *opaque) { - Monitor *mon =3D opaque; + MonitorQMP *mon =3D opaque; GMainContext *context; =20 - assert(mon->use_io_thread); + assert(mon->common.use_io_thread); context =3D iothread_get_g_main_context(mon_iothread); assert(context); - qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read, - monitor_qmp_event, NULL, mon, context, true); - monitor_list_append(mon); + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, + monitor_qmp_read, monitor_qmp_event, + NULL, &mon->common, context, true); + monitor_list_append(&mon->common); } =20 static void monitor_init_qmp(Chardev *chr, int flags) { - Monitor *mon =3D g_malloc(sizeof(*mon)); + MonitorQMP *mon =3D g_malloc0(sizeof(*mon)); =20 /* Only HMP supports readline */ assert(!(flags & MONITOR_USE_READLINE)); =20 /* Note: we run QMP monitor in I/O thread when @chr supports that */ - monitor_data_init(mon, flags, false, + monitor_data_init(&mon->common, flags, false, qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); =20 - qemu_chr_fe_init(&mon->chr, chr, &error_abort); - qemu_chr_fe_set_echo(&mon->chr, true); + qemu_mutex_init(&mon->qmp_queue_lock); + mon->qmp_requests =3D g_queue_new(); =20 - json_message_parser_init(&mon->qmp.parser, handle_qmp_command, mon, NU= LL); - if (mon->use_io_thread) { + qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); + qemu_chr_fe_set_echo(&mon->common.chr, true); + + json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); + if (mon->common.use_io_thread) { /* * Make sure the old iowatch is gone. It's possible when * e.g. the chardev is in client mode, with wait=3Don. @@ -4636,10 +4664,10 @@ static void monitor_init_qmp(Chardev *chr, int flag= s) monitor_qmp_setup_handlers_bh, mon); /* The bottom half will add @mon to @mon_list */ } else { - qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_qmp_read, monitor_qmp_event, - NULL, mon, NULL, true); - monitor_list_append(mon); + NULL, &mon->common, NULL, true); + monitor_list_append(&mon->common); } } =20 --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444404; cv=none; d=zoho.com; s=zohoarc; b=U6XlvwLWszkhbukN88KL7bd2s2+embRTurIERBvsCeWKgaF7owUkOOiLuaLq/jbNEXHEI2a5sn6K9YhOeh61OpUhFxSAmkX+nSUwsIU46nRhJz60j0AbyYpa23dkbWNOIqjnStJIkUZrGoHn0pMUH1ZqOGDCa0iVgCKfa4MZQCE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444404; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=yKmkQGDMY6avSeUFD0KM6rS7pbGrkI3BMevOAYxfzPg=; b=FovSSjhmI0txsz9ZscpJKtVqhAvL8t44E6/D66KXMsgLuogupZ8m5bInqv+CRl9lfdeTfRHutFkZDsgpQ+AAuAxvQQfG1aGPaldSnaJsJQdYvZl5gPE51EgJwvxsj5vMs1uEyyVx0FCY2jrT+1RyCxaojX2Hj9lKvPRWtx5qx8g= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560444404956689.4893431126895; Thu, 13 Jun 2019 09:46:44 -0700 (PDT) Received: from localhost ([::1]:41738 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSs7-0001Ia-S7 for importer@patchew.org; Thu, 13 Jun 2019 12:46:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59970) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRks-0000UU-8O for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRko-0003QV-VV for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:10 -0400 Received: from mx1.redhat.com ([209.132.183.28]:45378) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkd-0003B9-A1; Thu, 13 Jun 2019 11:34:58 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1A0B530C0DEA; Thu, 13 Jun 2019 15:34:36 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 852EE60C78; Thu, 13 Jun 2019 15:34:33 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:54 +0200 Message-Id: <20190613153405.24769-5-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.45]); Thu, 13 Jun 2019 15:34:46 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" The ReadLineState in Monitor is only used for HMP monitors. Create MonitorHMP and move it there. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- include/monitor/monitor.h | 5 +- hmp.c | 4 +- monitor.c | 129 +++++++++++++++++++++----------------- 3 files changed, 79 insertions(+), 59 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 06cfcd8f36..efdea83bb3 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -6,6 +6,7 @@ #include "qemu/readline.h" =20 extern __thread Monitor *cur_mon; +typedef struct MonitorHMP MonitorHMP; =20 /* flags for monitor_init */ /* 0x01 unused */ @@ -34,8 +35,8 @@ void monitor_flush(Monitor *mon); int monitor_set_cpu(int cpu_index); int monitor_get_cpu_index(void); =20 -void monitor_read_command(Monitor *mon, int show_prompt); -int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, +void monitor_read_command(MonitorHMP *mon, int show_prompt); +int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque); =20 AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_i= d, diff --git a/hmp.c b/hmp.c index be5e345c6f..99414cd39c 100644 --- a/hmp.c +++ b/hmp.c @@ -1943,6 +1943,8 @@ static void hmp_change_read_arg(void *opaque, const c= har *password, =20 void hmp_change(Monitor *mon, const QDict *qdict) { + /* FIXME Make MonitorHMP public and use container_of */ + MonitorHMP *hmp_mon =3D (MonitorHMP *) mon; const char *device =3D qdict_get_str(qdict, "device"); const char *target =3D qdict_get_str(qdict, "target"); const char *arg =3D qdict_get_try_str(qdict, "arg"); @@ -1960,7 +1962,7 @@ void hmp_change(Monitor *mon, const QDict *qdict) if (strcmp(target, "passwd") =3D=3D 0 || strcmp(target, "password") =3D=3D 0) { if (!arg) { - monitor_read_password(mon, hmp_change_read_arg, NULL); + monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); return; } } diff --git a/monitor.c b/monitor.c index 855a147723..572449f6db 100644 --- a/monitor.c +++ b/monitor.c @@ -192,14 +192,6 @@ struct Monitor { bool skip_flush; bool use_io_thread; =20 - /* - * State used only in the thread "owning" the monitor. - * If @use_io_thread, this is @mon_iothread. - * Else, it's the main thread. - * These members can be safely accessed without locks. - */ - ReadLineState *rs; - gchar *mon_cpu_path; mon_cmd_t *cmd_table; QTAILQ_ENTRY(Monitor) entry; @@ -220,6 +212,18 @@ struct Monitor { int mux_out; }; =20 +struct MonitorHMP { + Monitor common; + /* + * State used only in the thread "owning" the monitor. + * If @use_io_thread, this is @mon_iothread. (This does not actually h= appen + * in the current state of the code.) + * Else, it's the main thread. + * These members can be safely accessed without locks. + */ + ReadLineState *rs; +}; + typedef struct { Monitor common; JSONMessageParser parser; @@ -326,7 +330,7 @@ bool monitor_cur_is_qmp(void) return cur_mon && monitor_is_qmp(cur_mon); } =20 -void monitor_read_command(Monitor *mon, int show_prompt) +void monitor_read_command(MonitorHMP *mon, int show_prompt) { if (!mon->rs) return; @@ -336,7 +340,7 @@ void monitor_read_command(Monitor *mon, int show_prompt) readline_show_prompt(mon->rs); } =20 -int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, +int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, void *opaque) { if (mon->rs) { @@ -344,7 +348,8 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *r= eadline_func, /* prompt is printed on return from the command handler */ return 0; } else { - monitor_printf(mon, "terminal does not support password prompting\= n"); + monitor_printf(&mon->common, + "terminal does not support password prompting\n"); return -ENOTTY; } } @@ -705,7 +710,7 @@ static void monitor_qapi_event_init(void) qapi_event_throttle_equal); } =20 -static void handle_hmp_command(Monitor *mon, const char *cmdline); +static void handle_hmp_command(MonitorHMP *mon, const char *cmdline); =20 static void monitor_iothread_init(void); =20 @@ -715,7 +720,6 @@ static void monitor_data_init(Monitor *mon, int flags, = bool skip_flush, if (use_io_thread && !mon_iothread) { monitor_iothread_init(); } - memset(mon, 0, sizeof(Monitor)); qemu_mutex_init(&mon->mon_lock); mon->outbuf =3D qstring_new(); /* Use *mon_cmds by default. */ @@ -740,8 +744,10 @@ static void monitor_data_destroy(Monitor *mon) if (monitor_is_qmp(mon)) { MonitorQMP *qmp_mon =3D container_of(mon, MonitorQMP, common); monitor_data_destroy_qmp(qmp_mon); + } else { + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); + readline_free(hmp_mon->rs); } - readline_free(mon->rs); qobject_unref(mon->outbuf); qemu_mutex_destroy(&mon->mon_lock); } @@ -750,12 +756,13 @@ char *qmp_human_monitor_command(const char *command_l= ine, bool has_cpu_index, int64_t cpu_index, Error **errp) { char *output =3D NULL; - Monitor *old_mon, hmp; + Monitor *old_mon; + MonitorHMP hmp =3D {}; =20 - monitor_data_init(&hmp, 0, true, false); + monitor_data_init(&hmp.common, 0, true, false); =20 old_mon =3D cur_mon; - cur_mon =3D &hmp; + cur_mon =3D &hmp.common; =20 if (has_cpu_index) { int ret =3D monitor_set_cpu(cpu_index); @@ -770,16 +777,16 @@ char *qmp_human_monitor_command(const char *command_l= ine, bool has_cpu_index, handle_hmp_command(&hmp, command_line); cur_mon =3D old_mon; =20 - qemu_mutex_lock(&hmp.mon_lock); - if (qstring_get_length(hmp.outbuf) > 0) { - output =3D g_strdup(qstring_get_str(hmp.outbuf)); + qemu_mutex_lock(&hmp.common.mon_lock); + if (qstring_get_length(hmp.common.outbuf) > 0) { + output =3D g_strdup(qstring_get_str(hmp.common.outbuf)); } else { output =3D g_strdup(""); } - qemu_mutex_unlock(&hmp.mon_lock); + qemu_mutex_unlock(&hmp.common.mon_lock); =20 out: - monitor_data_destroy(&hmp); + monitor_data_destroy(&hmp.common); return output; } =20 @@ -1349,16 +1356,19 @@ static void hmp_info_sync_profile(Monitor *mon, con= st QDict *qdict) =20 static void hmp_info_history(Monitor *mon, const QDict *qdict) { + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); int i; const char *str; =20 - if (!mon->rs) + if (!hmp_mon->rs) { return; + } i =3D 0; for(;;) { - str =3D readline_get_history(mon->rs, i); - if (!str) + str =3D readline_get_history(hmp_mon->rs, i); + if (!str) { break; + } monitor_printf(mon, "%d: '%s'\n", i, str); i++; } @@ -3056,11 +3066,12 @@ static const mon_cmd_t *search_dispatch_table(const= mon_cmd_t *disp_table, * Do not assume the return value points into @table! It doesn't when * the command is found in a sub-command table. */ -static const mon_cmd_t *monitor_parse_command(Monitor *mon, +static const mon_cmd_t *monitor_parse_command(MonitorHMP *hmp_mon, const char *cmdp_start, const char **cmdp, mon_cmd_t *table) { + Monitor *mon =3D &hmp_mon->common; const char *p; const mon_cmd_t *cmd; char cmdname[256]; @@ -3091,7 +3102,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor= *mon, *cmdp =3D p; /* search sub command */ if (cmd->sub_table !=3D NULL && *p !=3D '\0') { - return monitor_parse_command(mon, cmdp_start, cmdp, cmd->sub_table= ); + return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_t= able); } =20 return cmd; @@ -3468,7 +3479,7 @@ fail: return NULL; } =20 -static void handle_hmp_command(Monitor *mon, const char *cmdline) +static void handle_hmp_command(MonitorHMP *mon, const char *cmdline) { QDict *qdict; const mon_cmd_t *cmd; @@ -3476,26 +3487,26 @@ static void handle_hmp_command(Monitor *mon, const = char *cmdline) =20 trace_handle_hmp_command(mon, cmdline); =20 - cmd =3D monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table); + cmd =3D monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_= table); if (!cmd) { return; } =20 - qdict =3D monitor_parse_arguments(mon, &cmdline, cmd); + qdict =3D monitor_parse_arguments(&mon->common, &cmdline, cmd); if (!qdict) { while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) { cmdline--; } - monitor_printf(mon, "Try \"help %.*s\" for more information\n", + monitor_printf(&mon->common, "Try \"help %.*s\" for more informati= on\n", (int)(cmdline - cmd_start), cmd_start); return; } =20 - cmd->cmd(mon, qdict); + cmd->cmd(&mon->common, qdict); qobject_unref(qdict); } =20 -static void cmd_completion(Monitor *mon, const char *name, const char *lis= t) +static void cmd_completion(MonitorHMP *mon, const char *name, const char *= list) { const char *p, *pstart; char cmd[128]; @@ -3519,7 +3530,7 @@ static void cmd_completion(Monitor *mon, const char *= name, const char *list) } } =20 -static void file_completion(Monitor *mon, const char *input) +static void file_completion(MonitorHMP *mon, const char *input) { DIR *ffs; struct dirent *d; @@ -4008,7 +4019,7 @@ void loadvm_completion(ReadLineState *rs, int nb_args= , const char *str) } } =20 -static void monitor_find_completion_by_table(Monitor *mon, +static void monitor_find_completion_by_table(MonitorHMP *mon, const mon_cmd_t *cmd_table, char **args, int nb_args) @@ -4103,7 +4114,7 @@ static void monitor_find_completion_by_table(Monitor = *mon, static void monitor_find_completion(void *opaque, const char *cmdline) { - Monitor *mon =3D opaque; + MonitorHMP *mon =3D opaque; char *args[MAX_ARGS]; int nb_args, len; =20 @@ -4123,7 +4134,7 @@ static void monitor_find_completion(void *opaque, } =20 /* 2. auto complete according to args */ - monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args); + monitor_find_completion_by_table(mon, mon->common.cmd_table, args, nb_= args); =20 cleanup: free_cmdline_args(args, nb_args); @@ -4334,19 +4345,21 @@ static void monitor_qmp_read(void *opaque, const ui= nt8_t *buf, int size) =20 static void monitor_read(void *opaque, const uint8_t *buf, int size) { + MonitorHMP *mon; Monitor *old_mon =3D cur_mon; int i; =20 cur_mon =3D opaque; + mon =3D container_of(cur_mon, MonitorHMP, common); =20 - if (cur_mon->rs) { + if (mon->rs) { for (i =3D 0; i < size; i++) - readline_handle_byte(cur_mon->rs, buf[i]); + readline_handle_byte(mon->rs, buf[i]); } else { if (size =3D=3D 0 || buf[size - 1] !=3D 0) monitor_printf(cur_mon, "corrupted command\n"); else - handle_hmp_command(cur_mon, (char *)buf); + handle_hmp_command(mon, (char *)buf); } =20 cur_mon =3D old_mon; @@ -4355,11 +4368,11 @@ static void monitor_read(void *opaque, const uint8_= t *buf, int size) static void monitor_command_cb(void *opaque, const char *cmdline, void *readline_opaque) { - Monitor *mon =3D opaque; + MonitorHMP *mon =3D opaque; =20 - monitor_suspend(mon); + monitor_suspend(&mon->common); handle_hmp_command(mon, cmdline); - monitor_resume(mon); + monitor_resume(&mon->common); } =20 int monitor_suspend(Monitor *mon) @@ -4405,8 +4418,9 @@ void monitor_resume(Monitor *mon) } =20 if (!monitor_is_qmp(mon)) { - assert(mon->rs); - readline_show_prompt(mon->rs); + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); + assert(hmp_mon->rs); + readline_show_prompt(hmp_mon->rs); } =20 aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon); @@ -4468,6 +4482,7 @@ static void monitor_qmp_event(void *opaque, int event) static void monitor_event(void *opaque, int event) { Monitor *mon =3D opaque; + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); =20 switch (event) { case CHR_EVENT_MUX_IN: @@ -4475,7 +4490,7 @@ static void monitor_event(void *opaque, int event) mon->mux_out =3D 0; qemu_mutex_unlock(&mon->mon_lock); if (mon->reset_seen) { - readline_restart(mon->rs); + readline_restart(hmp_mon->rs); monitor_resume(mon); monitor_flush(mon); } else { @@ -4502,8 +4517,8 @@ static void monitor_event(void *opaque, int event) monitor_printf(mon, "QEMU %s monitor - type 'help' for more " "information\n", QEMU_VERSION); if (!mon->mux_out) { - readline_restart(mon->rs); - readline_show_prompt(mon->rs); + readline_restart(hmp_mon->rs); + readline_show_prompt(hmp_mon->rs); } mon->reset_seen =3D 1; mon_refcount++; @@ -4564,15 +4579,17 @@ void monitor_init_globals(void) static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque, const char *fmt, ..= .) { + MonitorHMP *mon =3D opaque; va_list ap; va_start(ap, fmt); - monitor_vprintf(opaque, fmt, ap); + monitor_vprintf(&mon->common, fmt, ap); va_end(ap); } =20 static void monitor_readline_flush(void *opaque) { - monitor_flush(opaque); + MonitorHMP *mon =3D opaque; + monitor_flush(&mon->common); } =20 /* @@ -4673,11 +4690,11 @@ static void monitor_init_qmp(Chardev *chr, int flag= s) =20 static void monitor_init_hmp(Chardev *chr, int flags) { - Monitor *mon =3D g_malloc(sizeof(*mon)); + MonitorHMP *mon =3D g_malloc0(sizeof(*mon)); bool use_readline =3D flags & MONITOR_USE_READLINE; =20 - monitor_data_init(mon, flags, false, false); - qemu_chr_fe_init(&mon->chr, chr, &error_abort); + monitor_data_init(&mon->common, flags, false, false); + qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); =20 if (use_readline) { mon->rs =3D readline_init(monitor_readline_printf, @@ -4687,9 +4704,9 @@ static void monitor_init_hmp(Chardev *chr, int flags) monitor_read_command(mon, 0); } =20 - qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read, - monitor_event, NULL, mon, NULL, true); - monitor_list_append(mon); + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_r= ead, + monitor_event, NULL, &mon->common, NULL, true= ); + monitor_list_append(&mon->common); } =20 void monitor_init(Chardev *chr, int flags) --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560443885; cv=none; d=zoho.com; s=zohoarc; b=SIsw8WsYvGucxzneIZJzun0TELiTn/Diio7WKyXiyFe36d82sJR2YmeNA5Qo0ZtCSA/83HC9NQCz55yXvA2tjKqA/6zqFnPbPN4yf6bEE2igDGVhPdjPgzuvIDXokehCIqNJ+wXDDf1Hv884elyp2wHlFX3Rq8zJTDZiNwOFYuY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560443885; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=LtDJx9uMPRVfAkwKh3wVh91Rp780dg8pJ2n2LtjnyEc=; b=Z4uhLPZsy4K/SZ9tqa6VZBumWpA7bMRgR+EvnP7yg9Y1S1Z27ZgNAqJzR6L8T6Pn8tnZY5iXZqFPSAKJX3Pv0Ied+E/u6ZTi9/eC4W+eLddX2Fx45m/oOOboXxnCWBKqIcCmX/3+I1lta4GpNr94y7plsAUC8SD4guUMW608u08= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560443885854677.1477067222235; Thu, 13 Jun 2019 09:38:05 -0700 (PDT) Received: from localhost ([::1]:41578 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSjk-0001O9-Rd for importer@patchew.org; Thu, 13 Jun 2019 12:38:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59824) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRkk-0000Lz-Gz for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkg-0003Gm-Hr for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:00 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54836) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkU-00036Z-Rj; Thu, 13 Jun 2019 11:34:46 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E04C988E5B; Thu, 13 Jun 2019 15:34:40 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5F15260FFE; Thu, 13 Jun 2019 15:34:36 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:55 +0200 Message-Id: <20190613153405.24769-6-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Thu, 13 Jun 2019 15:34:45 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Monitor.cmd_table is initialised to point to mon_cmds and never changed afterwards. We can remove the indirection and just reference mon_cmds directly instead. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- monitor.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index 572449f6db..5eacaa48a6 100644 --- a/monitor.c +++ b/monitor.c @@ -193,7 +193,6 @@ struct Monitor { bool use_io_thread; =20 gchar *mon_cpu_path; - mon_cmd_t *cmd_table; QTAILQ_ENTRY(Monitor) entry; =20 /* @@ -722,8 +721,6 @@ static void monitor_data_init(Monitor *mon, int flags, = bool skip_flush, } qemu_mutex_init(&mon->mon_lock); mon->outbuf =3D qstring_new(); - /* Use *mon_cmds by default. */ - mon->cmd_table =3D mon_cmds; mon->skip_flush =3D skip_flush; mon->use_io_thread =3D use_io_thread; mon->flags =3D flags; @@ -1026,7 +1023,7 @@ static void help_cmd(Monitor *mon, const char *name) } =20 /* 2. dump the contents according to parsed args */ - help_cmd_dump(mon, mon->cmd_table, args, nb_args, 0); + help_cmd_dump(mon, mon_cmds, args, nb_args, 0); =20 free_cmdline_args(args, nb_args); } @@ -3487,7 +3484,7 @@ static void handle_hmp_command(MonitorHMP *mon, const= char *cmdline) =20 trace_handle_hmp_command(mon, cmdline); =20 - cmd =3D monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_= table); + cmd =3D monitor_parse_command(mon, cmdline, &cmdline, mon_cmds); if (!cmd) { return; } @@ -4134,7 +4131,7 @@ static void monitor_find_completion(void *opaque, } =20 /* 2. auto complete according to args */ - monitor_find_completion_by_table(mon, mon->common.cmd_table, args, nb_= args); + monitor_find_completion_by_table(mon, mon_cmds, args, nb_args); =20 cleanup: free_cmdline_args(args, nb_args); --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444412; cv=none; d=zoho.com; s=zohoarc; b=naiwGi2JVv9GbMMEdmXEkfZosU7c8rV+g0MWGDl+oCt72KdttssEKCpoFnFXMF5ZH2vL8zp1oCAHn89W8XJ7bIXl8DTGQgQE0hWTpCZLKZ8cGdsQLkJCS8CC2bWLSNh7NgazaFFsNMvL8tbgZwuMzCqtigTngTDRlCuU80oukVw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444412; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=vOJbY0O5ysrrTaX8u8+/FiZT/WngaR7IRHK5VGh2CXA=; b=N8ja0dPk4xNDUf7gT265J53jGGbxTAQQStoaQMoN1IU5fU9yMKgIeHwQlKostZ7B+Cs7WBh7BnaXgrEnshkHcrItx+uFOqD/0EadflMXxoX3UPKK9EtgPRXMjGiVUTVzZ43wjZPu7OMg2Iazm56axO06BWhMcPjHLxa9jjeYKhg= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560444412250162.3176015748628; Thu, 13 Jun 2019 09:46:52 -0700 (PDT) Received: from localhost ([::1]:41744 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSsA-0001Lu-6k for importer@patchew.org; Thu, 13 Jun 2019 12:46:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59894) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRko-0000Ns-Lp for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkm-0003Nh-Ju for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:06 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52800) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkW-00037v-Uz; Thu, 13 Jun 2019 11:34:50 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BB8A7308626C; Thu, 13 Jun 2019 15:34:43 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 38F496108C; Thu, 13 Jun 2019 15:34:41 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:56 +0200 Message-Id: <20190613153405.24769-7-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.49]); Thu, 13 Jun 2019 15:34:46 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This renames the type for HMP monitor commands and the tables holding the commands to make clear that they are related to HMP and to allow making them public later: * mon_cmd_t -> HMPCommand (fixing use of a reserved name, too) * mon_cmds -> hmp_cmds * info_cmds -> hmp_info_cmds Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- monitor.c | 68 ++++++++++++++++++++++++------------------------- hmp-commands.hx | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/monitor.c b/monitor.c index 5eacaa48a6..006c650761 100644 --- a/monitor.c +++ b/monitor.c @@ -127,7 +127,7 @@ * */ =20 -typedef struct mon_cmd_t { +typedef struct HMPCommand { const char *name; const char *args_type; const char *params; @@ -138,9 +138,9 @@ typedef struct mon_cmd_t { * 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; + struct HMPCommand *sub_table; void (*command_completion)(ReadLineState *rs, int nb_args, const char = *str); -} mon_cmd_t; +} HMPCommand; =20 /* file descriptors passed via SCM_RIGHTS */ typedef struct mon_fd_t mon_fd_t; @@ -277,8 +277,8 @@ static QLIST_HEAD(, MonFdset) mon_fdsets; =20 static int mon_refcount; =20 -static mon_cmd_t mon_cmds[]; -static mon_cmd_t info_cmds[]; +static HMPCommand hmp_cmds[]; +static HMPCommand hmp_info_cmds[]; =20 QmpCommandList qmp_commands, qmp_cap_negotiation_commands; =20 @@ -935,7 +935,7 @@ static int parse_cmdline(const char *cmdline, /* * Can command @cmd be executed in preconfig state? */ -static bool cmd_can_preconfig(const mon_cmd_t *cmd) +static bool cmd_can_preconfig(const HMPCommand *cmd) { if (!cmd->flags) { return false; @@ -945,7 +945,7 @@ static bool cmd_can_preconfig(const mon_cmd_t *cmd) } =20 static void help_cmd_dump_one(Monitor *mon, - const mon_cmd_t *cmd, + const HMPCommand *cmd, char **prefix_args, int prefix_args_nb) { @@ -962,10 +962,10 @@ static void help_cmd_dump_one(Monitor *mon, } =20 /* @args[@arg_index] is the valid command need to find in @cmds */ -static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds, +static void help_cmd_dump(Monitor *mon, const HMPCommand *cmds, char **args, int nb_args, int arg_index) { - const mon_cmd_t *cmd; + const HMPCommand *cmd; size_t i; =20 /* No valid arg need to compare with, dump all in *cmds */ @@ -1023,7 +1023,7 @@ static void help_cmd(Monitor *mon, const char *name) } =20 /* 2. dump the contents according to parsed args */ - help_cmd_dump(mon, mon_cmds, args, nb_args, 0); + help_cmd_dump(mon, hmp_cmds, args, nb_args, 0); =20 free_cmdline_args(args, nb_args); } @@ -2691,13 +2691,13 @@ int monitor_fd_param(Monitor *mon, const char *fdna= me, Error **errp) } =20 /* Please update hmp-commands.hx when adding or changing commands */ -static mon_cmd_t info_cmds[] =3D { +static HMPCommand hmp_info_cmds[] =3D { #include "hmp-commands-info.h" { NULL, NULL, }, }; =20 -/* mon_cmds and info_cmds would be sorted at runtime */ -static mon_cmd_t mon_cmds[] =3D { +/* hmp_cmds and hmp_info_cmds would be sorted at runtime */ +static HMPCommand hmp_cmds[] =3D { #include "hmp-commands.h" { NULL, NULL, }, }; @@ -3039,10 +3039,10 @@ static int is_valid_option(const char *c, const cha= r *typestr) return (typestr !=3D NULL); } =20 -static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table, - const char *cmdname) +static const HMPCommand *search_dispatch_table(const HMPCommand *disp_tabl= e, + const char *cmdname) { - const mon_cmd_t *cmd; + const HMPCommand *cmd; =20 for (cmd =3D disp_table; cmd->name !=3D NULL; cmd++) { if (compare_cmd(cmdname, cmd->name)) { @@ -3063,14 +3063,14 @@ static const mon_cmd_t *search_dispatch_table(const= mon_cmd_t *disp_table, * Do not assume the return value points into @table! It doesn't when * the command is found in a sub-command table. */ -static const mon_cmd_t *monitor_parse_command(MonitorHMP *hmp_mon, - const char *cmdp_start, - const char **cmdp, - mon_cmd_t *table) +static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, + const char *cmdp_start, + const char **cmdp, + HMPCommand *table) { Monitor *mon =3D &hmp_mon->common; const char *p; - const mon_cmd_t *cmd; + const HMPCommand *cmd; char cmdname[256]; =20 /* extract the command name */ @@ -3114,7 +3114,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor= HMP *hmp_mon, =20 static QDict *monitor_parse_arguments(Monitor *mon, const char **endp, - const mon_cmd_t *cmd) + const HMPCommand *cmd) { const char *typestr; char *key; @@ -3479,12 +3479,12 @@ fail: static void handle_hmp_command(MonitorHMP *mon, const char *cmdline) { QDict *qdict; - const mon_cmd_t *cmd; + const HMPCommand *cmd; const char *cmd_start =3D cmdline; =20 trace_handle_hmp_command(mon, cmdline); =20 - cmd =3D monitor_parse_command(mon, cmdline, &cmdline, mon_cmds); + cmd =3D monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds); if (!cmd) { return; } @@ -4017,14 +4017,14 @@ void loadvm_completion(ReadLineState *rs, int nb_ar= gs, const char *str) } =20 static void monitor_find_completion_by_table(MonitorHMP *mon, - const mon_cmd_t *cmd_table, + const HMPCommand *cmd_table, char **args, int nb_args) { const char *cmdname; int i; const char *ptype, *old_ptype, *str, *name; - const mon_cmd_t *cmd; + const HMPCommand *cmd; BlockBackend *blk =3D NULL; =20 if (nb_args <=3D 1) { @@ -4131,7 +4131,7 @@ static void monitor_find_completion(void *opaque, } =20 /* 2. auto complete according to args */ - monitor_find_completion_by_table(mon, mon_cmds, args, nb_args); + monitor_find_completion_by_table(mon, hmp_cmds, args, nb_args); =20 cleanup: free_cmdline_args(args, nb_args); @@ -4531,20 +4531,20 @@ static void monitor_event(void *opaque, int event) static int compare_mon_cmd(const void *a, const void *b) { - return strcmp(((const mon_cmd_t *)a)->name, - ((const mon_cmd_t *)b)->name); + return strcmp(((const HMPCommand *)a)->name, + ((const HMPCommand *)b)->name); } =20 static void sortcmdlist(void) { int array_num; - int elem_size =3D sizeof(mon_cmd_t); + int elem_size =3D sizeof(HMPCommand); =20 - array_num =3D sizeof(mon_cmds)/elem_size-1; - qsort((void *)mon_cmds, array_num, elem_size, compare_mon_cmd); + array_num =3D sizeof(hmp_cmds)/elem_size-1; + qsort((void *)hmp_cmds, array_num, elem_size, compare_mon_cmd); =20 - array_num =3D sizeof(info_cmds)/elem_size-1; - qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd); + array_num =3D sizeof(hmp_info_cmds)/elem_size-1; + qsort((void *)hmp_info_cmds, array_num, elem_size, compare_mon_cmd); } =20 static void monitor_iothread_init(void) diff --git a/hmp-commands.hx b/hmp-commands.hx index a2c3ffc218..8b7aec3e8d 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1934,7 +1934,7 @@ ETEXI .params =3D "[subcommand]", .help =3D "show various information about the system state", .cmd =3D hmp_info_help, - .sub_table =3D info_cmds, + .sub_table =3D hmp_info_cmds, .flags =3D "p", }, =20 --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560445085; cv=none; d=zoho.com; s=zohoarc; b=f3lNiItBPnQLe3X4L4+jNtMvC9cmNc+mDr2ANohUCCVBBlmdkrVr+HN+ZIJ+qd+jMCn1GaKnROiccoPzng1qUG5YkwdaYhQere/brHkRIpje0sqWqq/y+pplXQrg2++UoxBZuu3qrpXM8RRmpP6vRJ47/aeWzWdoCtzJR8YD0sA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560445085; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=OISqOZKWurWic0U/hCmn4Wgnvn58hu7pZY+VJ+4rCDo=; b=Uc2NfW4SAZV4dRxFyNAh133ly8db72nVAgEI8EerUFO2Q3MKtPyNywdLG46yv9ix8EhGCwLtYki4veUI1cc8R474aFhIY1PLxGQytAbvwZmAx0oxlBqXltvMJYmf1WFtK9YsiSadFkuXEFoxe/3xFYh7lpgVTQRJqhCAAV6EjiA= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560445085891332.1127710460107; Thu, 13 Jun 2019 09:58:05 -0700 (PDT) Received: from localhost ([::1]:41882 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbT33-0003j0-QV for importer@patchew.org; Thu, 13 Jun 2019 12:58:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59985) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRkt-0000WE-8G for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkr-0003Tx-Eo for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:11 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56786) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkk-0003F8-Df; Thu, 13 Jun 2019 11:35:04 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8DEFE6EB81; Thu, 13 Jun 2019 15:34:47 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 137B260C44; Thu, 13 Jun 2019 15:34:43 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:57 +0200 Message-Id: <20190613153405.24769-8-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Thu, 13 Jun 2019 15:34:52 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Create a new monitor/ subdirectory and move monitor.c there. As the plan is to move the monitor core into separate files, use the chance to rename it to misc.c. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- docs/devel/writing-qmp-commands.txt | 2 +- monitor.c =3D> monitor/misc.c | 2 +- MAINTAINERS | 4 ++-- Makefile.objs | 1 + Makefile.target | 3 ++- monitor/Makefile.objs | 1 + monitor/trace-events | 11 +++++++++++ trace-events | 10 ---------- 8 files changed, 19 insertions(+), 15 deletions(-) rename monitor.c =3D> monitor/misc.c (99%) create mode 100644 monitor/Makefile.objs create mode 100644 monitor/trace-events diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-c= ommands.txt index 9dfc62bf5a..cc6ecd6d5d 100644 --- a/docs/devel/writing-qmp-commands.txt +++ b/docs/devel/writing-qmp-commands.txt @@ -470,7 +470,7 @@ it's good practice to always check for errors. =20 Another important detail is that HMP's "info" commands don't go into the hmp-commands.hx. Instead, they go into the info_cmds[] table, which is def= ined -in the monitor.c file. The entry for the "info alarmclock" follows: +in the monitor/misc.c file. The entry for the "info alarmclock" follows: =20 { .name =3D "alarmclock", diff --git a/monitor.c b/monitor/misc.c similarity index 99% rename from monitor.c rename to monitor/misc.c index 006c650761..e5db04265d 100644 --- a/monitor.c +++ b/monitor/misc.c @@ -64,7 +64,7 @@ #include "qapi/qmp/json-parser.h" #include "qapi/qmp/qlist.h" #include "qom/object_interfaces.h" -#include "trace-root.h" +#include "trace.h" #include "trace/control.h" #include "monitor/hmp-target.h" #ifdef CONFIG_TRACE_SIMPLE diff --git a/MAINTAINERS b/MAINTAINERS index 588c8d947a..231964c1da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1916,7 +1916,7 @@ F: qapi/run-state.json Human Monitor (HMP) M: Dr. David Alan Gilbert S: Maintained -F: monitor.c +F: monitor/misc.c F: hmp.[ch] F: hmp-commands*.hx F: include/monitor/hmp-target.h @@ -2038,7 +2038,7 @@ QMP M: Markus Armbruster S: Supported F: qmp.c -F: monitor.c +F: monitor/misc.c F: docs/devel/*qmp-* F: docs/interop/*qmp-* F: scripts/qmp/ diff --git a/Makefile.objs b/Makefile.objs index c8337fa34b..dd39a70b48 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -130,6 +130,7 @@ trace-events-subdirs =3D trace-events-subdirs +=3D accel/kvm trace-events-subdirs +=3D accel/tcg trace-events-subdirs +=3D crypto +trace-events-subdirs +=3D monitor ifeq ($(CONFIG_USER_ONLY),y) trace-events-subdirs +=3D linux-user endif diff --git a/Makefile.target b/Makefile.target index ecd856e3a3..72c267f7dc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -148,9 +148,10 @@ endif #CONFIG_BSD_USER ######################################################### # System emulator target ifdef CONFIG_SOFTMMU -obj-y +=3D arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o +obj-y +=3D arch_init.o cpus.o gdbstub.o balloon.o ioport.o numa.o obj-y +=3D qtest.o obj-y +=3D hw/ +obj-y +=3D monitor/ obj-y +=3D qapi/ obj-y +=3D memory.o obj-y +=3D memory_mapping.o diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs new file mode 100644 index 0000000000..e783b0616b --- /dev/null +++ b/monitor/Makefile.objs @@ -0,0 +1 @@ +obj-y +=3D misc.o diff --git a/monitor/trace-events b/monitor/trace-events new file mode 100644 index 0000000000..abfdf20b14 --- /dev/null +++ b/monitor/trace-events @@ -0,0 +1,11 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# misc.c +monitor_protocol_event_handler(uint32_t event, void *qdict) "event=3D%d da= ta=3D%p" +monitor_protocol_event_emit(uint32_t event, void *data) "event=3D%d data= =3D%p" +monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "= event=3D%d data=3D%p rate=3D%" PRId64 +handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" +handle_qmp_command(void *mon, const char *req) "mon %p req: %s" +monitor_suspend(void *ptr, int cnt) "mon %p: %d" +monitor_qmp_cmd_in_band(const char *id) "%s" +monitor_qmp_cmd_out_of_band(const char *id) "%s" diff --git a/trace-events b/trace-events index 844ee58dd9..aeea3c2bdb 100644 --- a/trace-events +++ b/trace-events @@ -41,16 +41,6 @@ system_wakeup_request(int reason) "reason=3D%d" qemu_system_shutdown_request(int reason) "reason=3D%d" qemu_system_powerdown_request(void) "" =20 -# monitor.c -monitor_protocol_event_handler(uint32_t event, void *qdict) "event=3D%d da= ta=3D%p" -monitor_protocol_event_emit(uint32_t event, void *data) "event=3D%d data= =3D%p" -monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "= event=3D%d data=3D%p rate=3D%" PRId64 -handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" -handle_qmp_command(void *mon, const char *req) "mon %p req: %s" -monitor_suspend(void *ptr, int cnt) "mon %p: %d" -monitor_qmp_cmd_in_band(const char *id) "%s" -monitor_qmp_cmd_out_of_band(const char *id) "%s" - # dma-helpers.c dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=3D%p bs= =3D%p offset=3D%" PRId64 " to_dev=3D%d" dma_aio_cancel(void *dbs) "dbs=3D%p" --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444784; cv=none; d=zoho.com; s=zohoarc; b=Wu2XjLP2r+Gf2QbMUIlEsyE5B8uHK+xixMnRemPDq8b+CWC/lYQH4+DCNy+dnWo036qp7eiilrTRCdb9WaChMWnFpUmbc8RjP8ZjKfQzde9JdcbxeCliQ99spHS/Nd+6WwEMa+W+bpbu2drsX85geQZX4vn8FsYRVsLb1j7aMHQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444784; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=gxRZQ433thUhHYSjjz7QOVEyO6jBrffkL7Pt+PjAWts=; b=eB6nms7uFSVdunpV1mqyOBc00x5vUHafIOiX8FBse4pAYj/74XXNl6pHNhGJsbzDfoQCsOZQpnDZ11ZJyHZ9j+yJJc1bJtB9Y0c3km3I4f8TV9p4sSe5wdgOutg69CbVDi2JzBIjUQplYiVUy7I3FG72v0Yu35Xc6IvT0jmga08= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560444784038174.93199081327487; Thu, 13 Jun 2019 09:53:04 -0700 (PDT) Received: from localhost ([::1]:41788 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSy9-0006RS-Sg for importer@patchew.org; Thu, 13 Jun 2019 12:52:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60010) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRku-0000aP-NQ for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRkt-0003XJ-60 for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:12 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33028) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRko-0003J3-JP; Thu, 13 Jun 2019 11:35:06 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0DA4822387D; Thu, 13 Jun 2019 15:34:52 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id D9DD26108C; Thu, 13 Jun 2019 15:34:47 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:58 +0200 Message-Id: <20190613153405.24769-9-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Thu, 13 Jun 2019 15:34:56 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 08/15] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Now that we have a monitor/ subdirectory, let's move hmp.c and qmp.c from the root directory there. As they contain implementations of monitor commands, rename them to {hmp,qmp}-cmds.c, so that {hmp,qmp}.c are free for the HMP and QMP infrastructure. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- docs/devel/writing-qmp-commands.txt | 9 +++++---- hmp.c =3D> monitor/hmp-cmds.c | 2 +- qmp.c =3D> monitor/qmp-cmds.c | 2 +- MAINTAINERS | 5 +++-- Makefile.objs | 2 +- monitor/Makefile.objs | 1 + 6 files changed, 12 insertions(+), 9 deletions(-) rename hmp.c =3D> monitor/hmp-cmds.c (99%) rename qmp.c =3D> monitor/qmp-cmds.c (99%) diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-c= ommands.txt index cc6ecd6d5d..46a6c48683 100644 --- a/docs/devel/writing-qmp-commands.txt +++ b/docs/devel/writing-qmp-commands.txt @@ -20,7 +20,7 @@ new QMP command. =20 2. Write the QMP command itself, which is a regular C function. Preferably, the command should be exported by some QEMU subsystem. But it can also = be - added to the qmp.c file + added to the monitor/qmp-cmds.c file =20 3. At this point the command can be tested under the QMP protocol =20 @@ -101,7 +101,8 @@ protocol data. =20 The next step is to write the "hello-world" implementation. As explained earlier, it's preferable for commands to live in QEMU subsystems. But -"hello-world" doesn't pertain to any, so we put its implementation in qmp.= c: +"hello-world" doesn't pertain to any, so we put its implementation in +monitor/qmp-cmds.c: =20 void qmp_hello_world(Error **errp) { @@ -146,7 +147,7 @@ for mandatory arguments). Finally, 'str' is the argumen= t's type, which stands for "string". The QAPI also supports integers, booleans, enumeratio= ns and user defined types. =20 -Now, let's update our C implementation in qmp.c: +Now, let's update our C implementation in monitor/qmp-cmds.c: =20 void qmp_hello_world(bool has_message, const char *message, Error **errp) { @@ -267,7 +268,7 @@ monitor (HMP). =20 With the introduction of the QAPI, HMP commands make QMP calls. Most of the time HMP commands are simple wrappers. All HMP commands implementation exi= st in -the hmp.c file. +the monitor/hmp-cmds.c file. =20 Here's the implementation of the "hello-world" HMP command: =20 diff --git a/hmp.c b/monitor/hmp-cmds.c similarity index 99% rename from hmp.c rename to monitor/hmp-cmds.c index 99414cd39c..712737cd18 100644 --- a/hmp.c +++ b/monitor/hmp-cmds.c @@ -1,5 +1,5 @@ /* - * Human Monitor Interface + * Human Monitor Interface commands * * Copyright IBM, Corp. 2011 * diff --git a/qmp.c b/monitor/qmp-cmds.c similarity index 99% rename from qmp.c rename to monitor/qmp-cmds.c index 6797568444..f1b1e4f08b 100644 --- a/qmp.c +++ b/monitor/qmp-cmds.c @@ -1,5 +1,5 @@ /* - * QEMU Management Protocol + * QEMU Management Protocol commands * * Copyright IBM, Corp. 2011 * diff --git a/MAINTAINERS b/MAINTAINERS index 231964c1da..884f4b16bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1917,7 +1917,8 @@ Human Monitor (HMP) M: Dr. David Alan Gilbert S: Maintained F: monitor/misc.c -F: hmp.[ch] +F: monitor/hmp* +F: hmp.h F: hmp-commands*.hx F: include/monitor/hmp-target.h F: tests/test-hmp.c @@ -2037,7 +2038,7 @@ F: tests/check-qom-proplist.c QMP M: Markus Armbruster S: Supported -F: qmp.c +F: monitor/qmp* F: monitor/misc.c F: docs/devel/*qmp-* F: docs/interop/*qmp-* diff --git a/Makefile.objs b/Makefile.objs index dd39a70b48..9495fcbc7e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -83,8 +83,8 @@ common-obj-$(CONFIG_FDT) +=3D device_tree.o ###################################################################### # qapi =20 -common-obj-y +=3D qmp.o hmp.o common-obj-y +=3D qapi/ +common-obj-y +=3D monitor/ endif =20 ####################################################################### diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs index e783b0616b..a7170af6e1 100644 --- a/monitor/Makefile.objs +++ b/monitor/Makefile.objs @@ -1 +1,2 @@ obj-y +=3D misc.o +common-obj-y +=3D qmp-cmds.o hmp-cmds.o --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560445030; cv=none; d=zoho.com; s=zohoarc; b=C7tGQ0xEMXi/HDoZjwkr7Y63PGhyzrwKxr/8Zba27WKsUIAPXeuJtp1DOKLVzFRiEcYSTiYNmZVDt7R5+bscsbIp3VzsMUMHrlh05zIvePmE1gL7CjaA1LINaq7UfIwDPZXJWCpYrH0haeOqEuOAj1ECuODPFwYtBAGDqIaMSo0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560445030; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=3nKXXyFL5RaTO3/X5dg/xMymE/lk8CpgtJIFNV5BOnI=; b=E2TCjNMk2uTxSZx5p3A05qb+DiCPUAE1JtGadFWLhAnzmyWq5rhn12ndo073boQeWALMJ8/Y974d21A4JHcZM6lFXfGsqyToKIvemnJ4JJqcnYZvlWjBc0kmbUURvRNKpw6xqvXDQXfaaqrqx4mJUojGcZcHpvelI2LaEYbZD0o= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560445030692564.3025459607403; Thu, 13 Jun 2019 09:57:10 -0700 (PDT) Received: from localhost ([::1]:41868 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbT2B-0002ZN-Gh for importer@patchew.org; Thu, 13 Jun 2019 12:57:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60015) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRkv-0000bj-6K for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRks-0003Ws-Sw for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:13 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39552) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRkl-0003J4-AT; Thu, 13 Jun 2019 11:35:04 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DE3588F927; Thu, 13 Jun 2019 15:34:54 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5964C60FFE; Thu, 13 Jun 2019 15:34:52 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:33:59 +0200 Message-Id: <20190613153405.24769-10-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 13 Jun 2019 15:35:01 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Before we can split monitor/misc.c, we need to create a header file that contains the common definitions that will be used by multiple source files. For a start, add the type definitions for Monitor, MonitorHMP and MonitorQMP and their dependencies. We'll add functions as needed when splitting monitor/misc.c. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- monitor/monitor-internal.h | 148 +++++++++++++++++++++++++++++++++++++ monitor/misc.c | 110 +-------------------------- MAINTAINERS | 2 + 3 files changed, 151 insertions(+), 109 deletions(-) create mode 100644 monitor/monitor-internal.h diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h new file mode 100644 index 0000000000..17a632b0ad --- /dev/null +++ b/monitor/monitor-internal.h @@ -0,0 +1,148 @@ +/* + * QEMU monitor + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included= in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#ifndef MONITOR_INT_H +#define MONITOR_INT_H + +#include "monitor/monitor.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/json-parser.h" +#include "qapi/qmp/dispatch.h" +#include "qapi/qapi-types-misc.h" + +#include "qemu/readline.h" +#include "chardev/char-fe.h" +#include "sysemu/iothread.h" + +/* + * Supported types: + * + * 'F' filename + * 'B' block device name + * 's' string (accept optional quote) + * 'S' it just appends the rest of the string (accept optional qu= ote) + * 'O' option string of the form NAME=3DVALUE,... + * parsed according to QemuOptsList given by its name + * Example: 'device:O' uses qemu_device_opts. + * Restriction: only lists with empty desc are supported + * TODO lift the restriction + * 'i' 32 bit integer + * 'l' target long (32 or 64 bit) + * 'M' Non-negative target long (32 or 64 bit), in user mode the + * value is multiplied by 2^20 (think Mebibyte) + * 'o' octets (aka bytes) + * user mode accepts an optional E, e, P, p, T, t, G, g, M, m, + * K, k suffix, which multiplies the value by 2^60 for suffix= es E + * and e, 2^50 for suffixes P and p, 2^40 for suffixes T and = t, + * 2^30 for suffixes G and g, 2^20 for M and m, 2^10 for K an= d k + * 'T' double + * user mode accepts an optional ms, us, ns suffix, + * which divides the value by 1e3, 1e6, 1e9, respectively + * '/' optional gdb-like print format (like "/10x") + * + * '?' optional type (for all types, except '/') + * '.' other form of optional type (for 'i' and 'l') + * 'b' boolean + * user mode accepts "on" or "off" + * '-' optional parameter (eg. '-f') + * + */ + +typedef struct HMPCommand { + const char *name; + const char *args_type; + const char *params; + const char *help; + const char *flags; /* p=3Dpreconfig */ + void (*cmd)(Monitor *mon, const QDict *qdict); + /* + * @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 HMPCommand *sub_table; + void (*command_completion)(ReadLineState *rs, int nb_args, const char = *str); +} HMPCommand; + +struct Monitor { + CharBackend chr; + int reset_seen; + int flags; + int suspend_cnt; /* Needs to be accessed atomically */ + bool skip_flush; + bool use_io_thread; + + gchar *mon_cpu_path; + QTAILQ_ENTRY(Monitor) entry; + + /* + * The per-monitor lock. We can't access guest memory when holding + * the lock. + */ + QemuMutex mon_lock; + + /* + * Members that are protected by the per-monitor lock + */ + QLIST_HEAD(, mon_fd_t) fds; + QString *outbuf; + guint out_watch; + /* Read under either BQL or mon_lock, written with BQL+mon_lock. */ + int mux_out; +}; + +struct MonitorHMP { + Monitor common; + /* + * State used only in the thread "owning" the monitor. + * If @use_io_thread, this is @mon_iothread. (This does not actually h= appen + * in the current state of the code.) + * Else, it's the main thread. + * These members can be safely accessed without locks. + */ + ReadLineState *rs; +}; + +typedef struct { + Monitor common; + JSONMessageParser parser; + /* + * When a client connects, we're in capabilities negotiation mode. + * @commands is &qmp_cap_negotiation_commands then. When command + * qmp_capabilities succeeds, we go into command mode, and + * @command becomes &qmp_commands. + */ + QmpCommandList *commands; + bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ + bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ + /* + * Protects qmp request/response queue. + * Take monitor_lock first when you need both. + */ + QemuMutex qmp_queue_lock; + /* Input queue that holds all the parsed QMP requests */ + GQueue *qmp_requests; +} MonitorQMP; + +#endif diff --git a/monitor/misc.c b/monitor/misc.c index e5db04265d..6aa4a21676 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -23,6 +23,7 @@ */ =20 #include "qemu/osdep.h" +#include "monitor-internal.h" #include "qemu/units.h" #include #include "cpu.h" @@ -93,55 +94,6 @@ #include "hw/s390x/storage-attributes.h" #endif =20 -/* - * Supported types: - * - * 'F' filename - * 'B' block device name - * 's' string (accept optional quote) - * 'S' it just appends the rest of the string (accept optional qu= ote) - * 'O' option string of the form NAME=3DVALUE,... - * parsed according to QemuOptsList given by its name - * Example: 'device:O' uses qemu_device_opts. - * Restriction: only lists with empty desc are supported - * TODO lift the restriction - * 'i' 32 bit integer - * 'l' target long (32 or 64 bit) - * 'M' Non-negative target long (32 or 64 bit), in user mode the - * value is multiplied by 2^20 (think Mebibyte) - * 'o' octets (aka bytes) - * user mode accepts an optional E, e, P, p, T, t, G, g, M, m, - * K, k suffix, which multiplies the value by 2^60 for suffix= es E - * and e, 2^50 for suffixes P and p, 2^40 for suffixes T and = t, - * 2^30 for suffixes G and g, 2^20 for M and m, 2^10 for K an= d k - * 'T' double - * user mode accepts an optional ms, us, ns suffix, - * which divides the value by 1e3, 1e6, 1e9, respectively - * '/' optional gdb-like print format (like "/10x") - * - * '?' optional type (for all types, except '/') - * '.' other form of optional type (for 'i' and 'l') - * 'b' boolean - * user mode accepts "on" or "off" - * '-' optional parameter (eg. '-f') - * - */ - -typedef struct HMPCommand { - const char *name; - const char *args_type; - const char *params; - const char *help; - const char *flags; /* p=3Dpreconfig */ - void (*cmd)(Monitor *mon, const QDict *qdict); - /* @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 HMPCommand *sub_table; - void (*command_completion)(ReadLineState *rs, int nb_args, const char = *str); -} HMPCommand; - /* file descriptors passed via SCM_RIGHTS */ typedef struct mon_fd_t mon_fd_t; struct mon_fd_t { @@ -184,66 +136,6 @@ typedef struct { int64_t rate; /* Minimum time (in ns) between two events */ } MonitorQAPIEventConf; =20 -struct Monitor { - CharBackend chr; - int reset_seen; - int flags; - int suspend_cnt; /* Needs to be accessed atomically */ - bool skip_flush; - bool use_io_thread; - - gchar *mon_cpu_path; - QTAILQ_ENTRY(Monitor) entry; - - /* - * The per-monitor lock. We can't access guest memory when holding - * the lock. - */ - QemuMutex mon_lock; - - /* - * Members that are protected by the per-monitor lock - */ - QLIST_HEAD(, mon_fd_t) fds; - QString *outbuf; - guint out_watch; - /* Read under either BQL or mon_lock, written with BQL+mon_lock. */ - int mux_out; -}; - -struct MonitorHMP { - Monitor common; - /* - * State used only in the thread "owning" the monitor. - * If @use_io_thread, this is @mon_iothread. (This does not actually h= appen - * in the current state of the code.) - * Else, it's the main thread. - * These members can be safely accessed without locks. - */ - ReadLineState *rs; -}; - -typedef struct { - Monitor common; - JSONMessageParser parser; - /* - * When a client connects, we're in capabilities negotiation mode. - * @commands is &qmp_cap_negotiation_commands then. When command - * qmp_capabilities succeeds, we go into command mode, and - * @command becomes &qmp_commands. - */ - QmpCommandList *commands; - bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */ - bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */ - /* - * Protects qmp request/response queue. - * Take monitor_lock first when you need both. - */ - QemuMutex qmp_queue_lock; - /* Input queue that holds all the parsed QMP requests */ - GQueue *qmp_requests; -} MonitorQMP; - /* Shared monitor I/O thread */ IOThread *mon_iothread; =20 diff --git a/MAINTAINERS b/MAINTAINERS index 884f4b16bb..ebb839d305 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1916,6 +1916,7 @@ F: qapi/run-state.json Human Monitor (HMP) M: Dr. David Alan Gilbert S: Maintained +F: monitor/monitor-internal.h F: monitor/misc.c F: monitor/hmp* F: hmp.h @@ -2038,6 +2039,7 @@ F: tests/check-qom-proplist.c QMP M: Markus Armbruster S: Supported +F: monitor/monitor-internal.h F: monitor/qmp* F: monitor/misc.c F: docs/devel/*qmp-* --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560443276; cv=none; d=zoho.com; s=zohoarc; b=OnzYeDbNFQw6M+eBOXqNj3sOpvz/ngMmf8F0aGxkXDEndzhlqOYzZD5bnwcusSq9xSeMmxf6AWbPm8BbnF+ltkl7UkXt3g+/5QWb0+unF1hf1bx6bVlekIEgXNSgiJBH8/kd1OO7Jg5kAUsO25263TSxiLn7IKt/W2vd9I2fZVA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560443276; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=RsDkSq14RMyToJvAgPzQ3kN0sn0gpZVk05pKMGrHvh4=; b=HmWIOJ9rO1/lyClP9flzd3tPsJXSyHsbM7L1DZHga+RRXYm+i/QsD760bDxjuL7/OPHKXmPmKuv3jwPfM7Suu9JQDklEPKNQgbnJbjYd9v4u19rErwzu/QrfDcvLHsT8bUMBerlBBRgoFsuIsSn/Etl1jZPgM4CkwoOl4NcUNcs= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560443276256367.5802742515323; Thu, 13 Jun 2019 09:27:56 -0700 (PDT) Received: from localhost ([::1]:41502 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSZv-0001XU-2Z for importer@patchew.org; Thu, 13 Jun 2019 12:27:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60115) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRl7-0000rq-EU for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRl3-0003h9-3D for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:25 -0400 Received: from mx1.redhat.com ([209.132.183.28]:52278) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRku-0003Ya-KO; Thu, 13 Jun 2019 11:35:12 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CF3253007400; Thu, 13 Jun 2019 15:35:06 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3170160FBD; Thu, 13 Jun 2019 15:34:55 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:34:00 +0200 Message-Id: <20190613153405.24769-11-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Thu, 13 Jun 2019 15:35:11 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Move QMP infrastructure from monitor/misc.c to monitor/qmp.c. This is code that can be shared for all targets, so compile it only once. The amount of function and particularly extern variables in monitor_int.h is probably a bit larger than it needs to be, but this way no non-trivial code modifications are needed. The interfaces between QMP and the monitor core can be cleaned up later. Signed-off-by: Kevin Wolf Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster --- monitor/monitor-internal.h | 29 +++ monitor/misc.c | 397 +----------------------------------- monitor/qmp.c | 405 +++++++++++++++++++++++++++++++++++++ Makefile.objs | 1 + monitor/Makefile.objs | 1 + monitor/trace-events | 4 +- 6 files changed, 448 insertions(+), 389 deletions(-) create mode 100644 monitor/qmp.c diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 17a632b0ad..0a26f702dd 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -145,4 +145,33 @@ typedef struct { GQueue *qmp_requests; } MonitorQMP; =20 +/** + * Is @mon a QMP monitor? + */ +static inline bool monitor_is_qmp(const Monitor *mon) +{ + return (mon->flags & MONITOR_USE_CONTROL); +} + +typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList; +extern IOThread *mon_iothread; +extern QEMUBH *qmp_dispatcher_bh; +extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands; +extern QemuMutex monitor_lock; +extern MonitorList mon_list; +extern int mon_refcount; + +void monitor_init_qmp(Chardev *chr, int flags); + +int monitor_puts(Monitor *mon, const char *str); +void monitor_data_init(Monitor *mon, int flags, bool skip_flush, + bool use_io_thread); +int monitor_can_read(void *opaque); +void monitor_list_append(Monitor *mon); +void monitor_fdsets_cleanup(void); + +void qmp_send_response(MonitorQMP *mon, const QDict *rsp); +void monitor_data_destroy_qmp(MonitorQMP *mon); +void monitor_qmp_bh_dispatcher(void *data); + #endif diff --git a/monitor/misc.c b/monitor/misc.c index 6aa4a21676..368b8297d4 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -142,51 +142,29 @@ IOThread *mon_iothread; /* Bottom half to dispatch the requests received from I/O thread */ QEMUBH *qmp_dispatcher_bh; =20 -struct QMPRequest { - /* Owner of the request */ - MonitorQMP *mon; - /* - * Request object to be handled or Error to be reported - * (exactly one of them is non-null) - */ - QObject *req; - Error *err; -}; -typedef struct QMPRequest QMPRequest; - /* QMP checker flags */ #define QMP_ACCEPT_UNKNOWNS 1 =20 /* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */ -static QemuMutex monitor_lock; +QemuMutex monitor_lock; static GHashTable *monitor_qapi_event_state; -static QTAILQ_HEAD(, Monitor) mon_list; +MonitorList mon_list; static bool monitor_destroyed; =20 /* Protects mon_fdsets */ static QemuMutex mon_fdsets_lock; static QLIST_HEAD(, MonFdset) mon_fdsets; =20 -static int mon_refcount; +int mon_refcount; =20 static HMPCommand hmp_cmds[]; static HMPCommand hmp_info_cmds[]; =20 -QmpCommandList qmp_commands, qmp_cap_negotiation_commands; - __thread Monitor *cur_mon; =20 static void monitor_command_cb(void *opaque, const char *cmdline, void *readline_opaque); =20 -/** - * Is @mon a QMP monitor? - */ -static inline bool monitor_is_qmp(const Monitor *mon) -{ - return (mon->flags & MONITOR_USE_CONTROL); -} - /** * Is @mon is using readline? * Note: not all HMP monitors use readline, e.g., gdbserver has a @@ -245,28 +223,6 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFun= c *readline_func, } } =20 -static void qmp_request_free(QMPRequest *req) -{ - qobject_unref(req->req); - error_free(req->err); - g_free(req); -} - -/* Caller must hold mon->qmp.qmp_queue_lock */ -static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon) -{ - while (!g_queue_is_empty(mon->qmp_requests)) { - qmp_request_free(g_queue_pop_head(mon->qmp_requests)); - } -} - -static void monitor_qmp_cleanup_queues(MonitorQMP *mon) -{ - qemu_mutex_lock(&mon->qmp_queue_lock); - monitor_qmp_cleanup_req_queue_locked(mon); - qemu_mutex_unlock(&mon->qmp_queue_lock); -} - =20 static void monitor_flush_locked(Monitor *mon); =20 @@ -326,7 +282,7 @@ void monitor_flush(Monitor *mon) } =20 /* flush at every end of line */ -static int monitor_puts(Monitor *mon, const char *str) +int monitor_puts(Monitor *mon, const char *str) { int i; char c; @@ -376,21 +332,6 @@ int monitor_printf(Monitor *mon, const char *fmt, ...) return ret; } =20 -static void qmp_send_response(MonitorQMP *mon, const QDict *rsp) -{ - const QObject *data =3D QOBJECT(rsp); - QString *json; - - json =3D mon->common.flags & MONITOR_USE_PRETTY ? - qobject_to_json_pretty(data) : qobject_to_json(data); - assert(json !=3D NULL); - - qstring_append_chr(json, '\n'); - monitor_puts(&mon->common, qstring_get_str(json)); - - qobject_unref(json); -} - static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] =3D { /* Limit guest-triggerable events to 1 per second */ [QAPI_EVENT_RTC_CHANGE] =3D { 1000 * SCALE_MS }, @@ -605,8 +546,8 @@ static void handle_hmp_command(MonitorHMP *mon, const c= har *cmdline); =20 static void monitor_iothread_init(void); =20 -static void monitor_data_init(Monitor *mon, int flags, bool skip_flush, - bool use_io_thread) +void monitor_data_init(Monitor *mon, int flags, bool skip_flush, + bool use_io_thread) { if (use_io_thread && !mon_iothread) { monitor_iothread_init(); @@ -618,14 +559,6 @@ static void monitor_data_init(Monitor *mon, int flags,= bool skip_flush, mon->flags =3D flags; } =20 -static void monitor_data_destroy_qmp(MonitorQMP *mon) -{ - json_message_parser_destroy(&mon->parser); - qemu_mutex_destroy(&mon->qmp_queue_lock); - monitor_qmp_cleanup_req_queue_locked(mon); - g_queue_free(mon->qmp_requests); -} - static void monitor_data_destroy(Monitor *mon) { g_free(mon->mon_cpu_path); @@ -1064,18 +997,6 @@ static void monitor_init_qmp_commands(void) qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG= ); } =20 -static bool qmp_oob_enabled(MonitorQMP *mon) -{ - return mon->capab[QMP_CAPABILITY_OOB]; -} - -static void monitor_qmp_caps_reset(MonitorQMP *mon) -{ - memset(mon->capab_offered, 0, sizeof(mon->capab_offered)); - memset(mon->capab, 0, sizeof(mon->capab)); - mon->capab_offered[QMP_CAPABILITY_OOB] =3D mon->common.use_io_thread; -} - /* * Accept QMP capabilities in @list for @mon. * On success, set mon->qmp.capab[], and return true. @@ -2251,7 +2172,7 @@ static void monitor_fdset_cleanup(MonFdset *mon_fdset) } } =20 -static void monitor_fdsets_cleanup(void) +void monitor_fdsets_cleanup(void) { MonFdset *mon_fdset; MonFdset *mon_fdset_next; @@ -4029,209 +3950,13 @@ cleanup: free_cmdline_args(args, nb_args); } =20 -static int monitor_can_read(void *opaque) +int monitor_can_read(void *opaque) { Monitor *mon =3D opaque; =20 return !atomic_mb_read(&mon->suspend_cnt); } =20 -/* - * Emit QMP response @rsp with ID @id to @mon. - * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. - * Nothing is emitted then. - */ -static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) -{ - if (rsp) { - qmp_send_response(mon, rsp); - } -} - -static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) -{ - Monitor *old_mon; - QDict *rsp; - QDict *error; - - old_mon =3D cur_mon; - cur_mon =3D &mon->common; - - rsp =3D qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon)); - - cur_mon =3D old_mon; - - if (mon->commands =3D=3D &qmp_cap_negotiation_commands) { - error =3D qdict_get_qdict(rsp, "error"); - if (error - && !g_strcmp0(qdict_get_try_str(error, "class"), - QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { - /* Provide a more useful error message */ - qdict_del(error, "desc"); - qdict_put_str(error, "desc", "Expecting capabilities negotiati= on" - " with 'qmp_capabilities'"); - } - } - - monitor_qmp_respond(mon, rsp); - qobject_unref(rsp); -} - -/* - * Pop a QMP request from a monitor request queue. - * Return the request, or NULL all request queues are empty. - * We are using round-robin fashion to pop the request, to avoid - * processing commands only on a very busy monitor. To achieve that, - * when we process one request on a specific monitor, we put that - * monitor to the end of mon_list queue. - * - * Note: if the function returned with non-NULL, then the caller will - * be with qmp_mon->qmp_queue_lock held, and the caller is responsible - * to release it. - */ -static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void) -{ - QMPRequest *req_obj =3D NULL; - Monitor *mon; - MonitorQMP *qmp_mon; - - qemu_mutex_lock(&monitor_lock); - - QTAILQ_FOREACH(mon, &mon_list, entry) { - if (!monitor_is_qmp(mon)) { - continue; - } - - qmp_mon =3D container_of(mon, MonitorQMP, common); - qemu_mutex_lock(&qmp_mon->qmp_queue_lock); - req_obj =3D g_queue_pop_head(qmp_mon->qmp_requests); - if (req_obj) { - /* With the lock of corresponding queue held */ - break; - } - qemu_mutex_unlock(&qmp_mon->qmp_queue_lock); - } - - if (req_obj) { - /* - * We found one request on the monitor. Degrade this monitor's - * priority to lowest by re-inserting it to end of queue. - */ - QTAILQ_REMOVE(&mon_list, mon, entry); - QTAILQ_INSERT_TAIL(&mon_list, mon, entry); - } - - qemu_mutex_unlock(&monitor_lock); - - return req_obj; -} - -static void monitor_qmp_bh_dispatcher(void *data) -{ - QMPRequest *req_obj =3D monitor_qmp_requests_pop_any_with_lock(); - QDict *rsp; - bool need_resume; - MonitorQMP *mon; - - if (!req_obj) { - return; - } - - mon =3D req_obj->mon; - /* qmp_oob_enabled() might change after "qmp_capabilities" */ - need_resume =3D !qmp_oob_enabled(mon) || - mon->qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1; - qemu_mutex_unlock(&mon->qmp_queue_lock); - if (req_obj->req) { - QDict *qdict =3D qobject_to(QDict, req_obj->req); - QObject *id =3D qdict ? qdict_get(qdict, "id") : NULL; - trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: ""); - monitor_qmp_dispatch(mon, req_obj->req); - } else { - assert(req_obj->err); - rsp =3D qmp_error_response(req_obj->err); - req_obj->err =3D NULL; - monitor_qmp_respond(mon, rsp); - qobject_unref(rsp); - } - - if (need_resume) { - /* Pairs with the monitor_suspend() in handle_qmp_command() */ - monitor_resume(&mon->common); - } - qmp_request_free(req_obj); - - /* Reschedule instead of looping so the main loop stays responsive */ - qemu_bh_schedule(qmp_dispatcher_bh); -} - -static void handle_qmp_command(void *opaque, QObject *req, Error *err) -{ - MonitorQMP *mon =3D opaque; - QObject *id =3D NULL; - QDict *qdict; - QMPRequest *req_obj; - - assert(!req !=3D !err); - - qdict =3D qobject_to(QDict, req); - if (qdict) { - id =3D qdict_get(qdict, "id"); - } /* else will fail qmp_dispatch() */ - - if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { - QString *req_json =3D qobject_to_json(req); - trace_handle_qmp_command(mon, qstring_get_str(req_json)); - qobject_unref(req_json); - } - - if (qdict && qmp_is_oob(qdict)) { - /* OOB commands are executed immediately */ - trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: ""); - monitor_qmp_dispatch(mon, req); - qobject_unref(req); - return; - } - - req_obj =3D g_new0(QMPRequest, 1); - req_obj->mon =3D mon; - req_obj->req =3D req; - req_obj->err =3D err; - - /* Protect qmp_requests and fetching its length. */ - qemu_mutex_lock(&mon->qmp_queue_lock); - - /* - * Suspend the monitor when we can't queue more requests after - * this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume - * it. Note that when OOB is disabled, we queue at most one - * command, for backward compatibility. - */ - if (!qmp_oob_enabled(mon) || - mon->qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1) { - monitor_suspend(&mon->common); - } - - /* - * Put the request to the end of queue so that requests will be - * handled in time order. Ownership for req_obj, req, - * etc. will be delivered to the handler side. - */ - assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); - g_queue_push_tail(mon->qmp_requests, req_obj); - qemu_mutex_unlock(&mon->qmp_queue_lock); - - /* Kick the dispatcher routine */ - qemu_bh_schedule(qmp_dispatcher_bh); -} - -static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) -{ - MonitorQMP *mon =3D opaque; - - json_message_parser_feed(&mon->parser, (const char *) buf, size); -} - static void monitor_read(void *opaque, const uint8_t *buf, int size) { MonitorHMP *mon; @@ -4318,56 +4043,6 @@ void monitor_resume(Monitor *mon) trace_monitor_suspend(mon, -1); } =20 -static QDict *qmp_greeting(MonitorQMP *mon) -{ - QList *cap_list =3D qlist_new(); - QObject *ver =3D NULL; - QMPCapability cap; - - qmp_marshal_query_version(NULL, &ver, NULL); - - for (cap =3D 0; cap < QMP_CAPABILITY__MAX; cap++) { - if (mon->capab_offered[cap]) { - qlist_append_str(cap_list, QMPCapability_str(cap)); - } - } - - return qdict_from_jsonf_nofail( - "{'QMP': {'version': %p, 'capabilities': %p}}", - ver, cap_list); -} - -static void monitor_qmp_event(void *opaque, int event) -{ - QDict *data; - MonitorQMP *mon =3D opaque; - - switch (event) { - case CHR_EVENT_OPENED: - mon->commands =3D &qmp_cap_negotiation_commands; - monitor_qmp_caps_reset(mon); - data =3D qmp_greeting(mon); - qmp_send_response(mon, data); - qobject_unref(data); - mon_refcount++; - break; - case CHR_EVENT_CLOSED: - /* - * Note: this is only useful when the output of the chardev - * backend is still open. For example, when the backend is - * stdio, it's possible that stdout is still open when stdin - * is closed. - */ - monitor_qmp_cleanup_queues(mon); - json_message_parser_destroy(&mon->parser); - json_message_parser_init(&mon->parser, handle_qmp_command, - mon, NULL); - mon_refcount--; - monitor_fdsets_cleanup(); - break; - } -} - static void monitor_event(void *opaque, int event) { Monitor *mon =3D opaque; @@ -4503,7 +4178,7 @@ int error_vprintf_unless_qmp(const char *fmt, va_list= ap) return -1; } =20 -static void monitor_list_append(Monitor *mon) +void monitor_list_append(Monitor *mon) { qemu_mutex_lock(&monitor_lock); /* @@ -4523,60 +4198,6 @@ static void monitor_list_append(Monitor *mon) } } =20 -static void monitor_qmp_setup_handlers_bh(void *opaque) -{ - MonitorQMP *mon =3D opaque; - GMainContext *context; - - assert(mon->common.use_io_thread); - context =3D iothread_get_g_main_context(mon_iothread); - assert(context); - qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, - monitor_qmp_read, monitor_qmp_event, - NULL, &mon->common, context, true); - monitor_list_append(&mon->common); -} - -static void monitor_init_qmp(Chardev *chr, int flags) -{ - MonitorQMP *mon =3D g_malloc0(sizeof(*mon)); - - /* Only HMP supports readline */ - assert(!(flags & MONITOR_USE_READLINE)); - - /* Note: we run QMP monitor in I/O thread when @chr supports that */ - monitor_data_init(&mon->common, flags, false, - qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); - - qemu_mutex_init(&mon->qmp_queue_lock); - mon->qmp_requests =3D g_queue_new(); - - qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); - qemu_chr_fe_set_echo(&mon->common.chr, true); - - json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); - if (mon->common.use_io_thread) { - /* - * Make sure the old iowatch is gone. It's possible when - * e.g. the chardev is in client mode, with wait=3Don. - */ - remove_fd_in_watch(chr); - /* - * We can't call qemu_chr_fe_set_handlers() directly here - * since chardev might be running in the monitor I/O - * thread. Schedule a bottom half. - */ - aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), - monitor_qmp_setup_handlers_bh, mon); - /* The bottom half will add @mon to @mon_list */ - } else { - qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, - monitor_qmp_read, monitor_qmp_event, - NULL, &mon->common, NULL, true); - monitor_list_append(&mon->common); - } -} - static void monitor_init_hmp(Chardev *chr, int flags) { MonitorHMP *mon =3D g_malloc0(sizeof(*mon)); diff --git a/monitor/qmp.c b/monitor/qmp.c new file mode 100644 index 0000000000..31fbcd59f7 --- /dev/null +++ b/monitor/qmp.c @@ -0,0 +1,405 @@ +/* + * QEMU monitor + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included= in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#include "chardev/char-io.h" +#include "monitor-internal.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc.h" +#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qlist.h" +#include "trace.h" + +struct QMPRequest { + /* Owner of the request */ + MonitorQMP *mon; + /* + * Request object to be handled or Error to be reported + * (exactly one of them is non-null) + */ + QObject *req; + Error *err; +}; +typedef struct QMPRequest QMPRequest; + +QmpCommandList qmp_commands, qmp_cap_negotiation_commands; + +static bool qmp_oob_enabled(MonitorQMP *mon) +{ + return mon->capab[QMP_CAPABILITY_OOB]; +} + +static void monitor_qmp_caps_reset(MonitorQMP *mon) +{ + memset(mon->capab_offered, 0, sizeof(mon->capab_offered)); + memset(mon->capab, 0, sizeof(mon->capab)); + mon->capab_offered[QMP_CAPABILITY_OOB] =3D mon->common.use_io_thread; +} + +static void qmp_request_free(QMPRequest *req) +{ + qobject_unref(req->req); + error_free(req->err); + g_free(req); +} + +/* Caller must hold mon->qmp.qmp_queue_lock */ +static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon) +{ + while (!g_queue_is_empty(mon->qmp_requests)) { + qmp_request_free(g_queue_pop_head(mon->qmp_requests)); + } +} + +static void monitor_qmp_cleanup_queues(MonitorQMP *mon) +{ + qemu_mutex_lock(&mon->qmp_queue_lock); + monitor_qmp_cleanup_req_queue_locked(mon); + qemu_mutex_unlock(&mon->qmp_queue_lock); +} + +void qmp_send_response(MonitorQMP *mon, const QDict *rsp) +{ + const QObject *data =3D QOBJECT(rsp); + QString *json; + + json =3D mon->common.flags & MONITOR_USE_PRETTY ? + qobject_to_json_pretty(data) : qobject_to_json(data); + assert(json !=3D NULL); + + qstring_append_chr(json, '\n'); + monitor_puts(&mon->common, qstring_get_str(json)); + + qobject_unref(json); +} + +/* + * Emit QMP response @rsp with ID @id to @mon. + * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. + * Nothing is emitted then. + */ +static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) +{ + if (rsp) { + qmp_send_response(mon, rsp); + } +} + +static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) +{ + Monitor *old_mon; + QDict *rsp; + QDict *error; + + old_mon =3D cur_mon; + cur_mon =3D &mon->common; + + rsp =3D qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon)); + + cur_mon =3D old_mon; + + if (mon->commands =3D=3D &qmp_cap_negotiation_commands) { + error =3D qdict_get_qdict(rsp, "error"); + if (error + && !g_strcmp0(qdict_get_try_str(error, "class"), + QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { + /* Provide a more useful error message */ + qdict_del(error, "desc"); + qdict_put_str(error, "desc", "Expecting capabilities negotiati= on" + " with 'qmp_capabilities'"); + } + } + + monitor_qmp_respond(mon, rsp); + qobject_unref(rsp); +} + +/* + * Pop a QMP request from a monitor request queue. + * Return the request, or NULL all request queues are empty. + * We are using round-robin fashion to pop the request, to avoid + * processing commands only on a very busy monitor. To achieve that, + * when we process one request on a specific monitor, we put that + * monitor to the end of mon_list queue. + * + * Note: if the function returned with non-NULL, then the caller will + * be with qmp_mon->qmp_queue_lock held, and the caller is responsible + * to release it. + */ +static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void) +{ + QMPRequest *req_obj =3D NULL; + Monitor *mon; + MonitorQMP *qmp_mon; + + qemu_mutex_lock(&monitor_lock); + + QTAILQ_FOREACH(mon, &mon_list, entry) { + if (!monitor_is_qmp(mon)) { + continue; + } + + qmp_mon =3D container_of(mon, MonitorQMP, common); + qemu_mutex_lock(&qmp_mon->qmp_queue_lock); + req_obj =3D g_queue_pop_head(qmp_mon->qmp_requests); + if (req_obj) { + /* With the lock of corresponding queue held */ + break; + } + qemu_mutex_unlock(&qmp_mon->qmp_queue_lock); + } + + if (req_obj) { + /* + * We found one request on the monitor. Degrade this monitor's + * priority to lowest by re-inserting it to end of queue. + */ + QTAILQ_REMOVE(&mon_list, mon, entry); + QTAILQ_INSERT_TAIL(&mon_list, mon, entry); + } + + qemu_mutex_unlock(&monitor_lock); + + return req_obj; +} + +void monitor_qmp_bh_dispatcher(void *data) +{ + QMPRequest *req_obj =3D monitor_qmp_requests_pop_any_with_lock(); + QDict *rsp; + bool need_resume; + MonitorQMP *mon; + + if (!req_obj) { + return; + } + + mon =3D req_obj->mon; + /* qmp_oob_enabled() might change after "qmp_capabilities" */ + need_resume =3D !qmp_oob_enabled(mon) || + mon->qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1; + qemu_mutex_unlock(&mon->qmp_queue_lock); + if (req_obj->req) { + QDict *qdict =3D qobject_to(QDict, req_obj->req); + QObject *id =3D qdict ? qdict_get(qdict, "id") : NULL; + trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: ""); + monitor_qmp_dispatch(mon, req_obj->req); + } else { + assert(req_obj->err); + rsp =3D qmp_error_response(req_obj->err); + req_obj->err =3D NULL; + monitor_qmp_respond(mon, rsp); + qobject_unref(rsp); + } + + if (need_resume) { + /* Pairs with the monitor_suspend() in handle_qmp_command() */ + monitor_resume(&mon->common); + } + qmp_request_free(req_obj); + + /* Reschedule instead of looping so the main loop stays responsive */ + qemu_bh_schedule(qmp_dispatcher_bh); +} + +static void handle_qmp_command(void *opaque, QObject *req, Error *err) +{ + MonitorQMP *mon =3D opaque; + QObject *id =3D NULL; + QDict *qdict; + QMPRequest *req_obj; + + assert(!req !=3D !err); + + qdict =3D qobject_to(QDict, req); + if (qdict) { + id =3D qdict_get(qdict, "id"); + } /* else will fail qmp_dispatch() */ + + if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { + QString *req_json =3D qobject_to_json(req); + trace_handle_qmp_command(mon, qstring_get_str(req_json)); + qobject_unref(req_json); + } + + if (qdict && qmp_is_oob(qdict)) { + /* OOB commands are executed immediately */ + trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: ""); + monitor_qmp_dispatch(mon, req); + qobject_unref(req); + return; + } + + req_obj =3D g_new0(QMPRequest, 1); + req_obj->mon =3D mon; + req_obj->req =3D req; + req_obj->err =3D err; + + /* Protect qmp_requests and fetching its length. */ + qemu_mutex_lock(&mon->qmp_queue_lock); + + /* + * Suspend the monitor when we can't queue more requests after + * this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume + * it. Note that when OOB is disabled, we queue at most one + * command, for backward compatibility. + */ + if (!qmp_oob_enabled(mon) || + mon->qmp_requests->length =3D=3D QMP_REQ_QUEUE_LEN_MAX - 1) { + monitor_suspend(&mon->common); + } + + /* + * Put the request to the end of queue so that requests will be + * handled in time order. Ownership for req_obj, req, + * etc. will be delivered to the handler side. + */ + assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); + g_queue_push_tail(mon->qmp_requests, req_obj); + qemu_mutex_unlock(&mon->qmp_queue_lock); + + /* Kick the dispatcher routine */ + qemu_bh_schedule(qmp_dispatcher_bh); +} + +static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) +{ + MonitorQMP *mon =3D opaque; + + json_message_parser_feed(&mon->parser, (const char *) buf, size); +} + +static QDict *qmp_greeting(MonitorQMP *mon) +{ + QList *cap_list =3D qlist_new(); + QObject *ver =3D NULL; + QMPCapability cap; + + qmp_marshal_query_version(NULL, &ver, NULL); + + for (cap =3D 0; cap < QMP_CAPABILITY__MAX; cap++) { + if (mon->capab_offered[cap]) { + qlist_append_str(cap_list, QMPCapability_str(cap)); + } + } + + return qdict_from_jsonf_nofail( + "{'QMP': {'version': %p, 'capabilities': %p}}", + ver, cap_list); +} + +static void monitor_qmp_event(void *opaque, int event) +{ + QDict *data; + MonitorQMP *mon =3D opaque; + + switch (event) { + case CHR_EVENT_OPENED: + mon->commands =3D &qmp_cap_negotiation_commands; + monitor_qmp_caps_reset(mon); + data =3D qmp_greeting(mon); + qmp_send_response(mon, data); + qobject_unref(data); + mon_refcount++; + break; + case CHR_EVENT_CLOSED: + /* + * Note: this is only useful when the output of the chardev + * backend is still open. For example, when the backend is + * stdio, it's possible that stdout is still open when stdin + * is closed. + */ + monitor_qmp_cleanup_queues(mon); + json_message_parser_destroy(&mon->parser); + json_message_parser_init(&mon->parser, handle_qmp_command, + mon, NULL); + mon_refcount--; + monitor_fdsets_cleanup(); + break; + } +} + +void monitor_data_destroy_qmp(MonitorQMP *mon) +{ + json_message_parser_destroy(&mon->parser); + qemu_mutex_destroy(&mon->qmp_queue_lock); + monitor_qmp_cleanup_req_queue_locked(mon); + g_queue_free(mon->qmp_requests); +} + +static void monitor_qmp_setup_handlers_bh(void *opaque) +{ + MonitorQMP *mon =3D opaque; + GMainContext *context; + + assert(mon->common.use_io_thread); + context =3D iothread_get_g_main_context(mon_iothread); + assert(context); + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, + monitor_qmp_read, monitor_qmp_event, + NULL, &mon->common, context, true); + monitor_list_append(&mon->common); +} + +void monitor_init_qmp(Chardev *chr, int flags) +{ + MonitorQMP *mon =3D g_malloc0(sizeof(*mon)); + + /* Only HMP supports readline */ + assert(!(flags & MONITOR_USE_READLINE)); + + /* Note: we run QMP monitor in I/O thread when @chr supports that */ + monitor_data_init(&mon->common, flags, false, + qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); + + qemu_mutex_init(&mon->qmp_queue_lock); + mon->qmp_requests =3D g_queue_new(); + + qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); + qemu_chr_fe_set_echo(&mon->common.chr, true); + + json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); + if (mon->common.use_io_thread) { + /* + * Make sure the old iowatch is gone. It's possible when + * e.g. the chardev is in client mode, with wait=3Don. + */ + remove_fd_in_watch(chr); + /* + * We can't call qemu_chr_fe_set_handlers() directly here + * since chardev might be running in the monitor I/O + * thread. Schedule a bottom half. + */ + aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), + monitor_qmp_setup_handlers_bh, mon); + /* The bottom half will add @mon to @mon_list */ + } else { + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, + monitor_qmp_read, monitor_qmp_event, + NULL, &mon->common, NULL, true); + monitor_list_append(&mon->common); + } +} diff --git a/Makefile.objs b/Makefile.objs index 9495fcbc7e..658cfc9d9f 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -46,6 +46,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y =3D blockdev.o blockdev-nbd.o block/ common-obj-y +=3D bootdevice.o iothread.o common-obj-y +=3D job-qmp.o +common-obj-y +=3D monitor/ common-obj-y +=3D net/ common-obj-y +=3D qdev-monitor.o device-hotplug.o common-obj-$(CONFIG_WIN32) +=3D os-win32.o diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs index a7170af6e1..1037c09ff8 100644 --- a/monitor/Makefile.objs +++ b/monitor/Makefile.objs @@ -1,2 +1,3 @@ obj-y +=3D misc.o +common-obj-y +=3D qmp.o common-obj-y +=3D qmp-cmds.o hmp-cmds.o diff --git a/monitor/trace-events b/monitor/trace-events index abfdf20b14..a06dde3fd3 100644 --- a/monitor/trace-events +++ b/monitor/trace-events @@ -5,7 +5,9 @@ monitor_protocol_event_handler(uint32_t event, void *qdict)= "event=3D%d data=3D%p" monitor_protocol_event_emit(uint32_t event, void *data) "event=3D%d data= =3D%p" monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "= event=3D%d data=3D%p rate=3D%" PRId64 handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" -handle_qmp_command(void *mon, const char *req) "mon %p req: %s" monitor_suspend(void *ptr, int cnt) "mon %p: %d" + +# qmp.c monitor_qmp_cmd_in_band(const char *id) "%s" monitor_qmp_cmd_out_of_band(const char *id) "%s" +handle_qmp_command(void *mon, const char *req) "mon %p req: %s" --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560445691; cv=none; d=zoho.com; s=zohoarc; b=OutgWYspGhXcmA6nKR8WBFnoFwI2AVWwhLTbkPS9N2G8iMP8lYpkM0SifBYG6kbm/UtihGuwuMg8lJamyXSkCQzy+Ei3awMys9QqB9OtD4OMu0lOcpucYu3F85nMdYp+la51VJMiadXDUNPuRTuNRoKUNxEfUNwwVvYl0q72Js0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560445691; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=IfOuvnE15yuCf5bRJTyvCEYdLHTJ2txoULgBDSNm2Pk=; b=aT6ZRfK/uZcRnsg3gcGBPlxdxVlShBmY0knKEJVvcfpfmPUtMHxDu5lDY5udnwVSSABMwvtgz6+E8S81UH3hrhd2GjEzVfqR6q1xRv9rHp0RgKTnWynZG1X48oOfyA285w3YkDteR3fWFBO2XFZ3UEmMSvIzn7/5kyfn47BJ2so= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560445691161328.9265439251777; Thu, 13 Jun 2019 10:08:11 -0700 (PDT) Received: from localhost ([::1]:42014 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbTCl-0003Eu-5P for importer@patchew.org; Thu, 13 Jun 2019 13:08:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60376) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRlp-00013r-H9 for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:36:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRlh-0004BT-JU for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:36:09 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39876) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRl7-0003jq-Cy; Thu, 13 Jun 2019 11:35:25 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 31A67B5C0B; Thu, 13 Jun 2019 15:35:19 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 272BC60C7F; Thu, 13 Jun 2019 15:35:06 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:34:01 +0200 Message-Id: <20190613153405.24769-12-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 13 Jun 2019 15:35:24 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Move HMP infrastructure from monitor/misc.c to monitor/hmp.c. This is code that can be shared for all targets, so compile it only once. The amount of function and particularly extern variables in monitor_int.h is probably a bit larger than it needs to be, but this way no non-trivial code modifications are needed. The interfaces between HMP and the monitor core can be cleaned up later. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- monitor/monitor-internal.h | 10 + monitor/hmp.c | 1415 ++++++++++++++++++++++++++++++++++++ monitor/misc.c | 1360 +--------------------------------- monitor/Makefile.objs | 2 +- monitor/trace-events | 4 +- 5 files changed, 1443 insertions(+), 1348 deletions(-) create mode 100644 monitor/hmp.c diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 0a26f702dd..ad3b7ee7ec 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -26,6 +26,8 @@ #define MONITOR_INT_H =20 #include "monitor/monitor.h" +#include "qemu/cutils.h" + #include "qapi/qmp/qdict.h" #include "qapi/qmp/json-parser.h" #include "qapi/qmp/dispatch.h" @@ -161,7 +163,10 @@ extern QemuMutex monitor_lock; extern MonitorList mon_list; extern int mon_refcount; =20 +extern HMPCommand hmp_cmds[]; + void monitor_init_qmp(Chardev *chr, int flags); +void monitor_init_hmp(Chardev *chr, int flags); =20 int monitor_puts(Monitor *mon, const char *str); void monitor_data_init(Monitor *mon, int flags, bool skip_flush, @@ -174,4 +179,9 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rs= p); void monitor_data_destroy_qmp(MonitorQMP *mon); void monitor_qmp_bh_dispatcher(void *data); =20 +int get_monitor_def(int64_t *pval, const char *name); +void help_cmd(Monitor *mon, const char *name); +void handle_hmp_command(MonitorHMP *mon, const char *cmdline); +int hmp_compare_cmd(const char *name, const char *list); + #endif diff --git a/monitor/hmp.c b/monitor/hmp.c new file mode 100644 index 0000000000..3621b195ed --- /dev/null +++ b/monitor/hmp.c @@ -0,0 +1,1415 @@ +/* + * QEMU monitor + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included= in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "monitor-internal.h" + +#include "qapi/error.h" +#include "qapi/qmp/qnum.h" + +#include "qemu/config-file.h" +#include "qemu/ctype.h" +#include "qemu/log.h" +#include "qemu/option.h" +#include "qemu/units.h" +#include "sysemu/block-backend.h" +#include "sysemu/sysemu.h" + +#include "trace.h" + +static void monitor_command_cb(void *opaque, const char *cmdline, + void *readline_opaque) +{ + MonitorHMP *mon =3D opaque; + + monitor_suspend(&mon->common); + handle_hmp_command(mon, cmdline); + monitor_resume(&mon->common); +} + +void monitor_read_command(MonitorHMP *mon, int show_prompt) +{ + if (!mon->rs) { + return; + } + + readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL); + if (show_prompt) { + readline_show_prompt(mon->rs); + } +} + +int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, + void *opaque) +{ + if (mon->rs) { + readline_start(mon->rs, "Password: ", 1, readline_func, opaque); + /* prompt is printed on return from the command handler */ + return 0; + } else { + monitor_printf(&mon->common, + "terminal does not support password prompting\n"); + return -ENOTTY; + } +} + +static int get_str(char *buf, int buf_size, const char **pp) +{ + const char *p; + char *q; + int c; + + q =3D buf; + p =3D *pp; + while (qemu_isspace(*p)) { + p++; + } + if (*p =3D=3D '\0') { + fail: + *q =3D '\0'; + *pp =3D p; + return -1; + } + if (*p =3D=3D '\"') { + p++; + while (*p !=3D '\0' && *p !=3D '\"') { + if (*p =3D=3D '\\') { + p++; + c =3D *p++; + switch (c) { + case 'n': + c =3D '\n'; + break; + case 'r': + c =3D '\r'; + break; + case '\\': + case '\'': + case '\"': + break; + default: + printf("unsupported escape code: '\\%c'\n", c); + goto fail; + } + if ((q - buf) < buf_size - 1) { + *q++ =3D c; + } + } else { + if ((q - buf) < buf_size - 1) { + *q++ =3D *p; + } + p++; + } + } + if (*p !=3D '\"') { + printf("unterminated string\n"); + goto fail; + } + p++; + } else { + while (*p !=3D '\0' && !qemu_isspace(*p)) { + if ((q - buf) < buf_size - 1) { + *q++ =3D *p; + } + p++; + } + } + *q =3D '\0'; + *pp =3D p; + return 0; +} + +#define MAX_ARGS 16 + +static void free_cmdline_args(char **args, int nb_args) +{ + int i; + + assert(nb_args <=3D MAX_ARGS); + + for (i =3D 0; i < nb_args; i++) { + g_free(args[i]); + } + +} + +/* + * Parse the command line to get valid args. + * @cmdline: command line to be parsed. + * @pnb_args: location to store the number of args, must NOT be NULL. + * @args: location to store the args, which should be freed by caller, must + * NOT be NULL. + * + * Returns 0 on success, negative on failure. + * + * NOTE: this parser is an approximate form of the real command parser. Nu= mber + * of args have a limit of MAX_ARGS. If cmdline contains more, it wi= ll + * return with failure. + */ +static int parse_cmdline(const char *cmdline, + int *pnb_args, char **args) +{ + const char *p; + int nb_args, ret; + char buf[1024]; + + p =3D cmdline; + nb_args =3D 0; + for (;;) { + while (qemu_isspace(*p)) { + p++; + } + if (*p =3D=3D '\0') { + break; + } + if (nb_args >=3D MAX_ARGS) { + goto fail; + } + ret =3D get_str(buf, sizeof(buf), &p); + if (ret < 0) { + goto fail; + } + args[nb_args] =3D g_strdup(buf); + nb_args++; + } + *pnb_args =3D nb_args; + return 0; + + fail: + free_cmdline_args(args, nb_args); + return -1; +} + +/* + * Can command @cmd be executed in preconfig state? + */ +static bool cmd_can_preconfig(const HMPCommand *cmd) +{ + if (!cmd->flags) { + return false; + } + + return strchr(cmd->flags, 'p'); +} + +static void help_cmd_dump_one(Monitor *mon, + const HMPCommand *cmd, + char **prefix_args, + int prefix_args_nb) +{ + int i; + + if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) { + return; + } + + for (i =3D 0; i < prefix_args_nb; i++) { + monitor_printf(mon, "%s ", prefix_args[i]); + } + monitor_printf(mon, "%s %s -- %s\n", cmd->name, cmd->params, cmd->help= ); +} + +/* @args[@arg_index] is the valid command need to find in @cmds */ +static void help_cmd_dump(Monitor *mon, const HMPCommand *cmds, + char **args, int nb_args, int arg_index) +{ + const HMPCommand *cmd; + size_t i; + + /* No valid arg need to compare with, dump all in *cmds */ + if (arg_index >=3D nb_args) { + for (cmd =3D cmds; cmd->name !=3D NULL; cmd++) { + help_cmd_dump_one(mon, cmd, args, arg_index); + } + return; + } + + /* Find one entry to dump */ + for (cmd =3D cmds; cmd->name !=3D NULL; cmd++) { + if (hmp_compare_cmd(args[arg_index], cmd->name) && + ((!runstate_check(RUN_STATE_PRECONFIG) || + cmd_can_preconfig(cmd)))) { + if (cmd->sub_table) { + /* continue with next arg */ + help_cmd_dump(mon, cmd->sub_table, + args, nb_args, arg_index + 1); + } else { + help_cmd_dump_one(mon, cmd, args, arg_index); + } + return; + } + } + + /* Command not found */ + monitor_printf(mon, "unknown command: '"); + for (i =3D 0; i <=3D arg_index; i++) { + monitor_printf(mon, "%s%s", args[i], i =3D=3D arg_index ? "'\n" : = " "); + } +} + +void help_cmd(Monitor *mon, const char *name) +{ + char *args[MAX_ARGS]; + int nb_args =3D 0; + + /* 1. parse user input */ + if (name) { + /* special case for log, directly dump and return */ + if (!strcmp(name, "log")) { + const QEMULogItem *item; + monitor_printf(mon, "Log items (comma separated):\n"); + monitor_printf(mon, "%-10s %s\n", "none", "remove all logs"); + for (item =3D qemu_log_items; item->mask !=3D 0; item++) { + monitor_printf(mon, "%-10s %s\n", item->name, item->help); + } + return; + } + + if (parse_cmdline(name, &nb_args, args) < 0) { + return; + } + } + + /* 2. dump the contents according to parsed args */ + help_cmd_dump(mon, hmp_cmds, args, nb_args, 0); + + free_cmdline_args(args, nb_args); +} + +/*******************************************************************/ + +static const char *pch; +static sigjmp_buf expr_env; + +static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN +expr_error(Monitor *mon, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + monitor_vprintf(mon, fmt, ap); + monitor_printf(mon, "\n"); + va_end(ap); + siglongjmp(expr_env, 1); +} + +static void next(void) +{ + if (*pch !=3D '\0') { + pch++; + while (qemu_isspace(*pch)) { + pch++; + } + } +} + +static int64_t expr_sum(Monitor *mon); + +static int64_t expr_unary(Monitor *mon) +{ + int64_t n; + char *p; + int ret; + + switch (*pch) { + case '+': + next(); + n =3D expr_unary(mon); + break; + case '-': + next(); + n =3D -expr_unary(mon); + break; + case '~': + next(); + n =3D ~expr_unary(mon); + break; + case '(': + next(); + n =3D expr_sum(mon); + if (*pch !=3D ')') { + expr_error(mon, "')' expected"); + } + next(); + break; + case '\'': + pch++; + if (*pch =3D=3D '\0') { + expr_error(mon, "character constant expected"); + } + n =3D *pch; + pch++; + if (*pch !=3D '\'') { + expr_error(mon, "missing terminating \' character"); + } + next(); + break; + case '$': + { + char buf[128], *q; + int64_t reg =3D 0; + + pch++; + q =3D buf; + while ((*pch >=3D 'a' && *pch <=3D 'z') || + (*pch >=3D 'A' && *pch <=3D 'Z') || + (*pch >=3D '0' && *pch <=3D '9') || + *pch =3D=3D '_' || *pch =3D=3D '.') { + if ((q - buf) < sizeof(buf) - 1) { + *q++ =3D *pch; + } + pch++; + } + while (qemu_isspace(*pch)) { + pch++; + } + *q =3D 0; + ret =3D get_monitor_def(®, buf); + if (ret < 0) { + expr_error(mon, "unknown register"); + } + n =3D reg; + } + break; + case '\0': + expr_error(mon, "unexpected end of expression"); + n =3D 0; + break; + default: + errno =3D 0; + n =3D strtoull(pch, &p, 0); + if (errno =3D=3D ERANGE) { + expr_error(mon, "number too large"); + } + if (pch =3D=3D p) { + expr_error(mon, "invalid char '%c' in expression", *p); + } + pch =3D p; + while (qemu_isspace(*pch)) { + pch++; + } + break; + } + return n; +} + +static int64_t expr_prod(Monitor *mon) +{ + int64_t val, val2; + int op; + + val =3D expr_unary(mon); + for (;;) { + op =3D *pch; + if (op !=3D '*' && op !=3D '/' && op !=3D '%') { + break; + } + next(); + val2 =3D expr_unary(mon); + switch (op) { + default: + case '*': + val *=3D val2; + break; + case '/': + case '%': + if (val2 =3D=3D 0) { + expr_error(mon, "division by zero"); + } + if (op =3D=3D '/') { + val /=3D val2; + } else { + val %=3D val2; + } + break; + } + } + return val; +} + +static int64_t expr_logic(Monitor *mon) +{ + int64_t val, val2; + int op; + + val =3D expr_prod(mon); + for (;;) { + op =3D *pch; + if (op !=3D '&' && op !=3D '|' && op !=3D '^') { + break; + } + next(); + val2 =3D expr_prod(mon); + switch (op) { + default: + case '&': + val &=3D val2; + break; + case '|': + val |=3D val2; + break; + case '^': + val ^=3D val2; + break; + } + } + return val; +} + +static int64_t expr_sum(Monitor *mon) +{ + int64_t val, val2; + int op; + + val =3D expr_logic(mon); + for (;;) { + op =3D *pch; + if (op !=3D '+' && op !=3D '-') { + break; + } + next(); + val2 =3D expr_logic(mon); + if (op =3D=3D '+') { + val +=3D val2; + } else { + val -=3D val2; + } + } + return val; +} + +static int get_expr(Monitor *mon, int64_t *pval, const char **pp) +{ + pch =3D *pp; + if (sigsetjmp(expr_env, 0)) { + *pp =3D pch; + return -1; + } + while (qemu_isspace(*pch)) { + pch++; + } + *pval =3D expr_sum(mon); + *pp =3D pch; + return 0; +} + +static int get_double(Monitor *mon, double *pval, const char **pp) +{ + const char *p =3D *pp; + char *tailp; + double d; + + d =3D strtod(p, &tailp); + if (tailp =3D=3D p) { + monitor_printf(mon, "Number expected\n"); + return -1; + } + if (d !=3D d || d - d !=3D 0) { + /* NaN or infinity */ + monitor_printf(mon, "Bad number\n"); + return -1; + } + *pval =3D d; + *pp =3D tailp; + return 0; +} + +/* + * Store the command-name in cmdname, and return a pointer to + * the remaining of the command string. + */ +static const char *get_command_name(const char *cmdline, + char *cmdname, size_t nlen) +{ + size_t len; + const char *p, *pstart; + + p =3D cmdline; + while (qemu_isspace(*p)) { + p++; + } + if (*p =3D=3D '\0') { + return NULL; + } + pstart =3D p; + while (*p !=3D '\0' && *p !=3D '/' && !qemu_isspace(*p)) { + p++; + } + len =3D p - pstart; + if (len > nlen - 1) { + len =3D nlen - 1; + } + memcpy(cmdname, pstart, len); + cmdname[len] =3D '\0'; + return p; +} + +/** + * Read key of 'type' into 'key' and return the current + * 'type' pointer. + */ +static char *key_get_info(const char *type, char **key) +{ + size_t len; + char *p, *str; + + if (*type =3D=3D ',') { + type++; + } + + p =3D strchr(type, ':'); + if (!p) { + *key =3D NULL; + return NULL; + } + len =3D p - type; + + str =3D g_malloc(len + 1); + memcpy(str, type, len); + str[len] =3D '\0'; + + *key =3D str; + return ++p; +} + +static int default_fmt_format =3D 'x'; +static int default_fmt_size =3D 4; + +static int is_valid_option(const char *c, const char *typestr) +{ + char option[3]; + + option[0] =3D '-'; + option[1] =3D *c; + option[2] =3D '\0'; + + typestr =3D strstr(typestr, option); + return (typestr !=3D NULL); +} + +static const HMPCommand *search_dispatch_table(const HMPCommand *disp_tabl= e, + const char *cmdname) +{ + const HMPCommand *cmd; + + for (cmd =3D disp_table; cmd->name !=3D NULL; cmd++) { + if (hmp_compare_cmd(cmdname, cmd->name)) { + return cmd; + } + } + + return NULL; +} + +/* + * Parse command name from @cmdp according to command table @table. + * If blank, return NULL. + * Else, if no valid command can be found, report to @mon, and return + * NULL. + * Else, change @cmdp to point right behind the name, and return its + * command table entry. + * Do not assume the return value points into @table! It doesn't when + * the command is found in a sub-command table. + */ +static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, + const char *cmdp_start, + const char **cmdp, + HMPCommand *table) +{ + Monitor *mon =3D &hmp_mon->common; + const char *p; + const HMPCommand *cmd; + char cmdname[256]; + + /* extract the command name */ + p =3D get_command_name(*cmdp, cmdname, sizeof(cmdname)); + if (!p) { + return NULL; + } + + cmd =3D search_dispatch_table(table, cmdname); + if (!cmd) { + monitor_printf(mon, "unknown command: '%.*s'\n", + (int)(p - cmdp_start), cmdp_start); + return NULL; + } + if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) { + monitor_printf(mon, "Command '%.*s' not available with -preconfig " + "until after exit_preconfig.\n", + (int)(p - cmdp_start), cmdp_start); + return NULL; + } + + /* filter out following useless space */ + while (qemu_isspace(*p)) { + p++; + } + + *cmdp =3D p; + /* search sub command */ + if (cmd->sub_table !=3D NULL && *p !=3D '\0') { + return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_t= able); + } + + return cmd; +} + +/* + * Parse arguments for @cmd. + * If it can't be parsed, report to @mon, and return NULL. + * Else, insert command arguments into a QDict, and return it. + * Note: On success, caller has to free the QDict structure. + */ +static QDict *monitor_parse_arguments(Monitor *mon, + const char **endp, + const HMPCommand *cmd) +{ + const char *typestr; + char *key; + int c; + const char *p =3D *endp; + char buf[1024]; + QDict *qdict =3D qdict_new(); + + /* parse the parameters */ + typestr =3D cmd->args_type; + for (;;) { + typestr =3D key_get_info(typestr, &key); + if (!typestr) { + break; + } + c =3D *typestr; + typestr++; + switch (c) { + case 'F': + case 'B': + case 's': + { + int ret; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr =3D=3D '?') { + typestr++; + if (*p =3D=3D '\0') { + /* no optional string: NULL argument */ + break; + } + } + ret =3D get_str(buf, sizeof(buf), &p); + if (ret < 0) { + switch (c) { + case 'F': + monitor_printf(mon, "%s: filename expected\n", + cmd->name); + break; + case 'B': + monitor_printf(mon, "%s: block device name expecte= d\n", + cmd->name); + break; + default: + monitor_printf(mon, "%s: string expected\n", cmd->= name); + break; + } + goto fail; + } + qdict_put_str(qdict, key, buf); + } + break; + case 'O': + { + QemuOptsList *opts_list; + QemuOpts *opts; + + opts_list =3D qemu_find_opts(key); + if (!opts_list || opts_list->desc->name) { + goto bad_type; + } + while (qemu_isspace(*p)) { + p++; + } + if (!*p) { + break; + } + if (get_str(buf, sizeof(buf), &p) < 0) { + goto fail; + } + opts =3D qemu_opts_parse_noisily(opts_list, buf, true); + if (!opts) { + goto fail; + } + qemu_opts_to_qdict(opts, qdict); + qemu_opts_del(opts); + } + break; + case '/': + { + int count, format, size; + + while (qemu_isspace(*p)) { + p++; + } + if (*p =3D=3D '/') { + /* format found */ + p++; + count =3D 1; + if (qemu_isdigit(*p)) { + count =3D 0; + while (qemu_isdigit(*p)) { + count =3D count * 10 + (*p - '0'); + p++; + } + } + size =3D -1; + format =3D -1; + for (;;) { + switch (*p) { + case 'o': + case 'd': + case 'u': + case 'x': + case 'i': + case 'c': + format =3D *p++; + break; + case 'b': + size =3D 1; + p++; + break; + case 'h': + size =3D 2; + p++; + break; + case 'w': + size =3D 4; + p++; + break; + case 'g': + case 'L': + size =3D 8; + p++; + break; + default: + goto next; + } + } + next: + if (*p !=3D '\0' && !qemu_isspace(*p)) { + monitor_printf(mon, "invalid char in format: '%c'\= n", + *p); + goto fail; + } + if (format < 0) { + format =3D default_fmt_format; + } + if (format !=3D 'i') { + /* for 'i', not specifying a size gives -1 as size= */ + if (size < 0) { + size =3D default_fmt_size; + } + default_fmt_size =3D size; + } + default_fmt_format =3D format; + } else { + count =3D 1; + format =3D default_fmt_format; + if (format !=3D 'i') { + size =3D default_fmt_size; + } else { + size =3D -1; + } + } + qdict_put_int(qdict, "count", count); + qdict_put_int(qdict, "format", format); + qdict_put_int(qdict, "size", size); + } + break; + case 'i': + case 'l': + case 'M': + { + int64_t val; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr =3D=3D '?' || *typestr =3D=3D '.') { + if (*typestr =3D=3D '?') { + if (*p =3D=3D '\0') { + typestr++; + break; + } + } else { + if (*p =3D=3D '.') { + p++; + while (qemu_isspace(*p)) { + p++; + } + } else { + typestr++; + break; + } + } + typestr++; + } + if (get_expr(mon, &val, &p)) { + goto fail; + } + /* Check if 'i' is greater than 32-bit */ + if ((c =3D=3D 'i') && ((val >> 32) & 0xffffffff)) { + monitor_printf(mon, "\'%s\' has failed: ", cmd->name); + monitor_printf(mon, "integer is for 32-bit values\n"); + goto fail; + } else if (c =3D=3D 'M') { + if (val < 0) { + monitor_printf(mon, "enter a positive value\n"); + goto fail; + } + val *=3D MiB; + } + qdict_put_int(qdict, key, val); + } + break; + case 'o': + { + int ret; + uint64_t val; + const char *end; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr =3D=3D '?') { + typestr++; + if (*p =3D=3D '\0') { + break; + } + } + ret =3D qemu_strtosz_MiB(p, &end, &val); + if (ret < 0 || val > INT64_MAX) { + monitor_printf(mon, "invalid size\n"); + goto fail; + } + qdict_put_int(qdict, key, val); + p =3D end; + } + break; + case 'T': + { + double val; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr =3D=3D '?') { + typestr++; + if (*p =3D=3D '\0') { + break; + } + } + if (get_double(mon, &val, &p) < 0) { + goto fail; + } + if (p[0] && p[1] =3D=3D 's') { + switch (*p) { + case 'm': + val /=3D 1e3; p +=3D 2; break; + case 'u': + val /=3D 1e6; p +=3D 2; break; + case 'n': + val /=3D 1e9; p +=3D 2; break; + } + } + if (*p && !qemu_isspace(*p)) { + monitor_printf(mon, "Unknown unit suffix\n"); + goto fail; + } + qdict_put(qdict, key, qnum_from_double(val)); + } + break; + case 'b': + { + const char *beg; + bool val; + + while (qemu_isspace(*p)) { + p++; + } + beg =3D p; + while (qemu_isgraph(*p)) { + p++; + } + if (p - beg =3D=3D 2 && !memcmp(beg, "on", p - beg)) { + val =3D true; + } else if (p - beg =3D=3D 3 && !memcmp(beg, "off", p - beg= )) { + val =3D false; + } else { + monitor_printf(mon, "Expected 'on' or 'off'\n"); + goto fail; + } + qdict_put_bool(qdict, key, val); + } + break; + case '-': + { + const char *tmp =3D p; + int skip_key =3D 0; + /* option */ + + c =3D *typestr++; + if (c =3D=3D '\0') { + goto bad_type; + } + while (qemu_isspace(*p)) { + p++; + } + if (*p =3D=3D '-') { + p++; + if (c !=3D *p) { + if (!is_valid_option(p, typestr)) { + monitor_printf(mon, "%s: unsupported option -%= c\n", + cmd->name, *p); + goto fail; + } else { + skip_key =3D 1; + } + } + if (skip_key) { + p =3D tmp; + } else { + /* has option */ + p++; + qdict_put_bool(qdict, key, true); + } + } + } + break; + case 'S': + { + /* package all remaining string */ + int len; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr =3D=3D '?') { + typestr++; + if (*p =3D=3D '\0') { + /* no remaining string: NULL argument */ + break; + } + } + len =3D strlen(p); + if (len <=3D 0) { + monitor_printf(mon, "%s: string expected\n", + cmd->name); + goto fail; + } + qdict_put_str(qdict, key, p); + p +=3D len; + } + break; + default: + bad_type: + monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c); + goto fail; + } + g_free(key); + key =3D NULL; + } + /* check that all arguments were parsed */ + while (qemu_isspace(*p)) { + p++; + } + if (*p !=3D '\0') { + monitor_printf(mon, "%s: extraneous characters at the end of line\= n", + cmd->name); + goto fail; + } + + return qdict; + +fail: + qobject_unref(qdict); + g_free(key); + return NULL; +} + +void handle_hmp_command(MonitorHMP *mon, const char *cmdline) +{ + QDict *qdict; + const HMPCommand *cmd; + const char *cmd_start =3D cmdline; + + trace_handle_hmp_command(mon, cmdline); + + cmd =3D monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds); + if (!cmd) { + return; + } + + qdict =3D monitor_parse_arguments(&mon->common, &cmdline, cmd); + if (!qdict) { + while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) { + cmdline--; + } + monitor_printf(&mon->common, "Try \"help %.*s\" for more informati= on\n", + (int)(cmdline - cmd_start), cmd_start); + return; + } + + cmd->cmd(&mon->common, qdict); + qobject_unref(qdict); +} + +static void cmd_completion(MonitorHMP *mon, const char *name, const char *= list) +{ + const char *p, *pstart; + char cmd[128]; + int len; + + p =3D list; + for (;;) { + pstart =3D p; + p =3D qemu_strchrnul(p, '|'); + len =3D p - pstart; + if (len > sizeof(cmd) - 2) { + len =3D sizeof(cmd) - 2; + } + memcpy(cmd, pstart, len); + cmd[len] =3D '\0'; + if (name[0] =3D=3D '\0' || !strncmp(name, cmd, strlen(name))) { + readline_add_completion(mon->rs, cmd); + } + if (*p =3D=3D '\0') { + break; + } + p++; + } +} + +static void file_completion(MonitorHMP *mon, const char *input) +{ + DIR *ffs; + struct dirent *d; + char path[1024]; + char file[1024], file_prefix[1024]; + int input_path_len; + const char *p; + + p =3D strrchr(input, '/'); + if (!p) { + input_path_len =3D 0; + pstrcpy(file_prefix, sizeof(file_prefix), input); + pstrcpy(path, sizeof(path), "."); + } else { + input_path_len =3D p - input + 1; + memcpy(path, input, input_path_len); + if (input_path_len > sizeof(path) - 1) { + input_path_len =3D sizeof(path) - 1; + } + path[input_path_len] =3D '\0'; + pstrcpy(file_prefix, sizeof(file_prefix), p + 1); + } + + ffs =3D opendir(path); + if (!ffs) { + return; + } + for (;;) { + struct stat sb; + d =3D readdir(ffs); + if (!d) { + break; + } + + if (strcmp(d->d_name, ".") =3D=3D 0 || strcmp(d->d_name, "..") =3D= =3D 0) { + continue; + } + + if (strstart(d->d_name, file_prefix, NULL)) { + memcpy(file, input, input_path_len); + if (input_path_len < sizeof(file)) { + pstrcpy(file + input_path_len, sizeof(file) - input_path_l= en, + d->d_name); + } + /* + * stat the file to find out if it's a directory. + * In that case add a slash to speed up typing long paths + */ + if (stat(file, &sb) =3D=3D 0 && S_ISDIR(sb.st_mode)) { + pstrcat(file, sizeof(file), "/"); + } + readline_add_completion(mon->rs, file); + } + } + closedir(ffs); +} + +static const char *next_arg_type(const char *typestr) +{ + const char *p =3D strchr(typestr, ':'); + return (p !=3D NULL ? ++p : typestr); +} + +static void monitor_find_completion_by_table(MonitorHMP *mon, + const HMPCommand *cmd_table, + char **args, + int nb_args) +{ + const char *cmdname; + int i; + const char *ptype, *old_ptype, *str, *name; + const HMPCommand *cmd; + BlockBackend *blk =3D NULL; + + if (nb_args <=3D 1) { + /* command completion */ + if (nb_args =3D=3D 0) { + cmdname =3D ""; + } else { + cmdname =3D args[0]; + } + readline_set_completion_index(mon->rs, strlen(cmdname)); + for (cmd =3D cmd_table; cmd->name !=3D NULL; cmd++) { + if (!runstate_check(RUN_STATE_PRECONFIG) || + cmd_can_preconfig(cmd)) { + cmd_completion(mon, cmdname, cmd->name); + } + } + } else { + /* find the command */ + for (cmd =3D cmd_table; cmd->name !=3D NULL; cmd++) { + if (hmp_compare_cmd(args[0], cmd->name) && + (!runstate_check(RUN_STATE_PRECONFIG) || + cmd_can_preconfig(cmd))) { + break; + } + } + if (!cmd->name) { + return; + } + + if (cmd->sub_table) { + /* do the job again */ + monitor_find_completion_by_table(mon, cmd->sub_table, + &args[1], nb_args - 1); + return; + } + if (cmd->command_completion) { + cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]); + return; + } + + ptype =3D next_arg_type(cmd->args_type); + for (i =3D 0; i < nb_args - 2; i++) { + if (*ptype !=3D '\0') { + ptype =3D next_arg_type(ptype); + while (*ptype =3D=3D '?') { + ptype =3D next_arg_type(ptype); + } + } + } + str =3D args[nb_args - 1]; + old_ptype =3D NULL; + while (*ptype =3D=3D '-' && old_ptype !=3D ptype) { + old_ptype =3D ptype; + ptype =3D next_arg_type(ptype); + } + switch (*ptype) { + case 'F': + /* file completion */ + readline_set_completion_index(mon->rs, strlen(str)); + file_completion(mon, str); + break; + case 'B': + /* block device name completion */ + readline_set_completion_index(mon->rs, strlen(str)); + while ((blk =3D blk_next(blk)) !=3D NULL) { + name =3D blk_name(blk); + if (str[0] =3D=3D '\0' || + !strncmp(name, str, strlen(str))) { + readline_add_completion(mon->rs, name); + } + } + break; + case 's': + case 'S': + if (!strcmp(cmd->name, "help|?")) { + monitor_find_completion_by_table(mon, cmd_table, + &args[1], nb_args - 1); + } + break; + default: + break; + } + } +} + +static void monitor_find_completion(void *opaque, + const char *cmdline) +{ + MonitorHMP *mon =3D opaque; + char *args[MAX_ARGS]; + int nb_args, len; + + /* 1. parse the cmdline */ + if (parse_cmdline(cmdline, &nb_args, args) < 0) { + return; + } + + /* if the line ends with a space, it means we want to complete the + * next arg */ + len =3D strlen(cmdline); + if (len > 0 && qemu_isspace(cmdline[len - 1])) { + if (nb_args >=3D MAX_ARGS) { + goto cleanup; + } + args[nb_args++] =3D g_strdup(""); + } + + /* 2. auto complete according to args */ + monitor_find_completion_by_table(mon, hmp_cmds, args, nb_args); + +cleanup: + free_cmdline_args(args, nb_args); +} + +static void monitor_read(void *opaque, const uint8_t *buf, int size) +{ + MonitorHMP *mon; + Monitor *old_mon =3D cur_mon; + int i; + + cur_mon =3D opaque; + mon =3D container_of(cur_mon, MonitorHMP, common); + + if (mon->rs) { + for (i =3D 0; i < size; i++) { + readline_handle_byte(mon->rs, buf[i]); + } + } else { + if (size =3D=3D 0 || buf[size - 1] !=3D 0) { + monitor_printf(cur_mon, "corrupted command\n"); + } else { + handle_hmp_command(mon, (char *)buf); + } + } + + cur_mon =3D old_mon; +} + +static void monitor_event(void *opaque, int event) +{ + Monitor *mon =3D opaque; + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); + + switch (event) { + case CHR_EVENT_MUX_IN: + qemu_mutex_lock(&mon->mon_lock); + mon->mux_out =3D 0; + qemu_mutex_unlock(&mon->mon_lock); + if (mon->reset_seen) { + readline_restart(hmp_mon->rs); + monitor_resume(mon); + monitor_flush(mon); + } else { + atomic_mb_set(&mon->suspend_cnt, 0); + } + break; + + case CHR_EVENT_MUX_OUT: + if (mon->reset_seen) { + if (atomic_mb_read(&mon->suspend_cnt) =3D=3D 0) { + monitor_printf(mon, "\n"); + } + monitor_flush(mon); + monitor_suspend(mon); + } else { + atomic_inc(&mon->suspend_cnt); + } + qemu_mutex_lock(&mon->mon_lock); + mon->mux_out =3D 1; + qemu_mutex_unlock(&mon->mon_lock); + break; + + case CHR_EVENT_OPENED: + monitor_printf(mon, "QEMU %s monitor - type 'help' for more " + "information\n", QEMU_VERSION); + if (!mon->mux_out) { + readline_restart(hmp_mon->rs); + readline_show_prompt(hmp_mon->rs); + } + mon->reset_seen =3D 1; + mon_refcount++; + break; + + case CHR_EVENT_CLOSED: + mon_refcount--; + monitor_fdsets_cleanup(); + break; + } +} + + +/* + * These functions just adapt the readline interface in a typesafe way. We + * could cast function pointers but that discards compiler checks. + */ +static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque, + const char *fmt, ..= .) +{ + MonitorHMP *mon =3D opaque; + va_list ap; + va_start(ap, fmt); + monitor_vprintf(&mon->common, fmt, ap); + va_end(ap); +} + +static void monitor_readline_flush(void *opaque) +{ + MonitorHMP *mon =3D opaque; + monitor_flush(&mon->common); +} + +void monitor_init_hmp(Chardev *chr, int flags) +{ + MonitorHMP *mon =3D g_malloc0(sizeof(*mon)); + bool use_readline =3D flags & MONITOR_USE_READLINE; + + monitor_data_init(&mon->common, flags, false, false); + qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); + + if (use_readline) { + mon->rs =3D readline_init(monitor_readline_printf, + monitor_readline_flush, + mon, + monitor_find_completion); + monitor_read_command(mon, 0); + } + + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_r= ead, + monitor_event, NULL, &mon->common, NULL, true= ); + monitor_list_append(&mon->common); +} diff --git a/monitor/misc.c b/monitor/misc.c index 368b8297d4..c8289959c0 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -24,7 +24,6 @@ =20 #include "qemu/osdep.h" #include "monitor-internal.h" -#include "qemu/units.h" #include #include "cpu.h" #include "hw/hw.h" @@ -157,14 +156,10 @@ static QLIST_HEAD(, MonFdset) mon_fdsets; =20 int mon_refcount; =20 -static HMPCommand hmp_cmds[]; static HMPCommand hmp_info_cmds[]; =20 __thread Monitor *cur_mon; =20 -static void monitor_command_cb(void *opaque, const char *cmdline, - void *readline_opaque); - /** * Is @mon is using readline? * Note: not all HMP monitors use readline, e.g., gdbserver has a @@ -199,31 +194,6 @@ bool monitor_cur_is_qmp(void) return cur_mon && monitor_is_qmp(cur_mon); } =20 -void monitor_read_command(MonitorHMP *mon, int show_prompt) -{ - if (!mon->rs) - return; - - readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL); - if (show_prompt) - readline_show_prompt(mon->rs); -} - -int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, - void *opaque) -{ - if (mon->rs) { - readline_start(mon->rs, "Password: ", 1, readline_func, opaque); - /* prompt is printed on return from the command handler */ - return 0; - } else { - monitor_printf(&mon->common, - "terminal does not support password prompting\n"); - return -ENOTTY; - } -} - - static void monitor_flush_locked(Monitor *mon); =20 static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, @@ -542,8 +512,6 @@ static void monitor_qapi_event_init(void) qapi_event_throttle_equal); } =20 -static void handle_hmp_command(MonitorHMP *mon, const char *cmdline); - static void monitor_iothread_init(void); =20 void monitor_data_init(Monitor *mon, int flags, bool skip_flush, @@ -612,245 +580,27 @@ out: return output; } =20 -static int compare_cmd(const char *name, const char *list) +/** + * Is @name in the '|' separated list of names @list? + */ +int hmp_compare_cmd(const char *name, const char *list) { const char *p, *pstart; int len; len =3D strlen(name); p =3D list; - for(;;) { + for (;;) { pstart =3D p; p =3D qemu_strchrnul(p, '|'); - if ((p - pstart) =3D=3D len && !memcmp(pstart, name, len)) + if ((p - pstart) =3D=3D len && !memcmp(pstart, name, len)) { return 1; - if (*p =3D=3D '\0') - break; - p++; - } - return 0; -} - -static int get_str(char *buf, int buf_size, const char **pp) -{ - const char *p; - char *q; - int c; - - q =3D buf; - p =3D *pp; - while (qemu_isspace(*p)) { - p++; - } - if (*p =3D=3D '\0') { - fail: - *q =3D '\0'; - *pp =3D p; - return -1; - } - if (*p =3D=3D '\"') { - p++; - while (*p !=3D '\0' && *p !=3D '\"') { - if (*p =3D=3D '\\') { - p++; - c =3D *p++; - switch (c) { - case 'n': - c =3D '\n'; - break; - case 'r': - c =3D '\r'; - break; - case '\\': - case '\'': - case '\"': - break; - default: - printf("unsupported escape code: '\\%c'\n", c); - goto fail; - } - if ((q - buf) < buf_size - 1) { - *q++ =3D c; - } - } else { - if ((q - buf) < buf_size - 1) { - *q++ =3D *p; - } - p++; - } - } - if (*p !=3D '\"') { - printf("unterminated string\n"); - goto fail; - } - p++; - } else { - while (*p !=3D '\0' && !qemu_isspace(*p)) { - if ((q - buf) < buf_size - 1) { - *q++ =3D *p; - } - p++; - } - } - *q =3D '\0'; - *pp =3D p; - return 0; -} - -#define MAX_ARGS 16 - -static void free_cmdline_args(char **args, int nb_args) -{ - int i; - - assert(nb_args <=3D MAX_ARGS); - - for (i =3D 0; i < nb_args; i++) { - g_free(args[i]); - } - -} - -/* - * Parse the command line to get valid args. - * @cmdline: command line to be parsed. - * @pnb_args: location to store the number of args, must NOT be NULL. - * @args: location to store the args, which should be freed by caller, must - * NOT be NULL. - * - * Returns 0 on success, negative on failure. - * - * NOTE: this parser is an approximate form of the real command parser. Nu= mber - * of args have a limit of MAX_ARGS. If cmdline contains more, it wi= ll - * return with failure. - */ -static int parse_cmdline(const char *cmdline, - int *pnb_args, char **args) -{ - const char *p; - int nb_args, ret; - char buf[1024]; - - p =3D cmdline; - nb_args =3D 0; - for (;;) { - while (qemu_isspace(*p)) { - p++; } if (*p =3D=3D '\0') { break; } - if (nb_args >=3D MAX_ARGS) { - goto fail; - } - ret =3D get_str(buf, sizeof(buf), &p); - if (ret < 0) { - goto fail; - } - args[nb_args] =3D g_strdup(buf); - nb_args++; + p++; } - *pnb_args =3D nb_args; return 0; - - fail: - free_cmdline_args(args, nb_args); - return -1; -} - -/* - * Can command @cmd be executed in preconfig state? - */ -static bool cmd_can_preconfig(const HMPCommand *cmd) -{ - if (!cmd->flags) { - return false; - } - - return strchr(cmd->flags, 'p'); -} - -static void help_cmd_dump_one(Monitor *mon, - const HMPCommand *cmd, - char **prefix_args, - int prefix_args_nb) -{ - int i; - - if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) { - return; - } - - for (i =3D 0; i < prefix_args_nb; i++) { - monitor_printf(mon, "%s ", prefix_args[i]); - } - monitor_printf(mon, "%s %s -- %s\n", cmd->name, cmd->params, cmd->help= ); -} - -/* @args[@arg_index] is the valid command need to find in @cmds */ -static void help_cmd_dump(Monitor *mon, const HMPCommand *cmds, - char **args, int nb_args, int arg_index) -{ - const HMPCommand *cmd; - size_t i; - - /* No valid arg need to compare with, dump all in *cmds */ - if (arg_index >=3D nb_args) { - for (cmd =3D cmds; cmd->name !=3D NULL; cmd++) { - help_cmd_dump_one(mon, cmd, args, arg_index); - } - return; - } - - /* Find one entry to dump */ - for (cmd =3D cmds; cmd->name !=3D NULL; cmd++) { - if (compare_cmd(args[arg_index], cmd->name) && - ((!runstate_check(RUN_STATE_PRECONFIG) || - cmd_can_preconfig(cmd)))) { - if (cmd->sub_table) { - /* continue with next arg */ - help_cmd_dump(mon, cmd->sub_table, - args, nb_args, arg_index + 1); - } else { - help_cmd_dump_one(mon, cmd, args, arg_index); - } - return; - } - } - - /* Command not found */ - monitor_printf(mon, "unknown command: '"); - for (i =3D 0; i <=3D arg_index; i++) { - monitor_printf(mon, "%s%s", args[i], i =3D=3D arg_index ? "'\n" : = " "); - } -} - -static void help_cmd(Monitor *mon, const char *name) -{ - char *args[MAX_ARGS]; - int nb_args =3D 0; - - /* 1. parse user input */ - if (name) { - /* special case for log, directly dump and return */ - if (!strcmp(name, "log")) { - const QEMULogItem *item; - monitor_printf(mon, "Log items (comma separated):\n"); - monitor_printf(mon, "%-10s %s\n", "none", "remove all logs"); - for (item =3D qemu_log_items; item->mask !=3D 0; item++) { - monitor_printf(mon, "%-10s %s\n", item->name, item->help); - } - return; - } - - if (parse_cmdline(name, &nb_args, args) < 0) { - return; - } - } - - /* 2. dump the contents according to parsed args */ - help_cmd_dump(mon, hmp_cmds, args, nb_args, 0); - - free_cmdline_args(args, nb_args); } =20 static void do_help_cmd(Monitor *mon, const QDict *qdict) @@ -2510,30 +2260,16 @@ static HMPCommand hmp_info_cmds[] =3D { }; =20 /* hmp_cmds and hmp_info_cmds would be sorted at runtime */ -static HMPCommand hmp_cmds[] =3D { +HMPCommand hmp_cmds[] =3D { #include "hmp-commands.h" { NULL, NULL, }, }; =20 -/*******************************************************************/ - -static const char *pch; -static sigjmp_buf expr_env; - - -static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN -expr_error(Monitor *mon, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - monitor_vprintf(mon, fmt, ap); - monitor_printf(mon, "\n"); - va_end(ap); - siglongjmp(expr_env, 1); -} - -/* return 0 if OK, -1 if not found */ -static int get_monitor_def(target_long *pval, const char *name) +/* + * Set @pval to the value in the register identified by @name. + * return 0 if OK, -1 if not found + */ +int get_monitor_def(int64_t *pval, const char *name) { const MonitorDef *md =3D target_monitor_defs(); CPUState *cs =3D mon_get_cpu(); @@ -2546,7 +2282,7 @@ static int get_monitor_def(target_long *pval, const c= har *name) } =20 for(; md->name !=3D NULL; md++) { - if (compare_cmd(name, md->name)) { + if (hmp_compare_cmd(name, md->name)) { if (md->get_value) { *pval =3D md->get_value(md, md->offset); } else { @@ -2576,829 +2312,6 @@ static int get_monitor_def(target_long *pval, const= char *name) return ret; } =20 -static void next(void) -{ - if (*pch !=3D '\0') { - pch++; - while (qemu_isspace(*pch)) - pch++; - } -} - -static int64_t expr_sum(Monitor *mon); - -static int64_t expr_unary(Monitor *mon) -{ - int64_t n; - char *p; - int ret; - - switch(*pch) { - case '+': - next(); - n =3D expr_unary(mon); - break; - case '-': - next(); - n =3D -expr_unary(mon); - break; - case '~': - next(); - n =3D ~expr_unary(mon); - break; - case '(': - next(); - n =3D expr_sum(mon); - if (*pch !=3D ')') { - expr_error(mon, "')' expected"); - } - next(); - break; - case '\'': - pch++; - if (*pch =3D=3D '\0') - expr_error(mon, "character constant expected"); - n =3D *pch; - pch++; - if (*pch !=3D '\'') - expr_error(mon, "missing terminating \' character"); - next(); - break; - case '$': - { - char buf[128], *q; - target_long reg=3D0; - - pch++; - q =3D buf; - while ((*pch >=3D 'a' && *pch <=3D 'z') || - (*pch >=3D 'A' && *pch <=3D 'Z') || - (*pch >=3D '0' && *pch <=3D '9') || - *pch =3D=3D '_' || *pch =3D=3D '.') { - if ((q - buf) < sizeof(buf) - 1) - *q++ =3D *pch; - pch++; - } - while (qemu_isspace(*pch)) - pch++; - *q =3D 0; - ret =3D get_monitor_def(®, buf); - if (ret < 0) - expr_error(mon, "unknown register"); - n =3D reg; - } - break; - case '\0': - expr_error(mon, "unexpected end of expression"); - n =3D 0; - break; - default: - errno =3D 0; - n =3D strtoull(pch, &p, 0); - if (errno =3D=3D ERANGE) { - expr_error(mon, "number too large"); - } - if (pch =3D=3D p) { - expr_error(mon, "invalid char '%c' in expression", *p); - } - pch =3D p; - while (qemu_isspace(*pch)) - pch++; - break; - } - return n; -} - - -static int64_t expr_prod(Monitor *mon) -{ - int64_t val, val2; - int op; - - val =3D expr_unary(mon); - for(;;) { - op =3D *pch; - if (op !=3D '*' && op !=3D '/' && op !=3D '%') - break; - next(); - val2 =3D expr_unary(mon); - switch(op) { - default: - case '*': - val *=3D val2; - break; - case '/': - case '%': - if (val2 =3D=3D 0) - expr_error(mon, "division by zero"); - if (op =3D=3D '/') - val /=3D val2; - else - val %=3D val2; - break; - } - } - return val; -} - -static int64_t expr_logic(Monitor *mon) -{ - int64_t val, val2; - int op; - - val =3D expr_prod(mon); - for(;;) { - op =3D *pch; - if (op !=3D '&' && op !=3D '|' && op !=3D '^') - break; - next(); - val2 =3D expr_prod(mon); - switch(op) { - default: - case '&': - val &=3D val2; - break; - case '|': - val |=3D val2; - break; - case '^': - val ^=3D val2; - break; - } - } - return val; -} - -static int64_t expr_sum(Monitor *mon) -{ - int64_t val, val2; - int op; - - val =3D expr_logic(mon); - for(;;) { - op =3D *pch; - if (op !=3D '+' && op !=3D '-') - break; - next(); - val2 =3D expr_logic(mon); - if (op =3D=3D '+') - val +=3D val2; - else - val -=3D val2; - } - return val; -} - -static int get_expr(Monitor *mon, int64_t *pval, const char **pp) -{ - pch =3D *pp; - if (sigsetjmp(expr_env, 0)) { - *pp =3D pch; - return -1; - } - while (qemu_isspace(*pch)) - pch++; - *pval =3D expr_sum(mon); - *pp =3D pch; - return 0; -} - -static int get_double(Monitor *mon, double *pval, const char **pp) -{ - const char *p =3D *pp; - char *tailp; - double d; - - d =3D strtod(p, &tailp); - if (tailp =3D=3D p) { - monitor_printf(mon, "Number expected\n"); - return -1; - } - if (d !=3D d || d - d !=3D 0) { - /* NaN or infinity */ - monitor_printf(mon, "Bad number\n"); - return -1; - } - *pval =3D d; - *pp =3D tailp; - return 0; -} - -/* - * Store the command-name in cmdname, and return a pointer to - * the remaining of the command string. - */ -static const char *get_command_name(const char *cmdline, - char *cmdname, size_t nlen) -{ - size_t len; - const char *p, *pstart; - - p =3D cmdline; - while (qemu_isspace(*p)) - p++; - if (*p =3D=3D '\0') - return NULL; - pstart =3D p; - while (*p !=3D '\0' && *p !=3D '/' && !qemu_isspace(*p)) - p++; - len =3D p - pstart; - if (len > nlen - 1) - len =3D nlen - 1; - memcpy(cmdname, pstart, len); - cmdname[len] =3D '\0'; - return p; -} - -/** - * Read key of 'type' into 'key' and return the current - * 'type' pointer. - */ -static char *key_get_info(const char *type, char **key) -{ - size_t len; - char *p, *str; - - if (*type =3D=3D ',') - type++; - - p =3D strchr(type, ':'); - if (!p) { - *key =3D NULL; - return NULL; - } - len =3D p - type; - - str =3D g_malloc(len + 1); - memcpy(str, type, len); - str[len] =3D '\0'; - - *key =3D str; - return ++p; -} - -static int default_fmt_format =3D 'x'; -static int default_fmt_size =3D 4; - -static int is_valid_option(const char *c, const char *typestr) -{ - char option[3]; - =20 - option[0] =3D '-'; - option[1] =3D *c; - option[2] =3D '\0'; - =20 - typestr =3D strstr(typestr, option); - return (typestr !=3D NULL); -} - -static const HMPCommand *search_dispatch_table(const HMPCommand *disp_tabl= e, - const char *cmdname) -{ - const HMPCommand *cmd; - - for (cmd =3D disp_table; cmd->name !=3D NULL; cmd++) { - if (compare_cmd(cmdname, cmd->name)) { - return cmd; - } - } - - return NULL; -} - -/* - * Parse command name from @cmdp according to command table @table. - * If blank, return NULL. - * Else, if no valid command can be found, report to @mon, and return - * NULL. - * Else, change @cmdp to point right behind the name, and return its - * command table entry. - * Do not assume the return value points into @table! It doesn't when - * the command is found in a sub-command table. - */ -static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, - const char *cmdp_start, - const char **cmdp, - HMPCommand *table) -{ - Monitor *mon =3D &hmp_mon->common; - const char *p; - const HMPCommand *cmd; - char cmdname[256]; - - /* extract the command name */ - p =3D get_command_name(*cmdp, cmdname, sizeof(cmdname)); - if (!p) - return NULL; - - cmd =3D search_dispatch_table(table, cmdname); - if (!cmd) { - monitor_printf(mon, "unknown command: '%.*s'\n", - (int)(p - cmdp_start), cmdp_start); - return NULL; - } - if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) { - monitor_printf(mon, "Command '%.*s' not available with -preconfig " - "until after exit_preconfig.\n", - (int)(p - cmdp_start), cmdp_start); - return NULL; - } - - /* filter out following useless space */ - while (qemu_isspace(*p)) { - p++; - } - - *cmdp =3D p; - /* search sub command */ - if (cmd->sub_table !=3D NULL && *p !=3D '\0') { - return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_t= able); - } - - return cmd; -} - -/* - * Parse arguments for @cmd. - * If it can't be parsed, report to @mon, and return NULL. - * Else, insert command arguments into a QDict, and return it. - * Note: On success, caller has to free the QDict structure. - */ - -static QDict *monitor_parse_arguments(Monitor *mon, - const char **endp, - const HMPCommand *cmd) -{ - const char *typestr; - char *key; - int c; - const char *p =3D *endp; - char buf[1024]; - QDict *qdict =3D qdict_new(); - - /* parse the parameters */ - typestr =3D cmd->args_type; - for(;;) { - typestr =3D key_get_info(typestr, &key); - if (!typestr) - break; - c =3D *typestr; - typestr++; - switch(c) { - case 'F': - case 'B': - case 's': - { - int ret; - - while (qemu_isspace(*p)) - p++; - if (*typestr =3D=3D '?') { - typestr++; - if (*p =3D=3D '\0') { - /* no optional string: NULL argument */ - break; - } - } - ret =3D get_str(buf, sizeof(buf), &p); - if (ret < 0) { - switch(c) { - case 'F': - monitor_printf(mon, "%s: filename expected\n", - cmd->name); - break; - case 'B': - monitor_printf(mon, "%s: block device name expecte= d\n", - cmd->name); - break; - default: - monitor_printf(mon, "%s: string expected\n", cmd->= name); - break; - } - goto fail; - } - qdict_put_str(qdict, key, buf); - } - break; - case 'O': - { - QemuOptsList *opts_list; - QemuOpts *opts; - - opts_list =3D qemu_find_opts(key); - if (!opts_list || opts_list->desc->name) { - goto bad_type; - } - while (qemu_isspace(*p)) { - p++; - } - if (!*p) - break; - if (get_str(buf, sizeof(buf), &p) < 0) { - goto fail; - } - opts =3D qemu_opts_parse_noisily(opts_list, buf, true); - if (!opts) { - goto fail; - } - qemu_opts_to_qdict(opts, qdict); - qemu_opts_del(opts); - } - break; - case '/': - { - int count, format, size; - - while (qemu_isspace(*p)) - p++; - if (*p =3D=3D '/') { - /* format found */ - p++; - count =3D 1; - if (qemu_isdigit(*p)) { - count =3D 0; - while (qemu_isdigit(*p)) { - count =3D count * 10 + (*p - '0'); - p++; - } - } - size =3D -1; - format =3D -1; - for(;;) { - switch(*p) { - case 'o': - case 'd': - case 'u': - case 'x': - case 'i': - case 'c': - format =3D *p++; - break; - case 'b': - size =3D 1; - p++; - break; - case 'h': - size =3D 2; - p++; - break; - case 'w': - size =3D 4; - p++; - break; - case 'g': - case 'L': - size =3D 8; - p++; - break; - default: - goto next; - } - } - next: - if (*p !=3D '\0' && !qemu_isspace(*p)) { - monitor_printf(mon, "invalid char in format: '%c'\= n", - *p); - goto fail; - } - if (format < 0) - format =3D default_fmt_format; - if (format !=3D 'i') { - /* for 'i', not specifying a size gives -1 as size= */ - if (size < 0) - size =3D default_fmt_size; - default_fmt_size =3D size; - } - default_fmt_format =3D format; - } else { - count =3D 1; - format =3D default_fmt_format; - if (format !=3D 'i') { - size =3D default_fmt_size; - } else { - size =3D -1; - } - } - qdict_put_int(qdict, "count", count); - qdict_put_int(qdict, "format", format); - qdict_put_int(qdict, "size", size); - } - break; - case 'i': - case 'l': - case 'M': - { - int64_t val; - - while (qemu_isspace(*p)) - p++; - if (*typestr =3D=3D '?' || *typestr =3D=3D '.') { - if (*typestr =3D=3D '?') { - if (*p =3D=3D '\0') { - typestr++; - break; - } - } else { - if (*p =3D=3D '.') { - p++; - while (qemu_isspace(*p)) - p++; - } else { - typestr++; - break; - } - } - typestr++; - } - if (get_expr(mon, &val, &p)) - goto fail; - /* Check if 'i' is greater than 32-bit */ - if ((c =3D=3D 'i') && ((val >> 32) & 0xffffffff)) { - monitor_printf(mon, "\'%s\' has failed: ", cmd->name); - monitor_printf(mon, "integer is for 32-bit values\n"); - goto fail; - } else if (c =3D=3D 'M') { - if (val < 0) { - monitor_printf(mon, "enter a positive value\n"); - goto fail; - } - val *=3D MiB; - } - qdict_put_int(qdict, key, val); - } - break; - case 'o': - { - int ret; - uint64_t val; - const char *end; - - while (qemu_isspace(*p)) { - p++; - } - if (*typestr =3D=3D '?') { - typestr++; - if (*p =3D=3D '\0') { - break; - } - } - ret =3D qemu_strtosz_MiB(p, &end, &val); - if (ret < 0 || val > INT64_MAX) { - monitor_printf(mon, "invalid size\n"); - goto fail; - } - qdict_put_int(qdict, key, val); - p =3D end; - } - break; - case 'T': - { - double val; - - while (qemu_isspace(*p)) - p++; - if (*typestr =3D=3D '?') { - typestr++; - if (*p =3D=3D '\0') { - break; - } - } - if (get_double(mon, &val, &p) < 0) { - goto fail; - } - if (p[0] && p[1] =3D=3D 's') { - switch (*p) { - case 'm': - val /=3D 1e3; p +=3D 2; break; - case 'u': - val /=3D 1e6; p +=3D 2; break; - case 'n': - val /=3D 1e9; p +=3D 2; break; - } - } - if (*p && !qemu_isspace(*p)) { - monitor_printf(mon, "Unknown unit suffix\n"); - goto fail; - } - qdict_put(qdict, key, qnum_from_double(val)); - } - break; - case 'b': - { - const char *beg; - bool val; - - while (qemu_isspace(*p)) { - p++; - } - beg =3D p; - while (qemu_isgraph(*p)) { - p++; - } - if (p - beg =3D=3D 2 && !memcmp(beg, "on", p - beg)) { - val =3D true; - } else if (p - beg =3D=3D 3 && !memcmp(beg, "off", p - beg= )) { - val =3D false; - } else { - monitor_printf(mon, "Expected 'on' or 'off'\n"); - goto fail; - } - qdict_put_bool(qdict, key, val); - } - break; - case '-': - { - const char *tmp =3D p; - int skip_key =3D 0; - /* option */ - - c =3D *typestr++; - if (c =3D=3D '\0') - goto bad_type; - while (qemu_isspace(*p)) - p++; - if (*p =3D=3D '-') { - p++; - if(c !=3D *p) { - if(!is_valid_option(p, typestr)) { - =20 - monitor_printf(mon, "%s: unsupported option -%= c\n", - cmd->name, *p); - goto fail; - } else { - skip_key =3D 1; - } - } - if(skip_key) { - p =3D tmp; - } else { - /* has option */ - p++; - qdict_put_bool(qdict, key, true); - } - } - } - break; - case 'S': - { - /* package all remaining string */ - int len; - - while (qemu_isspace(*p)) { - p++; - } - if (*typestr =3D=3D '?') { - typestr++; - if (*p =3D=3D '\0') { - /* no remaining string: NULL argument */ - break; - } - } - len =3D strlen(p); - if (len <=3D 0) { - monitor_printf(mon, "%s: string expected\n", - cmd->name); - goto fail; - } - qdict_put_str(qdict, key, p); - p +=3D len; - } - break; - default: - bad_type: - monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c); - goto fail; - } - g_free(key); - key =3D NULL; - } - /* check that all arguments were parsed */ - while (qemu_isspace(*p)) - p++; - if (*p !=3D '\0') { - monitor_printf(mon, "%s: extraneous characters at the end of line\= n", - cmd->name); - goto fail; - } - - return qdict; - -fail: - qobject_unref(qdict); - g_free(key); - return NULL; -} - -static void handle_hmp_command(MonitorHMP *mon, const char *cmdline) -{ - QDict *qdict; - const HMPCommand *cmd; - const char *cmd_start =3D cmdline; - - trace_handle_hmp_command(mon, cmdline); - - cmd =3D monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds); - if (!cmd) { - return; - } - - qdict =3D monitor_parse_arguments(&mon->common, &cmdline, cmd); - if (!qdict) { - while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) { - cmdline--; - } - monitor_printf(&mon->common, "Try \"help %.*s\" for more informati= on\n", - (int)(cmdline - cmd_start), cmd_start); - return; - } - - cmd->cmd(&mon->common, qdict); - qobject_unref(qdict); -} - -static void cmd_completion(MonitorHMP *mon, const char *name, const char *= list) -{ - const char *p, *pstart; - char cmd[128]; - int len; - - p =3D list; - for(;;) { - pstart =3D p; - p =3D qemu_strchrnul(p, '|'); - len =3D p - pstart; - if (len > sizeof(cmd) - 2) - len =3D sizeof(cmd) - 2; - memcpy(cmd, pstart, len); - cmd[len] =3D '\0'; - if (name[0] =3D=3D '\0' || !strncmp(name, cmd, strlen(name))) { - readline_add_completion(mon->rs, cmd); - } - if (*p =3D=3D '\0') - break; - p++; - } -} - -static void file_completion(MonitorHMP *mon, const char *input) -{ - DIR *ffs; - struct dirent *d; - char path[1024]; - char file[1024], file_prefix[1024]; - int input_path_len; - const char *p; - - p =3D strrchr(input, '/'); - if (!p) { - input_path_len =3D 0; - pstrcpy(file_prefix, sizeof(file_prefix), input); - pstrcpy(path, sizeof(path), "."); - } else { - input_path_len =3D p - input + 1; - memcpy(path, input, input_path_len); - if (input_path_len > sizeof(path) - 1) - input_path_len =3D sizeof(path) - 1; - path[input_path_len] =3D '\0'; - pstrcpy(file_prefix, sizeof(file_prefix), p + 1); - } - - ffs =3D opendir(path); - if (!ffs) - return; - for(;;) { - struct stat sb; - d =3D readdir(ffs); - if (!d) - break; - - if (strcmp(d->d_name, ".") =3D=3D 0 || strcmp(d->d_name, "..") =3D= =3D 0) { - continue; - } - - if (strstart(d->d_name, file_prefix, NULL)) { - memcpy(file, input, input_path_len); - if (input_path_len < sizeof(file)) - pstrcpy(file + input_path_len, sizeof(file) - input_path_l= en, - d->d_name); - /* stat the file to find out if it's a directory. - * In that case add a slash to speed up typing long paths - */ - if (stat(file, &sb) =3D=3D 0 && S_ISDIR(sb.st_mode)) { - pstrcat(file, sizeof(file), "/"); - } - readline_add_completion(mon->rs, file); - } - } - closedir(ffs); -} - -static const char *next_arg_type(const char *typestr) -{ - const char *p =3D strchr(typestr, ':'); - return (p !=3D NULL ? ++p : typestr); -} - static void add_completion_option(ReadLineState *rs, const char *str, const char *option) { @@ -3829,127 +2742,6 @@ void loadvm_completion(ReadLineState *rs, int nb_ar= gs, const char *str) } } =20 -static void monitor_find_completion_by_table(MonitorHMP *mon, - const HMPCommand *cmd_table, - char **args, - int nb_args) -{ - const char *cmdname; - int i; - const char *ptype, *old_ptype, *str, *name; - const HMPCommand *cmd; - BlockBackend *blk =3D NULL; - - if (nb_args <=3D 1) { - /* command completion */ - if (nb_args =3D=3D 0) - cmdname =3D ""; - else - cmdname =3D args[0]; - readline_set_completion_index(mon->rs, strlen(cmdname)); - for (cmd =3D cmd_table; cmd->name !=3D NULL; cmd++) { - if (!runstate_check(RUN_STATE_PRECONFIG) || - cmd_can_preconfig(cmd)) { - cmd_completion(mon, cmdname, cmd->name); - } - } - } else { - /* find the command */ - for (cmd =3D cmd_table; cmd->name !=3D NULL; cmd++) { - if (compare_cmd(args[0], cmd->name) && - (!runstate_check(RUN_STATE_PRECONFIG) || - cmd_can_preconfig(cmd))) { - break; - } - } - if (!cmd->name) { - return; - } - - if (cmd->sub_table) { - /* do the job again */ - monitor_find_completion_by_table(mon, cmd->sub_table, - &args[1], nb_args - 1); - return; - } - if (cmd->command_completion) { - cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]); - return; - } - - ptype =3D next_arg_type(cmd->args_type); - for(i =3D 0; i < nb_args - 2; i++) { - if (*ptype !=3D '\0') { - ptype =3D next_arg_type(ptype); - while (*ptype =3D=3D '?') - ptype =3D next_arg_type(ptype); - } - } - str =3D args[nb_args - 1]; - old_ptype =3D NULL; - while (*ptype =3D=3D '-' && old_ptype !=3D ptype) { - old_ptype =3D ptype; - ptype =3D next_arg_type(ptype); - } - switch(*ptype) { - case 'F': - /* file completion */ - readline_set_completion_index(mon->rs, strlen(str)); - file_completion(mon, str); - break; - case 'B': - /* block device name completion */ - readline_set_completion_index(mon->rs, strlen(str)); - while ((blk =3D blk_next(blk)) !=3D NULL) { - name =3D blk_name(blk); - if (str[0] =3D=3D '\0' || - !strncmp(name, str, strlen(str))) { - readline_add_completion(mon->rs, name); - } - } - break; - case 's': - case 'S': - if (!strcmp(cmd->name, "help|?")) { - monitor_find_completion_by_table(mon, cmd_table, - &args[1], nb_args - 1); - } - break; - default: - break; - } - } -} - -static void monitor_find_completion(void *opaque, - const char *cmdline) -{ - MonitorHMP *mon =3D opaque; - char *args[MAX_ARGS]; - int nb_args, len; - - /* 1. parse the cmdline */ - if (parse_cmdline(cmdline, &nb_args, args) < 0) { - return; - } - - /* if the line ends with a space, it means we want to complete the - next arg */ - len =3D strlen(cmdline); - if (len > 0 && qemu_isspace(cmdline[len - 1])) { - if (nb_args >=3D MAX_ARGS) { - goto cleanup; - } - args[nb_args++] =3D g_strdup(""); - } - - /* 2. auto complete according to args */ - monitor_find_completion_by_table(mon, hmp_cmds, args, nb_args); - -cleanup: - free_cmdline_args(args, nb_args); -} - int monitor_can_read(void *opaque) { Monitor *mon =3D opaque; @@ -3957,38 +2749,6 @@ int monitor_can_read(void *opaque) return !atomic_mb_read(&mon->suspend_cnt); } =20 -static void monitor_read(void *opaque, const uint8_t *buf, int size) -{ - MonitorHMP *mon; - Monitor *old_mon =3D cur_mon; - int i; - - cur_mon =3D opaque; - mon =3D container_of(cur_mon, MonitorHMP, common); - - if (mon->rs) { - for (i =3D 0; i < size; i++) - readline_handle_byte(mon->rs, buf[i]); - } else { - if (size =3D=3D 0 || buf[size - 1] !=3D 0) - monitor_printf(cur_mon, "corrupted command\n"); - else - handle_hmp_command(mon, (char *)buf); - } - - cur_mon =3D old_mon; -} - -static void monitor_command_cb(void *opaque, const char *cmdline, - void *readline_opaque) -{ - MonitorHMP *mon =3D opaque; - - monitor_suspend(&mon->common); - handle_hmp_command(mon, cmdline); - monitor_resume(&mon->common); -} - int monitor_suspend(Monitor *mon) { if (monitor_is_hmp_non_interactive(mon)) { @@ -4043,58 +2803,6 @@ void monitor_resume(Monitor *mon) trace_monitor_suspend(mon, -1); } =20 -static void monitor_event(void *opaque, int event) -{ - Monitor *mon =3D opaque; - MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); - - switch (event) { - case CHR_EVENT_MUX_IN: - qemu_mutex_lock(&mon->mon_lock); - mon->mux_out =3D 0; - qemu_mutex_unlock(&mon->mon_lock); - if (mon->reset_seen) { - readline_restart(hmp_mon->rs); - monitor_resume(mon); - monitor_flush(mon); - } else { - atomic_mb_set(&mon->suspend_cnt, 0); - } - break; - - case CHR_EVENT_MUX_OUT: - if (mon->reset_seen) { - if (atomic_mb_read(&mon->suspend_cnt) =3D=3D 0) { - monitor_printf(mon, "\n"); - } - monitor_flush(mon); - monitor_suspend(mon); - } else { - atomic_inc(&mon->suspend_cnt); - } - qemu_mutex_lock(&mon->mon_lock); - mon->mux_out =3D 1; - qemu_mutex_unlock(&mon->mon_lock); - break; - - case CHR_EVENT_OPENED: - monitor_printf(mon, "QEMU %s monitor - type 'help' for more " - "information\n", QEMU_VERSION); - if (!mon->mux_out) { - readline_restart(hmp_mon->rs); - readline_show_prompt(hmp_mon->rs); - } - mon->reset_seen =3D 1; - mon_refcount++; - break; - - case CHR_EVENT_CLOSED: - mon_refcount--; - monitor_fdsets_cleanup(); - break; - } -} - static int compare_mon_cmd(const void *a, const void *b) { @@ -4137,25 +2845,6 @@ void monitor_init_globals(void) NULL); } =20 -/* These functions just adapt the readline interface in a typesafe way. We - * could cast function pointers but that discards compiler checks. - */ -static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque, - const char *fmt, ..= .) -{ - MonitorHMP *mon =3D opaque; - va_list ap; - va_start(ap, fmt); - monitor_vprintf(&mon->common, fmt, ap); - va_end(ap); -} - -static void monitor_readline_flush(void *opaque) -{ - MonitorHMP *mon =3D opaque; - monitor_flush(&mon->common); -} - /* * Print to current monitor if we have one, else to stderr. */ @@ -4198,27 +2887,6 @@ void monitor_list_append(Monitor *mon) } } =20 -static void monitor_init_hmp(Chardev *chr, int flags) -{ - MonitorHMP *mon =3D g_malloc0(sizeof(*mon)); - bool use_readline =3D flags & MONITOR_USE_READLINE; - - monitor_data_init(&mon->common, flags, false, false); - qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); - - if (use_readline) { - mon->rs =3D readline_init(monitor_readline_printf, - monitor_readline_flush, - mon, - monitor_find_completion); - monitor_read_command(mon, 0); - } - - qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_r= ead, - monitor_event, NULL, &mon->common, NULL, true= ); - monitor_list_append(&mon->common); -} - void monitor_init(Chardev *chr, int flags) { if (flags & MONITOR_USE_CONTROL) { diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs index 1037c09ff8..bea8838acc 100644 --- a/monitor/Makefile.objs +++ b/monitor/Makefile.objs @@ -1,3 +1,3 @@ obj-y +=3D misc.o -common-obj-y +=3D qmp.o +common-obj-y +=3D qmp.o hmp.o common-obj-y +=3D qmp-cmds.o hmp-cmds.o diff --git a/monitor/trace-events b/monitor/trace-events index a06dde3fd3..2285d26121 100644 --- a/monitor/trace-events +++ b/monitor/trace-events @@ -1,10 +1,12 @@ # See docs/devel/tracing.txt for syntax documentation. =20 +# hmp.c +handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" + # misc.c monitor_protocol_event_handler(uint32_t event, void *qdict) "event=3D%d da= ta=3D%p" monitor_protocol_event_emit(uint32_t event, void *data) "event=3D%d data= =3D%p" monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "= event=3D%d data=3D%p rate=3D%" PRId64 -handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" monitor_suspend(void *ptr, int cnt) "mon %p: %d" =20 # qmp.c --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560445055; cv=none; d=zoho.com; s=zohoarc; b=O9Th8Nbq70wK4iorS2FSb0QlRHT0ho8MboDleE2OjfqlSItbe4R9gJvOtC431go7++uZf7VM7bPQr9k0EunywZCxZy/9uhhUMrElB/UDqAGhLvp2T21a9fqQBQ10QbsQSa6GXNabjjLTB19DhbAmq5gOAicrS/SW8k32Ou/NfWI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560445055; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=3JPuntZROoLhM1pT6kMhVXl6ZNsg69KcVdCxvJboU34=; b=gmcC7lIyQ2ey/HY/64wwuQ81/sVGq9yCpKm0DH6zRoxrVO5HtkBvWu6Z0JI7nEgZPh41FoRqitKbKhxpZoKD92AE8HWNY/8nEtVoMQ6BRdAO+KuG5JgSY/1ro8EP22E9P/QFt5pknZovZk6lF0TuLgbKsuaWYmEJCG7g5qzLybA= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560445055450212.49949242771595; Thu, 13 Jun 2019 09:57:35 -0700 (PDT) Received: from localhost ([::1]:41880 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbT2Z-0003Ug-7E for importer@patchew.org; Thu, 13 Jun 2019 12:57:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60354) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRln-000131-FW for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:36:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRlh-0004BV-Id for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:36:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36962) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRlF-0003pD-W3; Thu, 13 Jun 2019 11:35:36 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 36BD6C075BC4; Thu, 13 Jun 2019 15:35:22 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7F6B960C78; Thu, 13 Jun 2019 15:35:19 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:34:02 +0200 Message-Id: <20190613153405.24769-13-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 13 Jun 2019 15:35:32 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Move the monitor core infrastructure from monitor/misc.c to monitor/monitor.c. This is code that can be shared for all targets, so compile it only once. What remains in monitor/misc.c after this patch is mostly monitor command implementations (which could move to hmp-cmds.c or qmp-cmds.c later) and code that requires a system emulator or is even target-dependent (including HMP command completion code). The amount of function and particularly extern variables in monitor_int.h is probably a bit larger than it needs to be, but this way no non-trivial code modifications are needed. The interfaces between all monitor parts can be cleaned up later. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- include/monitor/monitor.h | 1 + monitor/monitor-internal.h | 1 + monitor/misc.c | 599 +--------------------------------- monitor/monitor.c | 637 +++++++++++++++++++++++++++++++++++++ MAINTAINERS | 2 + monitor/Makefile.objs | 2 +- monitor/trace-events | 2 +- 7 files changed, 644 insertions(+), 600 deletions(-) create mode 100644 monitor/monitor.c diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index efdea83bb3..af5ddbe785 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -19,6 +19,7 @@ typedef struct MonitorHMP MonitorHMP; bool monitor_cur_is_qmp(void); =20 void monitor_init_globals(void); +void monitor_init_globals_core(void); void monitor_init(Chardev *chr, int flags); void monitor_cleanup(void); =20 diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index ad3b7ee7ec..30679d522e 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -171,6 +171,7 @@ void monitor_init_hmp(Chardev *chr, int flags); int monitor_puts(Monitor *mon, const char *str); void monitor_data_init(Monitor *mon, int flags, bool skip_flush, bool use_io_thread); +void monitor_data_destroy(Monitor *mon); int monitor_can_read(void *opaque); void monitor_list_append(Monitor *mon); void monitor_fdsets_cleanup(void); diff --git a/monitor/misc.c b/monitor/misc.c index c8289959c0..dddbddb21f 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -64,7 +64,6 @@ #include "qapi/qmp/json-parser.h" #include "qapi/qmp/qlist.h" #include "qom/object_interfaces.h" -#include "trace.h" #include "trace/control.h" #include "monitor/hmp-target.h" #ifdef CONFIG_TRACE_SIMPLE @@ -119,429 +118,15 @@ struct MonFdset { QLIST_ENTRY(MonFdset) next; }; =20 -/* - * To prevent flooding clients, events can be throttled. The - * throttling is calculated globally, rather than per-Monitor - * instance. - */ -typedef struct MonitorQAPIEventState { - QAPIEvent event; /* Throttling state for this event type and... */ - QDict *data; /* ... data, see qapi_event_throttle_equal() */ - QEMUTimer *timer; /* Timer for handling delayed events */ - QDict *qdict; /* Delayed event (if any) */ -} MonitorQAPIEventState; - -typedef struct { - int64_t rate; /* Minimum time (in ns) between two events */ -} MonitorQAPIEventConf; - -/* Shared monitor I/O thread */ -IOThread *mon_iothread; - -/* Bottom half to dispatch the requests received from I/O thread */ -QEMUBH *qmp_dispatcher_bh; - /* QMP checker flags */ #define QMP_ACCEPT_UNKNOWNS 1 =20 -/* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */ -QemuMutex monitor_lock; -static GHashTable *monitor_qapi_event_state; -MonitorList mon_list; -static bool monitor_destroyed; - /* Protects mon_fdsets */ static QemuMutex mon_fdsets_lock; static QLIST_HEAD(, MonFdset) mon_fdsets; =20 -int mon_refcount; - static HMPCommand hmp_info_cmds[]; =20 -__thread Monitor *cur_mon; - -/** - * Is @mon is using readline? - * Note: not all HMP monitors use readline, e.g., gdbserver has a - * non-interactive HMP monitor, so readline is not used there. - */ -static inline bool monitor_uses_readline(const Monitor *mon) -{ - return mon->flags & MONITOR_USE_READLINE; -} - -static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) -{ - return !monitor_is_qmp(mon) && !monitor_uses_readline(mon); -} - -/* - * Return the clock to use for recording an event's time. - * It's QEMU_CLOCK_REALTIME, except for qtests it's - * QEMU_CLOCK_VIRTUAL, to support testing rate limits. - * Beware: result is invalid before configure_accelerator(). - */ -static inline QEMUClockType monitor_get_event_clock(void) -{ - return qtest_enabled() ? QEMU_CLOCK_VIRTUAL : QEMU_CLOCK_REALTIME; -} - -/** - * Is the current monitor, if any, a QMP monitor? - */ -bool monitor_cur_is_qmp(void) -{ - return cur_mon && monitor_is_qmp(cur_mon); -} - -static void monitor_flush_locked(Monitor *mon); - -static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, - void *opaque) -{ - Monitor *mon =3D opaque; - - qemu_mutex_lock(&mon->mon_lock); - mon->out_watch =3D 0; - monitor_flush_locked(mon); - qemu_mutex_unlock(&mon->mon_lock); - return FALSE; -} - -/* Caller must hold mon->mon_lock */ -static void monitor_flush_locked(Monitor *mon) -{ - int rc; - size_t len; - const char *buf; - - if (mon->skip_flush) { - return; - } - - buf =3D qstring_get_str(mon->outbuf); - len =3D qstring_get_length(mon->outbuf); - - if (len && !mon->mux_out) { - rc =3D qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len); - if ((rc < 0 && errno !=3D EAGAIN) || (rc =3D=3D len)) { - /* all flushed or error */ - qobject_unref(mon->outbuf); - mon->outbuf =3D qstring_new(); - return; - } - if (rc > 0) { - /* partial write */ - QString *tmp =3D qstring_from_str(buf + rc); - qobject_unref(mon->outbuf); - mon->outbuf =3D tmp; - } - if (mon->out_watch =3D=3D 0) { - mon->out_watch =3D - qemu_chr_fe_add_watch(&mon->chr, G_IO_OUT | G_IO_HUP, - monitor_unblocked, mon); - } - } -} - -void monitor_flush(Monitor *mon) -{ - qemu_mutex_lock(&mon->mon_lock); - monitor_flush_locked(mon); - qemu_mutex_unlock(&mon->mon_lock); -} - -/* flush at every end of line */ -int monitor_puts(Monitor *mon, const char *str) -{ - int i; - char c; - - qemu_mutex_lock(&mon->mon_lock); - for (i =3D 0; str[i]; i++) { - c =3D str[i]; - if (c =3D=3D '\n') { - qstring_append_chr(mon->outbuf, '\r'); - } - qstring_append_chr(mon->outbuf, c); - if (c =3D=3D '\n') { - monitor_flush_locked(mon); - } - } - qemu_mutex_unlock(&mon->mon_lock); - - return i; -} - -int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) -{ - char *buf; - int n; - - if (!mon) - return -1; - - if (monitor_is_qmp(mon)) { - return -1; - } - - buf =3D g_strdup_vprintf(fmt, ap); - n =3D monitor_puts(mon, buf); - g_free(buf); - return n; -} - -int monitor_printf(Monitor *mon, const char *fmt, ...) -{ - int ret; - - va_list ap; - va_start(ap, fmt); - ret =3D monitor_vprintf(mon, fmt, ap); - va_end(ap); - return ret; -} - -static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] =3D { - /* Limit guest-triggerable events to 1 per second */ - [QAPI_EVENT_RTC_CHANGE] =3D { 1000 * SCALE_MS }, - [QAPI_EVENT_WATCHDOG] =3D { 1000 * SCALE_MS }, - [QAPI_EVENT_BALLOON_CHANGE] =3D { 1000 * SCALE_MS }, - [QAPI_EVENT_QUORUM_REPORT_BAD] =3D { 1000 * SCALE_MS }, - [QAPI_EVENT_QUORUM_FAILURE] =3D { 1000 * SCALE_MS }, - [QAPI_EVENT_VSERPORT_CHANGE] =3D { 1000 * SCALE_MS }, -}; - -/* - * Broadcast an event to all monitors. - * @qdict is the event object. Its member "event" must match @event. - * Caller must hold monitor_lock. - */ -static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) -{ - Monitor *mon; - MonitorQMP *qmp_mon; - - trace_monitor_protocol_event_emit(event, qdict); - QTAILQ_FOREACH(mon, &mon_list, entry) { - if (!monitor_is_qmp(mon)) { - continue; - } - - qmp_mon =3D container_of(mon, MonitorQMP, common); - if (qmp_mon->commands !=3D &qmp_cap_negotiation_commands) { - qmp_send_response(qmp_mon, qdict); - } - } -} - -static void monitor_qapi_event_handler(void *opaque); - -/* - * Queue a new event for emission to Monitor instances, - * applying any rate limiting if required. - */ -static void -monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict) -{ - MonitorQAPIEventConf *evconf; - MonitorQAPIEventState *evstate; - - assert(event < QAPI_EVENT__MAX); - evconf =3D &monitor_qapi_event_conf[event]; - trace_monitor_protocol_event_queue(event, qdict, evconf->rate); - - qemu_mutex_lock(&monitor_lock); - - if (!evconf->rate) { - /* Unthrottled event */ - monitor_qapi_event_emit(event, qdict); - } else { - QDict *data =3D qobject_to(QDict, qdict_get(qdict, "data")); - MonitorQAPIEventState key =3D { .event =3D event, .data =3D data }; - - evstate =3D g_hash_table_lookup(monitor_qapi_event_state, &key); - assert(!evstate || timer_pending(evstate->timer)); - - if (evstate) { - /* - * Timer is pending for (at least) evconf->rate ns after - * last send. Store event for sending when timer fires, - * replacing a prior stored event if any. - */ - qobject_unref(evstate->qdict); - evstate->qdict =3D qobject_ref(qdict); - } else { - /* - * Last send was (at least) evconf->rate ns ago. - * Send immediately, and arm the timer to call - * monitor_qapi_event_handler() in evconf->rate ns. Any - * events arriving before then will be delayed until then. - */ - int64_t now =3D qemu_clock_get_ns(monitor_get_event_clock()); - - monitor_qapi_event_emit(event, qdict); - - evstate =3D g_new(MonitorQAPIEventState, 1); - evstate->event =3D event; - evstate->data =3D qobject_ref(data); - evstate->qdict =3D NULL; - evstate->timer =3D timer_new_ns(monitor_get_event_clock(), - monitor_qapi_event_handler, - evstate); - g_hash_table_add(monitor_qapi_event_state, evstate); - timer_mod_ns(evstate->timer, now + evconf->rate); - } - } - - qemu_mutex_unlock(&monitor_lock); -} - -void qapi_event_emit(QAPIEvent event, QDict *qdict) -{ - /* - * monitor_qapi_event_queue_no_reenter() is not reentrant: it - * would deadlock on monitor_lock. Work around by queueing - * events in thread-local storage. - * TODO: remove this, make it re-enter safe. - */ - typedef struct MonitorQapiEvent { - QAPIEvent event; - QDict *qdict; - QSIMPLEQ_ENTRY(MonitorQapiEvent) entry; - } MonitorQapiEvent; - static __thread QSIMPLEQ_HEAD(, MonitorQapiEvent) event_queue; - static __thread bool reentered; - MonitorQapiEvent *ev; - - if (!reentered) { - QSIMPLEQ_INIT(&event_queue); - } - - ev =3D g_new(MonitorQapiEvent, 1); - ev->qdict =3D qobject_ref(qdict); - ev->event =3D event; - QSIMPLEQ_INSERT_TAIL(&event_queue, ev, entry); - if (reentered) { - return; - } - - reentered =3D true; - - while ((ev =3D QSIMPLEQ_FIRST(&event_queue)) !=3D NULL) { - QSIMPLEQ_REMOVE_HEAD(&event_queue, entry); - monitor_qapi_event_queue_no_reenter(ev->event, ev->qdict); - qobject_unref(ev->qdict); - g_free(ev); - } - - reentered =3D false; -} - -/* - * This function runs evconf->rate ns after sending a throttled - * event. - * If another event has since been stored, send it. - */ -static void monitor_qapi_event_handler(void *opaque) -{ - MonitorQAPIEventState *evstate =3D opaque; - MonitorQAPIEventConf *evconf =3D &monitor_qapi_event_conf[evstate->eve= nt]; - - trace_monitor_protocol_event_handler(evstate->event, evstate->qdict); - qemu_mutex_lock(&monitor_lock); - - if (evstate->qdict) { - int64_t now =3D qemu_clock_get_ns(monitor_get_event_clock()); - - monitor_qapi_event_emit(evstate->event, evstate->qdict); - qobject_unref(evstate->qdict); - evstate->qdict =3D NULL; - timer_mod_ns(evstate->timer, now + evconf->rate); - } else { - g_hash_table_remove(monitor_qapi_event_state, evstate); - qobject_unref(evstate->data); - timer_free(evstate->timer); - g_free(evstate); - } - - qemu_mutex_unlock(&monitor_lock); -} - -static unsigned int qapi_event_throttle_hash(const void *key) -{ - const MonitorQAPIEventState *evstate =3D key; - unsigned int hash =3D evstate->event * 255; - - if (evstate->event =3D=3D QAPI_EVENT_VSERPORT_CHANGE) { - hash +=3D g_str_hash(qdict_get_str(evstate->data, "id")); - } - - if (evstate->event =3D=3D QAPI_EVENT_QUORUM_REPORT_BAD) { - hash +=3D g_str_hash(qdict_get_str(evstate->data, "node-name")); - } - - return hash; -} - -static gboolean qapi_event_throttle_equal(const void *a, const void *b) -{ - const MonitorQAPIEventState *eva =3D a; - const MonitorQAPIEventState *evb =3D b; - - if (eva->event !=3D evb->event) { - return FALSE; - } - - if (eva->event =3D=3D QAPI_EVENT_VSERPORT_CHANGE) { - return !strcmp(qdict_get_str(eva->data, "id"), - qdict_get_str(evb->data, "id")); - } - - if (eva->event =3D=3D QAPI_EVENT_QUORUM_REPORT_BAD) { - return !strcmp(qdict_get_str(eva->data, "node-name"), - qdict_get_str(evb->data, "node-name")); - } - - return TRUE; -} - -static void monitor_qapi_event_init(void) -{ - monitor_qapi_event_state =3D g_hash_table_new(qapi_event_throttle_hash, - qapi_event_throttle_equal); -} - -static void monitor_iothread_init(void); - -void monitor_data_init(Monitor *mon, int flags, bool skip_flush, - bool use_io_thread) -{ - if (use_io_thread && !mon_iothread) { - monitor_iothread_init(); - } - qemu_mutex_init(&mon->mon_lock); - mon->outbuf =3D qstring_new(); - mon->skip_flush =3D skip_flush; - mon->use_io_thread =3D use_io_thread; - mon->flags =3D flags; -} - -static void monitor_data_destroy(Monitor *mon) -{ - g_free(mon->mon_cpu_path); - qemu_chr_fe_deinit(&mon->chr, false); - if (monitor_is_qmp(mon)) { - MonitorQMP *qmp_mon =3D container_of(mon, MonitorQMP, common); - monitor_data_destroy_qmp(qmp_mon); - } else { - MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); - readline_free(hmp_mon->rs); - } - qobject_unref(mon->outbuf); - qemu_mutex_destroy(&mon->mon_lock); -} - char *qmp_human_monitor_command(const char *command_line, bool has_cpu_ind= ex, int64_t cpu_index, Error **errp) { @@ -2742,67 +2327,6 @@ void loadvm_completion(ReadLineState *rs, int nb_arg= s, const char *str) } } =20 -int monitor_can_read(void *opaque) -{ - Monitor *mon =3D opaque; - - return !atomic_mb_read(&mon->suspend_cnt); -} - -int monitor_suspend(Monitor *mon) -{ - if (monitor_is_hmp_non_interactive(mon)) { - return -ENOTTY; - } - - atomic_inc(&mon->suspend_cnt); - - if (mon->use_io_thread) { - /* - * Kick I/O thread to make sure this takes effect. It'll be - * evaluated again in prepare() of the watch object. - */ - aio_notify(iothread_get_aio_context(mon_iothread)); - } - - trace_monitor_suspend(mon, 1); - return 0; -} - -static void monitor_accept_input(void *opaque) -{ - Monitor *mon =3D opaque; - - qemu_chr_fe_accept_input(&mon->chr); -} - -void monitor_resume(Monitor *mon) -{ - if (monitor_is_hmp_non_interactive(mon)) { - return; - } - - if (atomic_dec_fetch(&mon->suspend_cnt) =3D=3D 0) { - AioContext *ctx; - - if (mon->use_io_thread) { - ctx =3D iothread_get_aio_context(mon_iothread); - } else { - ctx =3D qemu_get_aio_context(); - } - - if (!monitor_is_qmp(mon)) { - MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); - assert(hmp_mon->rs); - readline_show_prompt(hmp_mon->rs); - } - - aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon); - } - - trace_monitor_suspend(mon, -1); -} - static int compare_mon_cmd(const void *a, const void *b) { @@ -2822,135 +2346,14 @@ static void sortcmdlist(void) qsort((void *)hmp_info_cmds, array_num, elem_size, compare_mon_cmd); } =20 -static void monitor_iothread_init(void) -{ - mon_iothread =3D iothread_create("mon_iothread", &error_abort); -} - void monitor_init_globals(void) { + monitor_init_globals_core(); monitor_init_qmp_commands(); - monitor_qapi_event_init(); sortcmdlist(); - qemu_mutex_init(&monitor_lock); qemu_mutex_init(&mon_fdsets_lock); - - /* - * The dispatcher BH must run in the main loop thread, since we - * have commands assuming that context. It would be nice to get - * rid of those assumptions. - */ - qmp_dispatcher_bh =3D aio_bh_new(iohandler_get_aio_context(), - monitor_qmp_bh_dispatcher, - NULL); -} - -/* - * Print to current monitor if we have one, else to stderr. - */ -int error_vprintf(const char *fmt, va_list ap) -{ - if (cur_mon && !monitor_cur_is_qmp()) { - return monitor_vprintf(cur_mon, fmt, ap); - } - return vfprintf(stderr, fmt, ap); -} - -int error_vprintf_unless_qmp(const char *fmt, va_list ap) -{ - if (!cur_mon) { - return vfprintf(stderr, fmt, ap); - } - if (!monitor_cur_is_qmp()) { - return monitor_vprintf(cur_mon, fmt, ap); - } - return -1; -} - -void monitor_list_append(Monitor *mon) -{ - qemu_mutex_lock(&monitor_lock); - /* - * This prevents inserting new monitors during monitor_cleanup(). - * A cleaner solution would involve the main thread telling other - * threads to terminate, waiting for their termination. - */ - if (!monitor_destroyed) { - QTAILQ_INSERT_HEAD(&mon_list, mon, entry); - mon =3D NULL; - } - qemu_mutex_unlock(&monitor_lock); - - if (mon) { - monitor_data_destroy(mon); - g_free(mon); - } -} - -void monitor_init(Chardev *chr, int flags) -{ - if (flags & MONITOR_USE_CONTROL) { - monitor_init_qmp(chr, flags); - } else { - monitor_init_hmp(chr, flags); - } } =20 -void monitor_cleanup(void) -{ - /* - * We need to explicitly stop the I/O thread (but not destroy it), - * clean up the monitor resources, then destroy the I/O thread since - * we need to unregister from chardev below in - * monitor_data_destroy(), and chardev is not thread-safe yet - */ - if (mon_iothread) { - iothread_stop(mon_iothread); - } - - /* Flush output buffers and destroy monitors */ - qemu_mutex_lock(&monitor_lock); - monitor_destroyed =3D true; - while (!QTAILQ_EMPTY(&mon_list)) { - Monitor *mon =3D QTAILQ_FIRST(&mon_list); - QTAILQ_REMOVE(&mon_list, mon, entry); - /* Permit QAPI event emission from character frontend release */ - qemu_mutex_unlock(&monitor_lock); - monitor_flush(mon); - monitor_data_destroy(mon); - qemu_mutex_lock(&monitor_lock); - g_free(mon); - } - qemu_mutex_unlock(&monitor_lock); - - /* QEMUBHs needs to be deleted before destroying the I/O thread */ - qemu_bh_delete(qmp_dispatcher_bh); - qmp_dispatcher_bh =3D NULL; - if (mon_iothread) { - iothread_destroy(mon_iothread); - mon_iothread =3D NULL; - } -} - -QemuOptsList qemu_mon_opts =3D { - .name =3D "mon", - .implied_opt_name =3D "chardev", - .head =3D QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), - .desc =3D { - { - .name =3D "mode", - .type =3D QEMU_OPT_STRING, - },{ - .name =3D "chardev", - .type =3D QEMU_OPT_STRING, - },{ - .name =3D "pretty", - .type =3D QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) { MachineState *ms =3D MACHINE(qdev_get_machine()); diff --git a/monitor/monitor.c b/monitor/monitor.c new file mode 100644 index 0000000000..6802b8e491 --- /dev/null +++ b/monitor/monitor.c @@ -0,0 +1,637 @@ +/* + * QEMU monitor + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included= in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "monitor-internal.h" + +#include "qapi/error.h" +#include "qapi/qapi-emit-events.h" +#include "qapi/qmp/qstring.h" + +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "sysemu/qtest.h" + +#include "trace.h" + +/* + * To prevent flooding clients, events can be throttled. The + * throttling is calculated globally, rather than per-Monitor + * instance. + */ +typedef struct MonitorQAPIEventState { + QAPIEvent event; /* Throttling state for this event type and... */ + QDict *data; /* ... data, see qapi_event_throttle_equal() */ + QEMUTimer *timer; /* Timer for handling delayed events */ + QDict *qdict; /* Delayed event (if any) */ +} MonitorQAPIEventState; + +typedef struct { + int64_t rate; /* Minimum time (in ns) between two events */ +} MonitorQAPIEventConf; + +/* Shared monitor I/O thread */ +IOThread *mon_iothread; + +/* Bottom half to dispatch the requests received from I/O thread */ +QEMUBH *qmp_dispatcher_bh; + +/* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */ +QemuMutex monitor_lock; +static GHashTable *monitor_qapi_event_state; + +MonitorList mon_list; +int mon_refcount; +static bool monitor_destroyed; + +__thread Monitor *cur_mon; + +/** + * Is the current monitor, if any, a QMP monitor? + */ +bool monitor_cur_is_qmp(void) +{ + return cur_mon && monitor_is_qmp(cur_mon); +} + +/** + * Is @mon is using readline? + * Note: not all HMP monitors use readline, e.g., gdbserver has a + * non-interactive HMP monitor, so readline is not used there. + */ +static inline bool monitor_uses_readline(const Monitor *mon) +{ + return mon->flags & MONITOR_USE_READLINE; +} + +static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) +{ + return !monitor_is_qmp(mon) && !monitor_uses_readline(mon); +} + +static void monitor_flush_locked(Monitor *mon); + +static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + Monitor *mon =3D opaque; + + qemu_mutex_lock(&mon->mon_lock); + mon->out_watch =3D 0; + monitor_flush_locked(mon); + qemu_mutex_unlock(&mon->mon_lock); + return FALSE; +} + +/* Caller must hold mon->mon_lock */ +static void monitor_flush_locked(Monitor *mon) +{ + int rc; + size_t len; + const char *buf; + + if (mon->skip_flush) { + return; + } + + buf =3D qstring_get_str(mon->outbuf); + len =3D qstring_get_length(mon->outbuf); + + if (len && !mon->mux_out) { + rc =3D qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len); + if ((rc < 0 && errno !=3D EAGAIN) || (rc =3D=3D len)) { + /* all flushed or error */ + qobject_unref(mon->outbuf); + mon->outbuf =3D qstring_new(); + return; + } + if (rc > 0) { + /* partial write */ + QString *tmp =3D qstring_from_str(buf + rc); + qobject_unref(mon->outbuf); + mon->outbuf =3D tmp; + } + if (mon->out_watch =3D=3D 0) { + mon->out_watch =3D + qemu_chr_fe_add_watch(&mon->chr, G_IO_OUT | G_IO_HUP, + monitor_unblocked, mon); + } + } +} + +void monitor_flush(Monitor *mon) +{ + qemu_mutex_lock(&mon->mon_lock); + monitor_flush_locked(mon); + qemu_mutex_unlock(&mon->mon_lock); +} + +/* flush at every end of line */ +int monitor_puts(Monitor *mon, const char *str) +{ + int i; + char c; + + qemu_mutex_lock(&mon->mon_lock); + for (i =3D 0; str[i]; i++) { + c =3D str[i]; + if (c =3D=3D '\n') { + qstring_append_chr(mon->outbuf, '\r'); + } + qstring_append_chr(mon->outbuf, c); + if (c =3D=3D '\n') { + monitor_flush_locked(mon); + } + } + qemu_mutex_unlock(&mon->mon_lock); + + return i; +} + +int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) +{ + char *buf; + int n; + + if (!mon) { + return -1; + } + + if (monitor_is_qmp(mon)) { + return -1; + } + + buf =3D g_strdup_vprintf(fmt, ap); + n =3D monitor_puts(mon, buf); + g_free(buf); + return n; +} + +int monitor_printf(Monitor *mon, const char *fmt, ...) +{ + int ret; + + va_list ap; + va_start(ap, fmt); + ret =3D monitor_vprintf(mon, fmt, ap); + va_end(ap); + return ret; +} + +/* + * Print to current monitor if we have one, else to stderr. + */ +int error_vprintf(const char *fmt, va_list ap) +{ + if (cur_mon && !monitor_cur_is_qmp()) { + return monitor_vprintf(cur_mon, fmt, ap); + } + return vfprintf(stderr, fmt, ap); +} + +int error_vprintf_unless_qmp(const char *fmt, va_list ap) +{ + if (!cur_mon) { + return vfprintf(stderr, fmt, ap); + } + if (!monitor_cur_is_qmp()) { + return monitor_vprintf(cur_mon, fmt, ap); + } + return -1; +} + + +static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] =3D { + /* Limit guest-triggerable events to 1 per second */ + [QAPI_EVENT_RTC_CHANGE] =3D { 1000 * SCALE_MS }, + [QAPI_EVENT_WATCHDOG] =3D { 1000 * SCALE_MS }, + [QAPI_EVENT_BALLOON_CHANGE] =3D { 1000 * SCALE_MS }, + [QAPI_EVENT_QUORUM_REPORT_BAD] =3D { 1000 * SCALE_MS }, + [QAPI_EVENT_QUORUM_FAILURE] =3D { 1000 * SCALE_MS }, + [QAPI_EVENT_VSERPORT_CHANGE] =3D { 1000 * SCALE_MS }, +}; + +/* + * Return the clock to use for recording an event's time. + * It's QEMU_CLOCK_REALTIME, except for qtests it's + * QEMU_CLOCK_VIRTUAL, to support testing rate limits. + * Beware: result is invalid before configure_accelerator(). + */ +static inline QEMUClockType monitor_get_event_clock(void) +{ + return qtest_enabled() ? QEMU_CLOCK_VIRTUAL : QEMU_CLOCK_REALTIME; +} + +/* + * Broadcast an event to all monitors. + * @qdict is the event object. Its member "event" must match @event. + * Caller must hold monitor_lock. + */ +static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) +{ + Monitor *mon; + MonitorQMP *qmp_mon; + + trace_monitor_protocol_event_emit(event, qdict); + QTAILQ_FOREACH(mon, &mon_list, entry) { + if (!monitor_is_qmp(mon)) { + continue; + } + + qmp_mon =3D container_of(mon, MonitorQMP, common); + if (qmp_mon->commands !=3D &qmp_cap_negotiation_commands) { + qmp_send_response(qmp_mon, qdict); + } + } +} + +static void monitor_qapi_event_handler(void *opaque); + +/* + * Queue a new event for emission to Monitor instances, + * applying any rate limiting if required. + */ +static void +monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict) +{ + MonitorQAPIEventConf *evconf; + MonitorQAPIEventState *evstate; + + assert(event < QAPI_EVENT__MAX); + evconf =3D &monitor_qapi_event_conf[event]; + trace_monitor_protocol_event_queue(event, qdict, evconf->rate); + + qemu_mutex_lock(&monitor_lock); + + if (!evconf->rate) { + /* Unthrottled event */ + monitor_qapi_event_emit(event, qdict); + } else { + QDict *data =3D qobject_to(QDict, qdict_get(qdict, "data")); + MonitorQAPIEventState key =3D { .event =3D event, .data =3D data }; + + evstate =3D g_hash_table_lookup(monitor_qapi_event_state, &key); + assert(!evstate || timer_pending(evstate->timer)); + + if (evstate) { + /* + * Timer is pending for (at least) evconf->rate ns after + * last send. Store event for sending when timer fires, + * replacing a prior stored event if any. + */ + qobject_unref(evstate->qdict); + evstate->qdict =3D qobject_ref(qdict); + } else { + /* + * Last send was (at least) evconf->rate ns ago. + * Send immediately, and arm the timer to call + * monitor_qapi_event_handler() in evconf->rate ns. Any + * events arriving before then will be delayed until then. + */ + int64_t now =3D qemu_clock_get_ns(monitor_get_event_clock()); + + monitor_qapi_event_emit(event, qdict); + + evstate =3D g_new(MonitorQAPIEventState, 1); + evstate->event =3D event; + evstate->data =3D qobject_ref(data); + evstate->qdict =3D NULL; + evstate->timer =3D timer_new_ns(monitor_get_event_clock(), + monitor_qapi_event_handler, + evstate); + g_hash_table_add(monitor_qapi_event_state, evstate); + timer_mod_ns(evstate->timer, now + evconf->rate); + } + } + + qemu_mutex_unlock(&monitor_lock); +} + +void qapi_event_emit(QAPIEvent event, QDict *qdict) +{ + /* + * monitor_qapi_event_queue_no_reenter() is not reentrant: it + * would deadlock on monitor_lock. Work around by queueing + * events in thread-local storage. + * TODO: remove this, make it re-enter safe. + */ + typedef struct MonitorQapiEvent { + QAPIEvent event; + QDict *qdict; + QSIMPLEQ_ENTRY(MonitorQapiEvent) entry; + } MonitorQapiEvent; + static __thread QSIMPLEQ_HEAD(, MonitorQapiEvent) event_queue; + static __thread bool reentered; + MonitorQapiEvent *ev; + + if (!reentered) { + QSIMPLEQ_INIT(&event_queue); + } + + ev =3D g_new(MonitorQapiEvent, 1); + ev->qdict =3D qobject_ref(qdict); + ev->event =3D event; + QSIMPLEQ_INSERT_TAIL(&event_queue, ev, entry); + if (reentered) { + return; + } + + reentered =3D true; + + while ((ev =3D QSIMPLEQ_FIRST(&event_queue)) !=3D NULL) { + QSIMPLEQ_REMOVE_HEAD(&event_queue, entry); + monitor_qapi_event_queue_no_reenter(ev->event, ev->qdict); + qobject_unref(ev->qdict); + g_free(ev); + } + + reentered =3D false; +} + +/* + * This function runs evconf->rate ns after sending a throttled + * event. + * If another event has since been stored, send it. + */ +static void monitor_qapi_event_handler(void *opaque) +{ + MonitorQAPIEventState *evstate =3D opaque; + MonitorQAPIEventConf *evconf =3D &monitor_qapi_event_conf[evstate->eve= nt]; + + trace_monitor_protocol_event_handler(evstate->event, evstate->qdict); + qemu_mutex_lock(&monitor_lock); + + if (evstate->qdict) { + int64_t now =3D qemu_clock_get_ns(monitor_get_event_clock()); + + monitor_qapi_event_emit(evstate->event, evstate->qdict); + qobject_unref(evstate->qdict); + evstate->qdict =3D NULL; + timer_mod_ns(evstate->timer, now + evconf->rate); + } else { + g_hash_table_remove(monitor_qapi_event_state, evstate); + qobject_unref(evstate->data); + timer_free(evstate->timer); + g_free(evstate); + } + + qemu_mutex_unlock(&monitor_lock); +} + +static unsigned int qapi_event_throttle_hash(const void *key) +{ + const MonitorQAPIEventState *evstate =3D key; + unsigned int hash =3D evstate->event * 255; + + if (evstate->event =3D=3D QAPI_EVENT_VSERPORT_CHANGE) { + hash +=3D g_str_hash(qdict_get_str(evstate->data, "id")); + } + + if (evstate->event =3D=3D QAPI_EVENT_QUORUM_REPORT_BAD) { + hash +=3D g_str_hash(qdict_get_str(evstate->data, "node-name")); + } + + return hash; +} + +static gboolean qapi_event_throttle_equal(const void *a, const void *b) +{ + const MonitorQAPIEventState *eva =3D a; + const MonitorQAPIEventState *evb =3D b; + + if (eva->event !=3D evb->event) { + return FALSE; + } + + if (eva->event =3D=3D QAPI_EVENT_VSERPORT_CHANGE) { + return !strcmp(qdict_get_str(eva->data, "id"), + qdict_get_str(evb->data, "id")); + } + + if (eva->event =3D=3D QAPI_EVENT_QUORUM_REPORT_BAD) { + return !strcmp(qdict_get_str(eva->data, "node-name"), + qdict_get_str(evb->data, "node-name")); + } + + return TRUE; +} + +int monitor_suspend(Monitor *mon) +{ + if (monitor_is_hmp_non_interactive(mon)) { + return -ENOTTY; + } + + atomic_inc(&mon->suspend_cnt); + + if (mon->use_io_thread) { + /* + * Kick I/O thread to make sure this takes effect. It'll be + * evaluated again in prepare() of the watch object. + */ + aio_notify(iothread_get_aio_context(mon_iothread)); + } + + trace_monitor_suspend(mon, 1); + return 0; +} + +static void monitor_accept_input(void *opaque) +{ + Monitor *mon =3D opaque; + + qemu_chr_fe_accept_input(&mon->chr); +} + +void monitor_resume(Monitor *mon) +{ + if (monitor_is_hmp_non_interactive(mon)) { + return; + } + + if (atomic_dec_fetch(&mon->suspend_cnt) =3D=3D 0) { + AioContext *ctx; + + if (mon->use_io_thread) { + ctx =3D iothread_get_aio_context(mon_iothread); + } else { + ctx =3D qemu_get_aio_context(); + } + + if (!monitor_is_qmp(mon)) { + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); + assert(hmp_mon->rs); + readline_show_prompt(hmp_mon->rs); + } + + aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon); + } + + trace_monitor_suspend(mon, -1); +} + +int monitor_can_read(void *opaque) +{ + Monitor *mon =3D opaque; + + return !atomic_mb_read(&mon->suspend_cnt); +} + +void monitor_list_append(Monitor *mon) +{ + qemu_mutex_lock(&monitor_lock); + /* + * This prevents inserting new monitors during monitor_cleanup(). + * A cleaner solution would involve the main thread telling other + * threads to terminate, waiting for their termination. + */ + if (!monitor_destroyed) { + QTAILQ_INSERT_HEAD(&mon_list, mon, entry); + mon =3D NULL; + } + qemu_mutex_unlock(&monitor_lock); + + if (mon) { + monitor_data_destroy(mon); + g_free(mon); + } +} + +static void monitor_iothread_init(void) +{ + mon_iothread =3D iothread_create("mon_iothread", &error_abort); +} + +void monitor_data_init(Monitor *mon, int flags, bool skip_flush, + bool use_io_thread) +{ + if (use_io_thread && !mon_iothread) { + monitor_iothread_init(); + } + qemu_mutex_init(&mon->mon_lock); + mon->outbuf =3D qstring_new(); + mon->skip_flush =3D skip_flush; + mon->use_io_thread =3D use_io_thread; + mon->flags =3D flags; +} + +void monitor_data_destroy(Monitor *mon) +{ + g_free(mon->mon_cpu_path); + qemu_chr_fe_deinit(&mon->chr, false); + if (monitor_is_qmp(mon)) { + MonitorQMP *qmp_mon =3D container_of(mon, MonitorQMP, common); + monitor_data_destroy_qmp(qmp_mon); + } else { + MonitorHMP *hmp_mon =3D container_of(mon, MonitorHMP, common); + readline_free(hmp_mon->rs); + } + qobject_unref(mon->outbuf); + qemu_mutex_destroy(&mon->mon_lock); +} + +void monitor_init(Chardev *chr, int flags) +{ + if (flags & MONITOR_USE_CONTROL) { + monitor_init_qmp(chr, flags); + } else { + monitor_init_hmp(chr, flags); + } +} + +void monitor_cleanup(void) +{ + /* + * We need to explicitly stop the I/O thread (but not destroy it), + * clean up the monitor resources, then destroy the I/O thread since + * we need to unregister from chardev below in + * monitor_data_destroy(), and chardev is not thread-safe yet + */ + if (mon_iothread) { + iothread_stop(mon_iothread); + } + + /* Flush output buffers and destroy monitors */ + qemu_mutex_lock(&monitor_lock); + monitor_destroyed =3D true; + while (!QTAILQ_EMPTY(&mon_list)) { + Monitor *mon =3D QTAILQ_FIRST(&mon_list); + QTAILQ_REMOVE(&mon_list, mon, entry); + /* Permit QAPI event emission from character frontend release */ + qemu_mutex_unlock(&monitor_lock); + monitor_flush(mon); + monitor_data_destroy(mon); + qemu_mutex_lock(&monitor_lock); + g_free(mon); + } + qemu_mutex_unlock(&monitor_lock); + + /* QEMUBHs needs to be deleted before destroying the I/O thread */ + qemu_bh_delete(qmp_dispatcher_bh); + qmp_dispatcher_bh =3D NULL; + if (mon_iothread) { + iothread_destroy(mon_iothread); + mon_iothread =3D NULL; + } +} + +static void monitor_qapi_event_init(void) +{ + monitor_qapi_event_state =3D g_hash_table_new(qapi_event_throttle_hash, + qapi_event_throttle_equal); +} + +void monitor_init_globals_core(void) +{ + monitor_qapi_event_init(); + qemu_mutex_init(&monitor_lock); + + /* + * The dispatcher BH must run in the main loop thread, since we + * have commands assuming that context. It would be nice to get + * rid of those assumptions. + */ + qmp_dispatcher_bh =3D aio_bh_new(iohandler_get_aio_context(), + monitor_qmp_bh_dispatcher, + NULL); +} + +QemuOptsList qemu_mon_opts =3D { + .name =3D "mon", + .implied_opt_name =3D "chardev", + .head =3D QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), + .desc =3D { + { + .name =3D "mode", + .type =3D QEMU_OPT_STRING, + },{ + .name =3D "chardev", + .type =3D QEMU_OPT_STRING, + },{ + .name =3D "pretty", + .type =3D QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; diff --git a/MAINTAINERS b/MAINTAINERS index ebb839d305..53c3654494 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1918,6 +1918,7 @@ M: Dr. David Alan Gilbert S: Maintained F: monitor/monitor-internal.h F: monitor/misc.c +F: monitor/monitor.c F: monitor/hmp* F: hmp.h F: hmp-commands*.hx @@ -2042,6 +2043,7 @@ S: Supported F: monitor/monitor-internal.h F: monitor/qmp* F: monitor/misc.c +F: monitor/monitor.c F: docs/devel/*qmp-* F: docs/interop/*qmp-* F: scripts/qmp/ diff --git a/monitor/Makefile.objs b/monitor/Makefile.objs index bea8838acc..e91a8581cd 100644 --- a/monitor/Makefile.objs +++ b/monitor/Makefile.objs @@ -1,3 +1,3 @@ obj-y +=3D misc.o -common-obj-y +=3D qmp.o hmp.o +common-obj-y +=3D monitor.o qmp.o hmp.o common-obj-y +=3D qmp-cmds.o hmp-cmds.o diff --git a/monitor/trace-events b/monitor/trace-events index 2285d26121..0365ac4d99 100644 --- a/monitor/trace-events +++ b/monitor/trace-events @@ -3,7 +3,7 @@ # hmp.c handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" =20 -# misc.c +# monitor.c monitor_protocol_event_handler(uint32_t event, void *qdict) "event=3D%d da= ta=3D%p" monitor_protocol_event_emit(uint32_t event, void *data) "event=3D%d data= =3D%p" monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "= event=3D%d data=3D%p rate=3D%" PRId64 --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560445367; cv=none; d=zoho.com; s=zohoarc; b=LVxFJ2b0i61AlXIobZ4fP4WjDrO3Fui0nv8+iPrz1se/D5nD900YATYna4oMeKpb3GSk8UU0Tg55tch4zNjj/w8QjcXw2abSiM4hKegu5FPL+OxpDBRmxgWvCbEyJBZROceMJ2PVE+JQ21uj6XoP0muVItrb6Bg5TocFTCIA4wI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560445367; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=0vzPXgrHbhYI8PYYZQVlnCM2nFBN9BnqEEjvP8j4/a0=; b=g96U+NFEpd+FCK/HclJNY9IhS6hvtXdcecRRCB1qkmess9iQ4bUBPVhy2AZOneR+aTeg9ZC7TVbsFCxBFcqla1WQyVAatb7nd1zWbzm/0eBNFQUni7m9YnHeiZ4T7wE00nHYB/sNbByclCyDFJkzRA3Q1yqKDor9wf3S0//i7Vo= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560445367252303.73981254045157; Thu, 13 Jun 2019 10:02:47 -0700 (PDT) Received: from localhost ([::1]:41964 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbT7Y-0006gj-Mf for importer@patchew.org; Thu, 13 Jun 2019 13:02:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60243) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRlT-00010q-Jv for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRlR-0003z3-7c for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:12278) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRlG-0003pF-06; Thu, 13 Jun 2019 11:35:34 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6F991C047B7A; Thu, 13 Jun 2019 15:35:26 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8183961980; Thu, 13 Jun 2019 15:35:22 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:34:03 +0200 Message-Id: <20190613153405.24769-14-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 13 Jun 2019 15:35:32 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Monitor.flags contains three different flags: One to distinguish HMP from QMP; one specific to HMP (MONITOR_USE_READLINE) that is ignored with QMP; and another one specific to QMP (MONITOR_USE_PRETTY) that is ignored with HMP. Split the flags field into three bools and move them to the right subclass. Flags are still in use for the monitor_init() interface. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- monitor/monitor-internal.h | 8 +++++--- monitor/hmp.c | 6 +++--- monitor/misc.c | 2 +- monitor/monitor.c | 14 +++++++++----- monitor/qmp.c | 7 ++++--- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 30679d522e..260725e51b 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -90,8 +90,8 @@ typedef struct HMPCommand { struct Monitor { CharBackend chr; int reset_seen; - int flags; int suspend_cnt; /* Needs to be accessed atomically */ + bool is_qmp; bool skip_flush; bool use_io_thread; =20 @@ -116,6 +116,7 @@ struct Monitor { =20 struct MonitorHMP { Monitor common; + bool use_readline; /* * State used only in the thread "owning" the monitor. * If @use_io_thread, this is @mon_iothread. (This does not actually h= appen @@ -129,6 +130,7 @@ struct MonitorHMP { typedef struct { Monitor common; JSONMessageParser parser; + bool pretty; /* * When a client connects, we're in capabilities negotiation mode. * @commands is &qmp_cap_negotiation_commands then. When command @@ -152,7 +154,7 @@ typedef struct { */ static inline bool monitor_is_qmp(const Monitor *mon) { - return (mon->flags & MONITOR_USE_CONTROL); + return mon->is_qmp; } =20 typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList; @@ -169,7 +171,7 @@ void monitor_init_qmp(Chardev *chr, int flags); void monitor_init_hmp(Chardev *chr, int flags); =20 int monitor_puts(Monitor *mon, const char *str); -void monitor_data_init(Monitor *mon, int flags, bool skip_flush, +void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush, bool use_io_thread); void monitor_data_destroy(Monitor *mon); int monitor_can_read(void *opaque); diff --git a/monitor/hmp.c b/monitor/hmp.c index 3621b195ed..5ba8b6e8d5 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -1396,12 +1396,12 @@ static void monitor_readline_flush(void *opaque) void monitor_init_hmp(Chardev *chr, int flags) { MonitorHMP *mon =3D g_malloc0(sizeof(*mon)); - bool use_readline =3D flags & MONITOR_USE_READLINE; =20 - monitor_data_init(&mon->common, flags, false, false); + monitor_data_init(&mon->common, false, false, false); qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); =20 - if (use_readline) { + mon->use_readline =3D flags & MONITOR_USE_READLINE; + if (mon->use_readline) { mon->rs =3D readline_init(monitor_readline_printf, monitor_readline_flush, mon, diff --git a/monitor/misc.c b/monitor/misc.c index dddbddb21f..10c056394e 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -134,7 +134,7 @@ char *qmp_human_monitor_command(const char *command_lin= e, bool has_cpu_index, Monitor *old_mon; MonitorHMP hmp =3D {}; =20 - monitor_data_init(&hmp.common, 0, true, false); + monitor_data_init(&hmp.common, false, true, false); =20 old_mon =3D cur_mon; cur_mon =3D &hmp.common; diff --git a/monitor/monitor.c b/monitor/monitor.c index 6802b8e491..7325e4362b 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -80,14 +80,18 @@ bool monitor_cur_is_qmp(void) * Note: not all HMP monitors use readline, e.g., gdbserver has a * non-interactive HMP monitor, so readline is not used there. */ -static inline bool monitor_uses_readline(const Monitor *mon) +static inline bool monitor_uses_readline(const MonitorHMP *mon) { - return mon->flags & MONITOR_USE_READLINE; + return mon->use_readline; } =20 static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) { - return !monitor_is_qmp(mon) && !monitor_uses_readline(mon); + if (monitor_is_qmp(mon)) { + return false; + } + + return !monitor_uses_readline(container_of(mon, MonitorHMP, common)); } =20 static void monitor_flush_locked(Monitor *mon); @@ -523,17 +527,17 @@ static void monitor_iothread_init(void) mon_iothread =3D iothread_create("mon_iothread", &error_abort); } =20 -void monitor_data_init(Monitor *mon, int flags, bool skip_flush, +void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush, bool use_io_thread) { if (use_io_thread && !mon_iothread) { monitor_iothread_init(); } qemu_mutex_init(&mon->mon_lock); + mon->is_qmp =3D is_qmp; mon->outbuf =3D qstring_new(); mon->skip_flush =3D skip_flush; mon->use_io_thread =3D use_io_thread; - mon->flags =3D flags; } =20 void monitor_data_destroy(Monitor *mon) diff --git a/monitor/qmp.c b/monitor/qmp.c index 31fbcd59f7..3abc718ca3 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -86,8 +86,7 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp) const QObject *data =3D QOBJECT(rsp); QString *json; =20 - json =3D mon->common.flags & MONITOR_USE_PRETTY ? - qobject_to_json_pretty(data) : qobject_to_json(data); + json =3D mon->pretty ? qobject_to_json_pretty(data) : qobject_to_json(= data); assert(json !=3D NULL); =20 qstring_append_chr(json, '\n'); @@ -372,9 +371,11 @@ void monitor_init_qmp(Chardev *chr, int flags) assert(!(flags & MONITOR_USE_READLINE)); =20 /* Note: we run QMP monitor in I/O thread when @chr supports that */ - monitor_data_init(&mon->common, flags, false, + monitor_data_init(&mon->common, true, false, qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); =20 + mon->pretty =3D flags & MONITOR_USE_PRETTY; + qemu_mutex_init(&mon->qmp_queue_lock); mon->qmp_requests =3D g_queue_new(); =20 --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560444827; cv=none; d=zoho.com; s=zohoarc; b=TA1BCLdi5GItuLkQAYSGGrY3tK7ySlFD2e6Ev23EzknrZ4zqKL+1CRcQHztK0V5SkOw9oc/CFATcc8f0jPuTsz3hfKrIQ7kYllNgnuWNjQ0xi3X0xiJk1fnNJtcFBxJ9wfNxJmM7nCj1DAhuRQKkluRRwMzrtxRovi0+VvsmhbU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560444827; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=dH8lehmnMacAKoZA6J+asnu1Oau73+Kk0yN3H15locA=; b=IfbShK/nVVXk72jr6gonP1fiSh5c39/ILPbSYXeOPcIOFUIiuN8xGEaano6Lj9HA9W67JDwFH/pT9QoVPMSUlLG3uEq4kvw9YXFGmUmAIhlpfMvDi4aF/I/h2bgSGAPuiE3jw8VMpuZahRSK+W3AFLtj3lfGJOXiebcdxuETOg0= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560444827397992.608863894474; Thu, 13 Jun 2019 09:53:47 -0700 (PDT) Received: from localhost ([::1]:41795 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSyt-00076f-DI for importer@patchew.org; Thu, 13 Jun 2019 12:53:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60226) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRlR-0000zn-8p for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRlK-0003uU-D0 for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:35:42 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57266) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRlE-0003mp-0Y; Thu, 13 Jun 2019 11:35:32 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 492A46E76B; Thu, 13 Jun 2019 15:35:28 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id BBAD760C7F; Thu, 13 Jun 2019 15:35:26 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:34:04 +0200 Message-Id: <20190613153405.24769-15-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Thu, 13 Jun 2019 15:35:28 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Most callers know which monitor type they want to have. Instead of calling monitor_init() with flags that can describe both types of monitors, make monitor_init_{hmp,qmp}() public interfaces that take specific bools instead of flags and call these functions directly. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- include/monitor/monitor.h | 9 ++------- monitor/monitor-internal.h | 3 --- chardev/char.c | 2 +- gdbstub.c | 2 +- monitor/hmp.c | 4 ++-- monitor/monitor.c | 9 --------- monitor/qmp.c | 7 ++----- stubs/monitor.c | 6 +++++- tests/test-util-sockets.c | 3 ++- vl.c | 18 ++++++++++++------ 10 files changed, 27 insertions(+), 36 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index af5ddbe785..6e64f062db 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -8,19 +8,14 @@ extern __thread Monitor *cur_mon; typedef struct MonitorHMP MonitorHMP; =20 -/* flags for monitor_init */ -/* 0x01 unused */ -#define MONITOR_USE_READLINE 0x02 -#define MONITOR_USE_CONTROL 0x04 -#define MONITOR_USE_PRETTY 0x08 - #define QMP_REQ_QUEUE_LEN_MAX 8 =20 bool monitor_cur_is_qmp(void); =20 void monitor_init_globals(void); void monitor_init_globals_core(void); -void monitor_init(Chardev *chr, int flags); +void monitor_init_qmp(Chardev *chr, bool pretty); +void monitor_init_hmp(Chardev *chr, bool use_readline); void monitor_cleanup(void); =20 int monitor_suspend(Monitor *mon); diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 260725e51b..333ebf89e4 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -167,9 +167,6 @@ extern int mon_refcount; =20 extern HMPCommand hmp_cmds[]; =20 -void monitor_init_qmp(Chardev *chr, int flags); -void monitor_init_hmp(Chardev *chr, int flags); - int monitor_puts(Monitor *mon, const char *str); void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush, bool use_io_thread); diff --git a/chardev/char.c b/chardev/char.c index e4887bcc82..7b6b2cb123 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -731,7 +731,7 @@ Chardev *qemu_chr_new_noreplay(const char *label, const= char *filename, =20 if (qemu_opt_get_bool(opts, "mux", 0)) { assert(permit_mux_mon); - monitor_init(chr, MONITOR_USE_READLINE); + monitor_init_hmp(chr, true); } =20 out: diff --git a/gdbstub.c b/gdbstub.c index 17dcd9186d..939134eec9 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2565,7 +2565,7 @@ int gdbserver_start(const char *device) /* Initialize a monitor terminal for gdb */ mon_chr =3D qemu_chardev_new(NULL, TYPE_CHARDEV_GDB, NULL, NULL, &error_abort); - monitor_init(mon_chr, 0); + monitor_init_hmp(mon_chr, false); } else { qemu_chr_fe_deinit(&s->chr, true); mon_chr =3D s->mon_chr; diff --git a/monitor/hmp.c b/monitor/hmp.c index 5ba8b6e8d5..43185a7445 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -1393,14 +1393,14 @@ static void monitor_readline_flush(void *opaque) monitor_flush(&mon->common); } =20 -void monitor_init_hmp(Chardev *chr, int flags) +void monitor_init_hmp(Chardev *chr, bool use_readline) { MonitorHMP *mon =3D g_malloc0(sizeof(*mon)); =20 monitor_data_init(&mon->common, false, false, false); qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); =20 - mon->use_readline =3D flags & MONITOR_USE_READLINE; + mon->use_readline =3D use_readline; if (mon->use_readline) { mon->rs =3D readline_init(monitor_readline_printf, monitor_readline_flush, diff --git a/monitor/monitor.c b/monitor/monitor.c index 7325e4362b..01d8fb5d30 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -555,15 +555,6 @@ void monitor_data_destroy(Monitor *mon) qemu_mutex_destroy(&mon->mon_lock); } =20 -void monitor_init(Chardev *chr, int flags) -{ - if (flags & MONITOR_USE_CONTROL) { - monitor_init_qmp(chr, flags); - } else { - monitor_init_hmp(chr, flags); - } -} - void monitor_cleanup(void) { /* diff --git a/monitor/qmp.c b/monitor/qmp.c index 3abc718ca3..7258f2b088 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -363,18 +363,15 @@ static void monitor_qmp_setup_handlers_bh(void *opaqu= e) monitor_list_append(&mon->common); } =20 -void monitor_init_qmp(Chardev *chr, int flags) +void monitor_init_qmp(Chardev *chr, bool pretty) { MonitorQMP *mon =3D g_malloc0(sizeof(*mon)); =20 - /* Only HMP supports readline */ - assert(!(flags & MONITOR_USE_READLINE)); - /* Note: we run QMP monitor in I/O thread when @chr supports that */ monitor_data_init(&mon->common, true, false, qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT= )); =20 - mon->pretty =3D flags & MONITOR_USE_PRETTY; + mon->pretty =3D pretty; =20 qemu_mutex_init(&mon->qmp_queue_lock); mon->qmp_requests =3D g_queue_new(); diff --git a/stubs/monitor.c b/stubs/monitor.c index cdbf5c5f9a..c3e9a2e4dc 100644 --- a/stubs/monitor.c +++ b/stubs/monitor.c @@ -16,7 +16,11 @@ int monitor_get_fd(Monitor *mon, const char *name, Error= **errp) return -1; } =20 -void monitor_init(Chardev *chr, int flags) +void monitor_init_qmp(Chardev *chr, bool pretty) +{ +} + +void monitor_init_hmp(Chardev *chr, bool use_readline) { } =20 diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index fd1ced058c..f1ebffee5a 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -71,7 +71,8 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Erro= r **errp) */ __thread Monitor *cur_mon; int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } -void monitor_init(Chardev *chr, int flags) {} +void monitor_init_qmp(Chardev *chr, bool pretty) {} +void monitor_init_hmp(Chardev *chr, bool use_readline) {} =20 =20 static void test_socket_fd_pass_name_good(void) diff --git a/vl.c b/vl.c index 005468cbfb..32daa434eb 100644 --- a/vl.c +++ b/vl.c @@ -2299,25 +2299,27 @@ static int fsdev_init_func(void *opaque, QemuOpts *= opts, Error **errp) static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp) { Chardev *chr; + bool qmp; + bool pretty =3D false; const char *chardev; const char *mode; - int flags; =20 mode =3D qemu_opt_get(opts, "mode"); if (mode =3D=3D NULL) { mode =3D "readline"; } if (strcmp(mode, "readline") =3D=3D 0) { - flags =3D MONITOR_USE_READLINE; + qmp =3D false; } else if (strcmp(mode, "control") =3D=3D 0) { - flags =3D MONITOR_USE_CONTROL; + qmp =3D true; } else { error_setg(errp, "unknown monitor mode \"%s\"", mode); return -1; } =20 - if (qemu_opt_get_bool(opts, "pretty", 0)) - flags |=3D MONITOR_USE_PRETTY; + if (qemu_opt_get_bool(opts, "pretty", 0)) { + pretty =3D true; + } =20 chardev =3D qemu_opt_get(opts, "chardev"); if (!chardev) { @@ -2330,7 +2332,11 @@ static int mon_init_func(void *opaque, QemuOpts *opt= s, Error **errp) return -1; } =20 - monitor_init(chr, flags); + if (qmp) { + monitor_init_qmp(chr, pretty); + } else { + monitor_init_hmp(chr, true); + } return 0; } =20 --=20 2.20.1 From nobody Tue Apr 30 03:14:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1560443703; cv=none; d=zoho.com; s=zohoarc; b=jJu3+LvwEKA7t4VNZJ4uaO/o89GtpjRK8C6IlFkcJLGpf1NR/g3cyvOiZodXrJF3Z3EjM9a21so2XfZuc7FI3JzFqdJXctIS/kdahW/vzm7VcZr9NmQGkbFmWoekspD92wPbmrhAvC4okKevcjBsO4SIpBL9pNiBzzfmL0aYCxc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560443703; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=802nGfkFHZQdbfwXwyJ/kLg3ftiLi810HJgkq91rpLE=; b=WqOez8yZF4SowbAMh8rrNLHdh3Df+N2v8F/xHUq/7NRzhFDy8qII56S9YHJ1onbDaOnIqDv8UanANUeyRJRsvzIn+eV6NO2BjjMwBSijwdBz3Sz9hXWWVgktd2Dd/QpsS5NPFghWKDWlz+dvcMgZqblhTCv0AdsmPTCqYCRd/30= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 15604437034761017.0745630776314; Thu, 13 Jun 2019 09:35:03 -0700 (PDT) Received: from localhost ([::1]:41544 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbSgl-0006KH-C6 for importer@patchew.org; Thu, 13 Jun 2019 12:34:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60379) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbRlp-00013z-I7 for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:36:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbRln-0004Fo-II for qemu-devel@nongnu.org; Thu, 13 Jun 2019 11:36:09 -0400 Received: from mx1.redhat.com ([209.132.183.28]:45980) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hbRlU-00041M-Df; Thu, 13 Jun 2019 11:35:49 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9D7362EF16E; Thu, 13 Jun 2019 15:35:34 +0000 (UTC) Received: from linux.fritz.box.com (ovpn-116-246.ams2.redhat.com [10.36.116.246]) by smtp.corp.redhat.com (Postfix) with ESMTP id 16AAF60C7F; Thu, 13 Jun 2019 15:35:30 +0000 (UTC) From: Kevin Wolf To: qemu-devel@nongnu.org Date: Thu, 13 Jun 2019 17:34:05 +0200 Message-Id: <20190613153405.24769-16-kwolf@redhat.com> In-Reply-To: <20190613153405.24769-1-kwolf@redhat.com> References: <20190613153405.24769-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Thu, 13 Jun 2019 15:35:42 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, berrange@redhat.com, qemu-block@nongnu.org, armbru@redhat.com, dgilbert@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" The -mon pretty=3Don|off switch of the -mon option applies only the QMP monitors. It used to be silently ignored for HMP. Deprecate this combination so that we can make it an error in future versions. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- vl.c | 10 +++++++++- qemu-deprecated.texi | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 32daa434eb..99a56b5556 100644 --- a/vl.c +++ b/vl.c @@ -2317,6 +2317,10 @@ static int mon_init_func(void *opaque, QemuOpts *opt= s, Error **errp) return -1; } =20 + if (!qmp && qemu_opt_get(opts, "pretty")) { + warn_report("'pretty' is deprecated for HMP monitors, it has no ef= fect " + "and will be removed in future versions"); + } if (qemu_opt_get_bool(opts, "pretty", 0)) { pretty =3D true; } @@ -2362,7 +2366,11 @@ static void monitor_parse(const char *optarg, const = char *mode, bool pretty) opts =3D qemu_opts_create(qemu_find_opts("mon"), label, 1, &error_fata= l); qemu_opt_set(opts, "mode", mode, &error_abort); qemu_opt_set(opts, "chardev", label, &error_abort); - qemu_opt_set_bool(opts, "pretty", pretty, &error_abort); + if (!strcmp(mode, "control")) { + qemu_opt_set_bool(opts, "pretty", pretty, &error_abort); + } else { + assert(pretty =3D=3D false); + } monitor_device_index++; } =20 diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index 50292d820b..df04f2840b 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -72,6 +72,12 @@ backend settings instead of environment variables. To e= ase migration to the new format, the ``-audiodev-help'' option can be used to convert the current values of the environment variables to ``-audiodev'' options. =20 +@subsection -mon ...,control=3Dreadline,pretty=3Don|off (since 4.1) + +The @code{pretty=3Don|off} switch has no effect for HMP monitors, but is +silently ignored. Using the switch with HMP monitors will become an +error in the future. + @subsection -realtime (since 4.1) =20 The @code{-realtime mlock=3Don|off} argument has been replaced by the --=20 2.20.1