All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
@ 2019-06-13 15:33 Kevin Wolf
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 01/15] monitor: Remove unused password prompting fields Kevin Wolf
                   ` (16 more replies)
  0 siblings, 17 replies; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

monitor.c mixes a lot of different things in a single file: The core
monitor infrastructure, HMP infrastrcture, QMP infrastructure, and the
implementation of several HMP and QMP commands. Almost worse, struct
Monitor mixes state for HMP, for QMP, and state actually shared between
all monitors. monitor.c must be linked with a system emulator and even
requires per-target compilation because some of the commands it
implements access system emulator state.

The reason why I care about this is that I'm working on a protoype for a
storage daemon, which wants to use QMP (but probably not HMP) and
obviously doesn't have any system emulator state. So I'm interested in
some core monitor parts that can be linked to non-system-emulator tools.

This series first creates separate structs MonitorQMP and MonitorHMP
which inherit from Monitor, and then moves the associated infrastructure
code into separate source files.

While the split is probably not perfect, I think it's an improvement of
the current state even for QEMU proper, and it's good enough so I can
link my storage daemon against just monitor/core.o and monitor/qmp.o and
get a useless QMP monitor that parses the JSON input and rejects
everything as an unknown command.

Next I'll try to teach it a subset of QMP commands that can actually be
supported in a tool, but while there will be a few follow-up patches to
achieve this, I don't expect that this work will bring up much that
needs to be changed in the splitting process done in this series.

v3:
- Assert monitor_is_qmp() before casting to MonitorQMP in two places
- Added note that HMP doesn't currently use iothread to the
  documentation of MonitorHMP
- Removed unnecessary memset() in monitor_data_init()
- Removed Monitor.cmd_table instead of moving it to MonitorHMP. Renamed
  the tables to have an hmp_ prefix.
- monitor_int.h of v2 becomes monitor-internal.h now
- Cleaned up #include directives in new files
- Moved some more functions between files
- Removed monitor_init() in favour of public monitor_init_hmp/qmp()
- Deprecate -mon control=readline,pretty=on|off
- Improved several commit messages

v2:
- Fix coding style while moving files to make checkpatch happier
- Updated file name references in docs/devel/writing-qmp-commands.txt
- Updated MAINTAINERS for moved and newly created files
- Created monitor/trace-events instead of using the root directory one
- Move {hmp,qmp}.c to monitor/{hmp,qmp}-cmds.c

Kevin Wolf (15):
  monitor: Remove unused password prompting fields
  monitor: Split monitor_init in HMP and QMP function
  monitor: Make MonitorQMP a child class of Monitor
  monitor: Create MonitorHMP with readline state
  monitor: Remove Monitor.cmd_table indirection
  monitor: Rename HMP command type and tables
  Move monitor.c to monitor/misc.c
  monitor: Move {hmp,qmp}.c to monitor/{hmp,qmp}-cmds.c
  monitor: Create monitor-internal.h with common definitions
  monitor: Split out monitor/qmp.c
  monitor: Split out monitor/hmp.c
  monitor: Split out monitor/monitor.c
  monitor: Split Monitor.flags into separate bools
  monitor: Replace monitor_init() with monitor_init_{hmp,qmp}()
  vl: Deprecate -mon pretty=... for HMP monitors

 docs/devel/writing-qmp-commands.txt |   11 +-
 include/monitor/monitor.h           |   15 +-
 monitor/monitor-internal.h          |  187 ++
 chardev/char.c                      |    2 +-
 gdbstub.c                           |    2 +-
 monitor.c                           | 4729 ---------------------------
 hmp.c => monitor/hmp-cmds.c         |    6 +-
 monitor/hmp.c                       | 1415 ++++++++
 monitor/misc.c                      | 2368 ++++++++++++++
 monitor/monitor.c                   |  632 ++++
 qmp.c => monitor/qmp-cmds.c         |    2 +-
 monitor/qmp.c                       |  403 +++
 stubs/monitor.c                     |    6 +-
 tests/test-util-sockets.c           |    3 +-
 vl.c                                |   28 +-
 MAINTAINERS                         |   13 +-
 Makefile.objs                       |    4 +-
 Makefile.target                     |    3 +-
 hmp-commands.hx                     |    2 +-
 monitor/Makefile.objs               |    3 +
 monitor/trace-events                |   15 +
 qemu-deprecated.texi                |    6 +
 trace-events                        |   10 -
 23 files changed, 5091 insertions(+), 4774 deletions(-)
 create mode 100644 monitor/monitor-internal.h
 delete mode 100644 monitor.c
 rename hmp.c => monitor/hmp-cmds.c (99%)
 create mode 100644 monitor/hmp.c
 create mode 100644 monitor/misc.c
 create mode 100644 monitor/monitor.c
 rename qmp.c => monitor/qmp-cmds.c (99%)
 create mode 100644 monitor/qmp.c
 create mode 100644 monitor/Makefile.objs
 create mode 100644 monitor/trace-events

-- 
2.20.1



^ permalink raw reply	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 01/15] monitor: Remove unused password prompting fields
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 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 {
 
     MonitorQMP qmp;
     gchar *mon_cpu_path;
-    BlockCompletionFunc *password_completion_cb;
-    void *password_opaque;
     mon_cmd_t *cmd_table;
     QTAILQ_ENTRY(Monitor) entry;
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 01/15] monitor: Remove unused password prompting fields Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  8:51   ` Markus Armbruster
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 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);
 
 static void monitor_iothread_init(void);
 
-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_flush,
     mon->skip_flush = skip_flush;
     mon->use_io_thread = use_io_thread;
     mon->qmp.qmp_requests = g_queue_new();
+    mon->flags = flags;
 }
 
 static void monitor_data_destroy(Monitor *mon)
@@ -742,7 +743,7 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     char *output = NULL;
     Monitor *old_mon, hmp;
 
-    monitor_data_init(&hmp, true, false);
+    monitor_data_init(&hmp, 0, true, false);
 
     old_mon = cur_mon;
     cur_mon = &hmp;
@@ -4605,19 +4606,51 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
     monitor_list_append(mon);
 }
 
-void monitor_init(Chardev *chr, int flags)
+static void monitor_init_qmp(Chardev *chr, int flags)
 {
     Monitor *mon = g_malloc(sizeof(*mon));
-    bool use_readline = flags & MONITOR_USE_READLINE;
+
+    /* 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, 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));
 
     qemu_chr_fe_init(&mon->chr, chr, &error_abort);
-    mon->flags = flags;
+    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=on.
+         */
+        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 = g_malloc(sizeof(*mon));
+    bool use_readline = 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 = readline_init(monitor_readline_printf,
                                 monitor_readline_flush,
@@ -4626,36 +4659,18 @@ void monitor_init(Chardev *chr, int flags)
         monitor_read_command(mon, 0);
     }
 
-    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=on.
-             */
-            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);
 }
 
 void monitor_cleanup(void)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 01/15] monitor: Remove unused password prompting fields Kevin Wolf
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  8:54   ` Markus Armbruster
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state Kevin Wolf
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 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;
 };
 
-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;
 
-    MonitorQMP qmp;
     gchar *mon_cpu_path;
     mon_cmd_t *cmd_table;
     QTAILQ_ENTRY(Monitor) entry;
@@ -241,6 +220,27 @@ struct Monitor {
     int mux_out;
 };
 
+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;
 
@@ -249,7 +249,7 @@ QEMUBH *qmp_dispatcher_bh;
 
 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)
 }
 
 /* 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));
     }
 }
 
-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);
 }
 
 
@@ -480,17 +480,17 @@ int monitor_printf(Monitor *mon, const char *fmt, ...)
     return ret;
 }
 
-static void qmp_send_response(Monitor *mon, const QDict *rsp)
+static void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
 {
     const QObject *data = QOBJECT(rsp);
     QString *json;
 
-    json = mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data) :
-                                             qobject_to_json(data);
+    json = mon->common.flags & MONITOR_USE_PRETTY ?
+           qobject_to_json_pretty(data) : qobject_to_json(data);
     assert(json != NULL);
 
     qstring_append_chr(json, '\n');
-    monitor_puts(mon, qstring_get_str(json));
+    monitor_puts(&mon->common, qstring_get_str(json));
 
     qobject_unref(json);
 }
@@ -513,12 +513,17 @@ static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
 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)
-            && mon->qmp.commands != &qmp_cap_negotiation_commands) {
-            qmp_send_response(mon, qdict);
+        if (!monitor_is_qmp(mon)) {
+            continue;
+        }
+
+        qmp_mon = container_of(mon, MonitorQMP, common);
+        if (qmp_mon->commands != &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 = qstring_new();
     /* Use *mon_cmds by default. */
     mon->cmd_table = mon_cmds;
     mon->skip_flush = skip_flush;
     mon->use_io_thread = use_io_thread;
-    mon->qmp.qmp_requests = g_queue_new();
     mon->flags = flags;
 }
 
+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 = 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);
 }
 
 char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
@@ -1087,8 +1096,12 @@ static void query_commands_cb(QmpCommand *cmd, void *opaque)
 CommandInfoList *qmp_query_commands(Error **errp)
 {
     CommandInfoList *list = NULL;
+    MonitorQMP *mon;
+
+    assert(monitor_is_qmp(cur_mon));
+    mon = container_of(cur_mon, MonitorQMP, common);
 
-    qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
+    qmp_for_each_command(mon->commands, query_commands_cb, &list);
 
     return list;
 }
@@ -1155,16 +1168,16 @@ static void monitor_init_qmp_commands(void)
                          qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
 }
 
-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];
 }
 
-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] = 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] = mon->common.use_io_thread;
 }
 
 /*
@@ -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 = NULL;
@@ -1181,7 +1194,7 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
     memset(capab, 0, sizeof(capab));
 
     for (; list; list = list->next) {
-        if (!mon->qmp.capab_offered[list->value]) {
+        if (!mon->capab_offered[list->value]) {
             if (!unavailable) {
                 unavailable = g_string_new(QMPCapability_str(list->value));
             } else {
@@ -1198,25 +1211,30 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
         return false;
     }
 
-    memcpy(mon->qmp.capab, capab, sizeof(capab));
+    memcpy(mon->capab, capab, sizeof(capab));
     return true;
 }
 
 void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
                           Error **errp)
 {
-    if (cur_mon->qmp.commands == &qmp_commands) {
+    MonitorQMP *mon;
+
+    assert(monitor_is_qmp(cur_mon));
+    mon = container_of(cur_mon, MonitorQMP, common);
+
+    if (mon->commands == &qmp_commands) {
         error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
                   "Capabilities negotiation is already complete, command "
                   "ignored");
         return;
     }
 
-    if (!qmp_caps_accept(cur_mon, enable, errp)) {
+    if (!qmp_caps_accept(mon, enable, errp)) {
         return;
     }
 
-    cur_mon->qmp.commands = &qmp_commands;
+    mon->commands = &qmp_commands;
 }
 
 /* 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);
     }
 }
 
-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;
 
     old_mon = cur_mon;
-    cur_mon = mon;
+    cur_mon = &mon->common;
 
-    rsp = qmp_dispatch(mon->qmp.commands, req, qmp_oob_enabled(mon));
+    rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon));
 
     cur_mon = old_mon;
 
-    if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
+    if (mon->commands == &qmp_cap_negotiation_commands) {
         error = 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, QObject *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 = NULL;
     Monitor *mon;
+    MonitorQMP *qmp_mon;
 
     qemu_mutex_lock(&monitor_lock);
 
     QTAILQ_FOREACH(mon, &mon_list, entry) {
-        qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
-        req_obj = g_queue_pop_head(mon->qmp.qmp_requests);
+        if (!monitor_is_qmp(mon)) {
+            continue;
+        }
+
+        qmp_mon = container_of(mon, MonitorQMP, common);
+        qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
+        req_obj = 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);
     }
 
     if (req_obj) {
@@ -4207,7 +4231,7 @@ static void monitor_qmp_bh_dispatcher(void *data)
     QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
     QDict *rsp;
     bool need_resume;
-    Monitor *mon;
+    MonitorQMP *mon;
 
     if (!req_obj) {
         return;
@@ -4216,8 +4240,8 @@ static void monitor_qmp_bh_dispatcher(void *data)
     mon = req_obj->mon;
     /*  qmp_oob_enabled() might change after "qmp_capabilities" */
     need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
-    qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+    qemu_mutex_unlock(&mon->qmp_queue_lock);
     if (req_obj->req) {
         QDict *qdict = qobject_to(QDict, req_obj->req);
         QObject *id = qdict ? qdict_get(qdict, "id") : NULL;
@@ -4233,7 +4257,7 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
     if (need_resume) {
         /* Pairs with the monitor_suspend() in handle_qmp_command() */
-        monitor_resume(mon);
+        monitor_resume(&mon->common);
     }
     qmp_request_free(req_obj);
 
@@ -4243,7 +4267,7 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
 static void handle_qmp_command(void *opaque, QObject *req, Error *err)
 {
-    Monitor *mon = opaque;
+    MonitorQMP *mon = opaque;
     QObject *id = NULL;
     QDict *qdict;
     QMPRequest *req_obj;
@@ -4275,7 +4299,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
     req_obj->err = err;
 
     /* Protect qmp_requests and fetching its length. */
-    qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
+    qemu_mutex_lock(&mon->qmp_queue_lock);
 
     /*
      * 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 == QMP_REQ_QUEUE_LEN_MAX - 1) {
-        monitor_suspend(mon);
+        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
+        monitor_suspend(&mon->common);
     }
 
     /*
@@ -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);
 
     /* 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)
 
 static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
 {
-    Monitor *mon = opaque;
+    MonitorQMP *mon = opaque;
 
-    json_message_parser_feed(&mon->qmp.parser, (const char *) buf, size);
+    json_message_parser_feed(&mon->parser, (const char *) buf, size);
 }
 
 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);
 }
 
-static QDict *qmp_greeting(Monitor *mon)
+static QDict *qmp_greeting(MonitorQMP *mon)
 {
     QList *cap_list = qlist_new();
     QObject *ver = NULL;
@@ -4400,7 +4424,7 @@ static QDict *qmp_greeting(Monitor *mon)
     qmp_marshal_query_version(NULL, &ver, NULL);
 
     for (cap = 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 = opaque;
+    MonitorQMP *mon = opaque;
 
     switch (event) {
     case CHR_EVENT_OPENED:
-        mon->qmp.commands = &qmp_cap_negotiation_commands;
+        mon->commands = &qmp_cap_negotiation_commands;
         monitor_qmp_caps_reset(mon);
         data = 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)
 
 static void monitor_qmp_setup_handlers_bh(void *opaque)
 {
-    Monitor *mon = opaque;
+    MonitorQMP *mon = opaque;
     GMainContext *context;
 
-    assert(mon->use_io_thread);
+    assert(mon->common.use_io_thread);
     context = 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);
 }
 
 static void monitor_init_qmp(Chardev *chr, int flags)
 {
-    Monitor *mon = g_malloc(sizeof(*mon));
+    MonitorQMP *mon = 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, flags, false,
+    monitor_data_init(&mon->common, flags, false,
                       qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
 
-    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 = g_queue_new();
 
-    json_message_parser_init(&mon->qmp.parser, handle_qmp_command, mon, NULL);
-    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=on.
@@ -4636,10 +4664,10 @@ static void monitor_init_qmp(Chardev *chr, int flags)
                                 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);
     }
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (2 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  8:55   ` Markus Armbruster
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection Kevin Wolf
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

The ReadLineState in Monitor is only used for HMP monitors. Create
MonitorHMP and move it there.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 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"
 
 extern __thread Monitor *cur_mon;
+typedef struct MonitorHMP MonitorHMP;
 
 /* 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);
 
-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);
 
 AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
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 char *password,
 
 void hmp_change(Monitor *mon, const QDict *qdict)
 {
+    /* FIXME Make MonitorHMP public and use container_of */
+    MonitorHMP *hmp_mon = (MonitorHMP *) mon;
     const char *device = qdict_get_str(qdict, "device");
     const char *target = qdict_get_str(qdict, "target");
     const char *arg = qdict_get_try_str(qdict, "arg");
@@ -1960,7 +1962,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
         if (strcmp(target, "passwd") == 0 ||
             strcmp(target, "password") == 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;
 
-    /*
-     * 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;
 };
 
+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 happen
+     * 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);
 }
 
-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);
 }
 
-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 *readline_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);
 }
 
-static void handle_hmp_command(Monitor *mon, const char *cmdline);
+static void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
 
 static void monitor_iothread_init(void);
 
@@ -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 = 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 = container_of(mon, MonitorQMP, common);
         monitor_data_destroy_qmp(qmp_mon);
+    } else {
+        MonitorHMP *hmp_mon = 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_line, bool has_cpu_index,
                                 int64_t cpu_index, Error **errp)
 {
     char *output = NULL;
-    Monitor *old_mon, hmp;
+    Monitor *old_mon;
+    MonitorHMP hmp = {};
 
-    monitor_data_init(&hmp, 0, true, false);
+    monitor_data_init(&hmp.common, 0, true, false);
 
     old_mon = cur_mon;
-    cur_mon = &hmp;
+    cur_mon = &hmp.common;
 
     if (has_cpu_index) {
         int ret = monitor_set_cpu(cpu_index);
@@ -770,16 +777,16 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     handle_hmp_command(&hmp, command_line);
     cur_mon = old_mon;
 
-    qemu_mutex_lock(&hmp.mon_lock);
-    if (qstring_get_length(hmp.outbuf) > 0) {
-        output = g_strdup(qstring_get_str(hmp.outbuf));
+    qemu_mutex_lock(&hmp.common.mon_lock);
+    if (qstring_get_length(hmp.common.outbuf) > 0) {
+        output = g_strdup(qstring_get_str(hmp.common.outbuf));
     } else {
         output = g_strdup("");
     }
-    qemu_mutex_unlock(&hmp.mon_lock);
+    qemu_mutex_unlock(&hmp.common.mon_lock);
 
 out:
-    monitor_data_destroy(&hmp);
+    monitor_data_destroy(&hmp.common);
     return output;
 }
 
@@ -1349,16 +1356,19 @@ static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
 
 static void hmp_info_history(Monitor *mon, const QDict *qdict)
 {
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
     int i;
     const char *str;
 
-    if (!mon->rs)
+    if (!hmp_mon->rs) {
         return;
+    }
     i = 0;
     for(;;) {
-        str = readline_get_history(mon->rs, i);
-        if (!str)
+        str = 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 = &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 = p;
     /* search sub command */
     if (cmd->sub_table != NULL && *p != '\0') {
-        return monitor_parse_command(mon, cmdp_start, cmdp, cmd->sub_table);
+        return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table);
     }
 
     return cmd;
@@ -3468,7 +3479,7 @@ fail:
     return NULL;
 }
 
-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)
 
     trace_handle_hmp_command(mon, cmdline);
 
-    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
+    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_table);
     if (!cmd) {
         return;
     }
 
-    qdict = monitor_parse_arguments(mon, &cmdline, cmd);
+    qdict = 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 information\n",
                        (int)(cmdline - cmd_start), cmd_start);
         return;
     }
 
-    cmd->cmd(mon, qdict);
+    cmd->cmd(&mon->common, qdict);
     qobject_unref(qdict);
 }
 
-static void cmd_completion(Monitor *mon, const char *name, const char *list)
+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)
     }
 }
 
-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)
     }
 }
 
-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 = opaque;
+    MonitorHMP *mon = opaque;
     char *args[MAX_ARGS];
     int nb_args, len;
 
@@ -4123,7 +4134,7 @@ static void monitor_find_completion(void *opaque,
     }
 
     /* 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);
 
 cleanup:
     free_cmdline_args(args, nb_args);
@@ -4334,19 +4345,21 @@ static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
 
 static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
+    MonitorHMP *mon;
     Monitor *old_mon = cur_mon;
     int i;
 
     cur_mon = opaque;
+    mon = container_of(cur_mon, MonitorHMP, common);
 
-    if (cur_mon->rs) {
+    if (mon->rs) {
         for (i = 0; i < size; i++)
-            readline_handle_byte(cur_mon->rs, buf[i]);
+            readline_handle_byte(mon->rs, buf[i]);
     } else {
         if (size == 0 || buf[size - 1] != 0)
             monitor_printf(cur_mon, "corrupted command\n");
         else
-            handle_hmp_command(cur_mon, (char *)buf);
+            handle_hmp_command(mon, (char *)buf);
     }
 
     cur_mon = 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 = opaque;
+    MonitorHMP *mon = opaque;
 
-    monitor_suspend(mon);
+    monitor_suspend(&mon->common);
     handle_hmp_command(mon, cmdline);
-    monitor_resume(mon);
+    monitor_resume(&mon->common);
 }
 
 int monitor_suspend(Monitor *mon)
@@ -4405,8 +4418,9 @@ void monitor_resume(Monitor *mon)
         }
 
         if (!monitor_is_qmp(mon)) {
-            assert(mon->rs);
-            readline_show_prompt(mon->rs);
+            MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+            assert(hmp_mon->rs);
+            readline_show_prompt(hmp_mon->rs);
         }
 
         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 = opaque;
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
 
     switch (event) {
     case CHR_EVENT_MUX_IN:
@@ -4475,7 +4490,7 @@ static void monitor_event(void *opaque, int event)
         mon->mux_out = 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 = 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 = opaque;
     va_list ap;
     va_start(ap, fmt);
-    monitor_vprintf(opaque, fmt, ap);
+    monitor_vprintf(&mon->common, fmt, ap);
     va_end(ap);
 }
 
 static void monitor_readline_flush(void *opaque)
 {
-    monitor_flush(opaque);
+    MonitorHMP *mon = opaque;
+    monitor_flush(&mon->common);
 }
 
 /*
@@ -4673,11 +4690,11 @@ static void monitor_init_qmp(Chardev *chr, int flags)
 
 static void monitor_init_hmp(Chardev *chr, int flags)
 {
-    Monitor *mon = g_malloc(sizeof(*mon));
+    MonitorHMP *mon = g_malloc0(sizeof(*mon));
     bool use_readline = flags & MONITOR_USE_READLINE;
 
-    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);
 
     if (use_readline) {
         mon->rs = readline_init(monitor_readline_printf,
@@ -4687,9 +4704,9 @@ static void monitor_init_hmp(Chardev *chr, int flags)
         monitor_read_command(mon, 0);
     }
 
-    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_read,
+                             monitor_event, NULL, &mon->common, NULL, true);
+    monitor_list_append(&mon->common);
 }
 
 void monitor_init(Chardev *chr, int flags)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (3 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  5:51   ` Markus Armbruster
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables Kevin Wolf
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
---
 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;
 
     gchar *mon_cpu_path;
-    mon_cmd_t *cmd_table;
     QTAILQ_ENTRY(Monitor) entry;
 
     /*
@@ -722,8 +721,6 @@ static void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
     }
     qemu_mutex_init(&mon->mon_lock);
     mon->outbuf = qstring_new();
-    /* Use *mon_cmds by default. */
-    mon->cmd_table = mon_cmds;
     mon->skip_flush = skip_flush;
     mon->use_io_thread = use_io_thread;
     mon->flags = flags;
@@ -1026,7 +1023,7 @@ static void help_cmd(Monitor *mon, const char *name)
     }
 
     /* 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);
 
     free_cmdline_args(args, nb_args);
 }
@@ -3487,7 +3484,7 @@ static void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
 
     trace_handle_hmp_command(mon, cmdline);
 
-    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_table);
+    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon_cmds);
     if (!cmd) {
         return;
     }
@@ -4134,7 +4131,7 @@ static void monitor_find_completion(void *opaque,
     }
 
     /* 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);
 
 cleanup:
     free_cmdline_args(args, nb_args);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (4 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  5:52   ` Markus Armbruster
  2019-06-14  6:01   ` Markus Armbruster
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c Kevin Wolf
                   ` (10 subsequent siblings)
  16 siblings, 2 replies; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
---
 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 @@
  *
  */
 
-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;
 
 /* file descriptors passed via SCM_RIGHTS */
 typedef struct mon_fd_t mon_fd_t;
@@ -277,8 +277,8 @@ static QLIST_HEAD(, MonFdset) mon_fdsets;
 
 static int mon_refcount;
 
-static mon_cmd_t mon_cmds[];
-static mon_cmd_t info_cmds[];
+static HMPCommand hmp_cmds[];
+static HMPCommand hmp_info_cmds[];
 
 QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
 
@@ -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)
 }
 
 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,
 }
 
 /* @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;
 
     /* No valid arg need to compare with, dump all in *cmds */
@@ -1023,7 +1023,7 @@ static void help_cmd(Monitor *mon, const char *name)
     }
 
     /* 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);
 
     free_cmdline_args(args, nb_args);
 }
@@ -2691,13 +2691,13 @@ int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
 }
 
 /* Please update hmp-commands.hx when adding or changing commands */
-static mon_cmd_t info_cmds[] = {
+static HMPCommand hmp_info_cmds[] = {
 #include "hmp-commands-info.h"
     { NULL, NULL, },
 };
 
-/* mon_cmds and info_cmds would be sorted at runtime */
-static mon_cmd_t mon_cmds[] = {
+/* hmp_cmds and hmp_info_cmds would be sorted at runtime */
+static HMPCommand hmp_cmds[] = {
 #include "hmp-commands.h"
     { NULL, NULL, },
 };
@@ -3039,10 +3039,10 @@ static int is_valid_option(const char *c, const char *typestr)
     return (typestr != NULL);
 }
 
-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_table,
+                                               const char *cmdname)
 {
-    const mon_cmd_t *cmd;
+    const HMPCommand *cmd;
 
     for (cmd = disp_table; cmd->name != 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 = &hmp_mon->common;
     const char *p;
-    const mon_cmd_t *cmd;
+    const HMPCommand *cmd;
     char cmdname[256];
 
     /* extract the command name */
@@ -3114,7 +3114,7 @@ static const mon_cmd_t *monitor_parse_command(MonitorHMP *hmp_mon,
 
 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 = cmdline;
 
     trace_handle_hmp_command(mon, cmdline);
 
-    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon_cmds);
+    cmd = monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds);
     if (!cmd) {
         return;
     }
@@ -4017,14 +4017,14 @@ void loadvm_completion(ReadLineState *rs, int nb_args, const char *str)
 }
 
 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 = NULL;
 
     if (nb_args <= 1) {
@@ -4131,7 +4131,7 @@ static void monitor_find_completion(void *opaque,
     }
 
     /* 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);
 
 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);
 }
 
 static void sortcmdlist(void)
 {
     int array_num;
-    int elem_size = sizeof(mon_cmd_t);
+    int elem_size = sizeof(HMPCommand);
 
-    array_num = sizeof(mon_cmds)/elem_size-1;
-    qsort((void *)mon_cmds, array_num, elem_size, compare_mon_cmd);
+    array_num = sizeof(hmp_cmds)/elem_size-1;
+    qsort((void *)hmp_cmds, array_num, elem_size, compare_mon_cmd);
 
-    array_num = sizeof(info_cmds)/elem_size-1;
-    qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
+    array_num = sizeof(hmp_info_cmds)/elem_size-1;
+    qsort((void *)hmp_info_cmds, array_num, elem_size, compare_mon_cmd);
 }
 
 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     = "[subcommand]",
         .help       = "show various information about the system state",
         .cmd        = hmp_info_help,
-        .sub_table  = info_cmds,
+        .sub_table  = hmp_info_cmds,
         .flags      = "p",
     },
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (5 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  6:04   ` Markus Armbruster
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 08/15] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 docs/devel/writing-qmp-commands.txt |  2 +-
 monitor.c => 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 => 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-commands.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.
 
 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 defined
-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:
 
     {
         .name       = "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 <dgilbert@redhat.com>
 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 <armbru@redhat.com>
 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 =
 trace-events-subdirs += accel/kvm
 trace-events-subdirs += accel/tcg
 trace-events-subdirs += crypto
+trace-events-subdirs += monitor
 ifeq ($(CONFIG_USER_ONLY),y)
 trace-events-subdirs += 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 += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
+obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o numa.o
 obj-y += qtest.o
 obj-y += hw/
+obj-y += monitor/
 obj-y += qapi/
 obj-y += memory.o
 obj-y += 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 += 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=%d data=%p"
+monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
+monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" 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=%d"
 qemu_system_shutdown_request(int reason) "reason=%d"
 qemu_system_powerdown_request(void) ""
 
-# monitor.c
-monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p"
-monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
-monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" 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=%p bs=%p offset=%" PRId64 " to_dev=%d"
 dma_aio_cancel(void *dbs) "dbs=%p"
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 08/15] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (6 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions Kevin Wolf
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 docs/devel/writing-qmp-commands.txt | 9 +++++----
 hmp.c => monitor/hmp-cmds.c         | 2 +-
 qmp.c => monitor/qmp-cmds.c         | 2 +-
 MAINTAINERS                         | 5 +++--
 Makefile.objs                       | 2 +-
 monitor/Makefile.objs               | 1 +
 6 files changed, 12 insertions(+), 9 deletions(-)
 rename hmp.c => monitor/hmp-cmds.c (99%)
 rename qmp.c => monitor/qmp-cmds.c (99%)

diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.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.
 
 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
 
 3. At this point the command can be tested under the QMP protocol
 
@@ -101,7 +101,8 @@ protocol data.
 
 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:
 
 void qmp_hello_world(Error **errp)
 {
@@ -146,7 +147,7 @@ for mandatory arguments). Finally, 'str' is the argument's type, which
 stands for "string". The QAPI also supports integers, booleans, enumerations
 and user defined types.
 
-Now, let's update our C implementation in qmp.c:
+Now, let's update our C implementation in monitor/qmp-cmds.c:
 
 void qmp_hello_world(bool has_message, const char *message, Error **errp)
 {
@@ -267,7 +268,7 @@ monitor (HMP).
 
 With the introduction of the QAPI, HMP commands make QMP calls. Most of the
 time HMP commands are simple wrappers. All HMP commands implementation exist in
-the hmp.c file.
+the monitor/hmp-cmds.c file.
 
 Here's the implementation of the "hello-world" HMP command:
 
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 <dgilbert@redhat.com>
 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 <armbru@redhat.com>
 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) += device_tree.o
 ######################################################################
 # qapi
 
-common-obj-y += qmp.o hmp.o
 common-obj-y += qapi/
+common-obj-y += monitor/
 endif
 
 #######################################################################
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 += misc.o
+common-obj-y += qmp-cmds.o hmp-cmds.o
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (7 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 08/15] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
@ 2019-06-13 15:33 ` Kevin Wolf
  2019-06-14  6:37   ` Markus Armbruster
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c Kevin Wolf
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 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"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * 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 OTHER
+ * 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 quote)
+ * 'O'          option string of the form NAME=VALUE,...
+ *              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 suffixes 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 and 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=preconfig */
+    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 happen
+     * 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 @@
  */
 
 #include "qemu/osdep.h"
+#include "monitor-internal.h"
 #include "qemu/units.h"
 #include <dirent.h>
 #include "cpu.h"
@@ -93,55 +94,6 @@
 #include "hw/s390x/storage-attributes.h"
 #endif
 
-/*
- * Supported types:
- *
- * 'F'          filename
- * 'B'          block device name
- * 's'          string (accept optional quote)
- * 'S'          it just appends the rest of the string (accept optional quote)
- * 'O'          option string of the form NAME=VALUE,...
- *              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 suffixes 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 and 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=preconfig */
-    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;
 
-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 happen
-     * 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;
 
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 <dgilbert@redhat.com>
 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 <armbru@redhat.com>
 S: Supported
+F: monitor/monitor-internal.h
 F: monitor/qmp*
 F: monitor/misc.c
 F: docs/devel/*qmp-*
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (8 preceding siblings ...)
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions Kevin Wolf
@ 2019-06-13 15:34 ` Kevin Wolf
  2019-06-14  6:46   ` Markus Armbruster
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c Kevin Wolf
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 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;
 
+/**
+ * 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;
 
-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
 
 /* 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;
 
 /* Protects mon_fdsets */
 static QemuMutex mon_fdsets_lock;
 static QLIST_HEAD(, MonFdset) mon_fdsets;
 
-static int mon_refcount;
+int mon_refcount;
 
 static HMPCommand hmp_cmds[];
 static HMPCommand hmp_info_cmds[];
 
-QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
-
 __thread Monitor *cur_mon;
 
 static void monitor_command_cb(void *opaque, const char *cmdline,
                                void *readline_opaque);
 
-/**
- * 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, ReadLineFunc *readline_func,
     }
 }
 
-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);
-}
-
 
 static void monitor_flush_locked(Monitor *mon);
 
@@ -326,7 +282,7 @@ void monitor_flush(Monitor *mon)
 }
 
 /* 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;
 }
 
-static void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
-{
-    const QObject *data = QOBJECT(rsp);
-    QString *json;
-
-    json = mon->common.flags & MONITOR_USE_PRETTY ?
-           qobject_to_json_pretty(data) : qobject_to_json(data);
-    assert(json != 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] = {
     /* Limit guest-triggerable events to 1 per second */
     [QAPI_EVENT_RTC_CHANGE]        = { 1000 * SCALE_MS },
@@ -605,8 +546,8 @@ static void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
 
 static void monitor_iothread_init(void);
 
-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 = flags;
 }
 
-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);
 }
 
-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] = 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)
     }
 }
 
-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);
 }
 
-static int monitor_can_read(void *opaque)
+int monitor_can_read(void *opaque)
 {
     Monitor *mon = opaque;
 
     return !atomic_mb_read(&mon->suspend_cnt);
 }
 
-/*
- * 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 = cur_mon;
-    cur_mon = &mon->common;
-
-    rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon));
-
-    cur_mon = old_mon;
-
-    if (mon->commands == &qmp_cap_negotiation_commands) {
-        error = 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 negotiation"
-                          " 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 = 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 = container_of(mon, MonitorQMP, common);
-        qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
-        req_obj = 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 = monitor_qmp_requests_pop_any_with_lock();
-    QDict *rsp;
-    bool need_resume;
-    MonitorQMP *mon;
-
-    if (!req_obj) {
-        return;
-    }
-
-    mon = req_obj->mon;
-    /*  qmp_oob_enabled() might change after "qmp_capabilities" */
-    need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
-    qemu_mutex_unlock(&mon->qmp_queue_lock);
-    if (req_obj->req) {
-        QDict *qdict = qobject_to(QDict, req_obj->req);
-        QObject *id = 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 = qmp_error_response(req_obj->err);
-        req_obj->err = 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 = opaque;
-    QObject *id = NULL;
-    QDict *qdict;
-    QMPRequest *req_obj;
-
-    assert(!req != !err);
-
-    qdict = qobject_to(QDict, req);
-    if (qdict) {
-        id = qdict_get(qdict, "id");
-    } /* else will fail qmp_dispatch() */
-
-    if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
-        QString *req_json = 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 = g_new0(QMPRequest, 1);
-    req_obj->mon = mon;
-    req_obj->req = req;
-    req_obj->err = 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 == 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 = 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);
 }
 
-static QDict *qmp_greeting(MonitorQMP *mon)
-{
-    QList *cap_list = qlist_new();
-    QObject *ver = NULL;
-    QMPCapability cap;
-
-    qmp_marshal_query_version(NULL, &ver, NULL);
-
-    for (cap = 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 = opaque;
-
-    switch (event) {
-    case CHR_EVENT_OPENED:
-        mon->commands = &qmp_cap_negotiation_commands;
-        monitor_qmp_caps_reset(mon);
-        data = 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 = opaque;
@@ -4503,7 +4178,7 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap)
     return -1;
 }
 
-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)
     }
 }
 
-static void monitor_qmp_setup_handlers_bh(void *opaque)
-{
-    MonitorQMP *mon = opaque;
-    GMainContext *context;
-
-    assert(mon->common.use_io_thread);
-    context = 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 = 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 = 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=on.
-         */
-        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 = 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"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * 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 OTHER
+ * 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] = 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 = QOBJECT(rsp);
+    QString *json;
+
+    json = mon->common.flags & MONITOR_USE_PRETTY ?
+           qobject_to_json_pretty(data) : qobject_to_json(data);
+    assert(json != 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 = cur_mon;
+    cur_mon = &mon->common;
+
+    rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon));
+
+    cur_mon = old_mon;
+
+    if (mon->commands == &qmp_cap_negotiation_commands) {
+        error = 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 negotiation"
+                          " 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 = 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 = container_of(mon, MonitorQMP, common);
+        qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
+        req_obj = 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 = monitor_qmp_requests_pop_any_with_lock();
+    QDict *rsp;
+    bool need_resume;
+    MonitorQMP *mon;
+
+    if (!req_obj) {
+        return;
+    }
+
+    mon = req_obj->mon;
+    /*  qmp_oob_enabled() might change after "qmp_capabilities" */
+    need_resume = !qmp_oob_enabled(mon) ||
+        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+    qemu_mutex_unlock(&mon->qmp_queue_lock);
+    if (req_obj->req) {
+        QDict *qdict = qobject_to(QDict, req_obj->req);
+        QObject *id = 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 = qmp_error_response(req_obj->err);
+        req_obj->err = 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 = opaque;
+    QObject *id = NULL;
+    QDict *qdict;
+    QMPRequest *req_obj;
+
+    assert(!req != !err);
+
+    qdict = qobject_to(QDict, req);
+    if (qdict) {
+        id = qdict_get(qdict, "id");
+    } /* else will fail qmp_dispatch() */
+
+    if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
+        QString *req_json = 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 = g_new0(QMPRequest, 1);
+    req_obj->mon = mon;
+    req_obj->req = req;
+    req_obj->err = 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 == 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 = opaque;
+
+    json_message_parser_feed(&mon->parser, (const char *) buf, size);
+}
+
+static QDict *qmp_greeting(MonitorQMP *mon)
+{
+    QList *cap_list = qlist_new();
+    QObject *ver = NULL;
+    QMPCapability cap;
+
+    qmp_marshal_query_version(NULL, &ver, NULL);
+
+    for (cap = 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 = opaque;
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        mon->commands = &qmp_cap_negotiation_commands;
+        monitor_qmp_caps_reset(mon);
+        data = 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 = opaque;
+    GMainContext *context;
+
+    assert(mon->common.use_io_thread);
+    context = 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 = 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 = 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=on.
+         */
+        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 = blockdev.o blockdev-nbd.o block/
 common-obj-y += bootdevice.o iothread.o
 common-obj-y += job-qmp.o
+common-obj-y += monitor/
 common-obj-y += net/
 common-obj-y += qdev-monitor.o device-hotplug.o
 common-obj-$(CONFIG_WIN32) += 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 += misc.o
+common-obj-y += qmp.o
 common-obj-y += 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=%d data=%p"
 monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
 monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" 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"
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (9 preceding siblings ...)
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c Kevin Wolf
@ 2019-06-13 15:34 ` Kevin Wolf
  2019-06-14  8:23   ` Markus Armbruster
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c Kevin Wolf
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
---
 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
 
 #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;
 
+extern HMPCommand hmp_cmds[];
+
 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, int flags, bool skip_flush,
@@ -174,4 +179,9 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp);
 void monitor_data_destroy_qmp(MonitorQMP *mon);
 void monitor_qmp_bh_dispatcher(void *data);
 
+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"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * 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 OTHER
+ * 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 = 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 = buf;
+    p = *pp;
+    while (qemu_isspace(*p)) {
+        p++;
+    }
+    if (*p == '\0') {
+    fail:
+        *q = '\0';
+        *pp = p;
+        return -1;
+    }
+    if (*p == '\"') {
+        p++;
+        while (*p != '\0' && *p != '\"') {
+            if (*p == '\\') {
+                p++;
+                c = *p++;
+                switch (c) {
+                case 'n':
+                    c = '\n';
+                    break;
+                case 'r':
+                    c = '\r';
+                    break;
+                case '\\':
+                case '\'':
+                case '\"':
+                    break;
+                default:
+                    printf("unsupported escape code: '\\%c'\n", c);
+                    goto fail;
+                }
+                if ((q - buf) < buf_size - 1) {
+                    *q++ = c;
+                }
+            } else {
+                if ((q - buf) < buf_size - 1) {
+                    *q++ = *p;
+                }
+                p++;
+            }
+        }
+        if (*p != '\"') {
+            printf("unterminated string\n");
+            goto fail;
+        }
+        p++;
+    } else {
+        while (*p != '\0' && !qemu_isspace(*p)) {
+            if ((q - buf) < buf_size - 1) {
+                *q++ = *p;
+            }
+            p++;
+        }
+    }
+    *q = '\0';
+    *pp = p;
+    return 0;
+}
+
+#define MAX_ARGS 16
+
+static void free_cmdline_args(char **args, int nb_args)
+{
+    int i;
+
+    assert(nb_args <= MAX_ARGS);
+
+    for (i = 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. Number
+ *       of args have a limit of MAX_ARGS. If cmdline contains more, it will
+ *       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 = cmdline;
+    nb_args = 0;
+    for (;;) {
+        while (qemu_isspace(*p)) {
+            p++;
+        }
+        if (*p == '\0') {
+            break;
+        }
+        if (nb_args >= MAX_ARGS) {
+            goto fail;
+        }
+        ret = get_str(buf, sizeof(buf), &p);
+        if (ret < 0) {
+            goto fail;
+        }
+        args[nb_args] = g_strdup(buf);
+        nb_args++;
+    }
+    *pnb_args = 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 = 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 >= nb_args) {
+        for (cmd = cmds; cmd->name != NULL; cmd++) {
+            help_cmd_dump_one(mon, cmd, args, arg_index);
+        }
+        return;
+    }
+
+    /* Find one entry to dump */
+    for (cmd = cmds; cmd->name != 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 = 0; i <= arg_index; i++) {
+        monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
+    }
+}
+
+void help_cmd(Monitor *mon, const char *name)
+{
+    char *args[MAX_ARGS];
+    int nb_args = 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 = qemu_log_items; item->mask != 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 != '\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 = expr_unary(mon);
+        break;
+    case '-':
+        next();
+        n = -expr_unary(mon);
+        break;
+    case '~':
+        next();
+        n = ~expr_unary(mon);
+        break;
+    case '(':
+        next();
+        n = expr_sum(mon);
+        if (*pch != ')') {
+            expr_error(mon, "')' expected");
+        }
+        next();
+        break;
+    case '\'':
+        pch++;
+        if (*pch == '\0') {
+            expr_error(mon, "character constant expected");
+        }
+        n = *pch;
+        pch++;
+        if (*pch != '\'') {
+            expr_error(mon, "missing terminating \' character");
+        }
+        next();
+        break;
+    case '$':
+        {
+            char buf[128], *q;
+            int64_t reg = 0;
+
+            pch++;
+            q = buf;
+            while ((*pch >= 'a' && *pch <= 'z') ||
+                   (*pch >= 'A' && *pch <= 'Z') ||
+                   (*pch >= '0' && *pch <= '9') ||
+                   *pch == '_' || *pch == '.') {
+                if ((q - buf) < sizeof(buf) - 1) {
+                    *q++ = *pch;
+                }
+                pch++;
+            }
+            while (qemu_isspace(*pch)) {
+                pch++;
+            }
+            *q = 0;
+            ret = get_monitor_def(&reg, buf);
+            if (ret < 0) {
+                expr_error(mon, "unknown register");
+            }
+            n = reg;
+        }
+        break;
+    case '\0':
+        expr_error(mon, "unexpected end of expression");
+        n = 0;
+        break;
+    default:
+        errno = 0;
+        n = strtoull(pch, &p, 0);
+        if (errno == ERANGE) {
+            expr_error(mon, "number too large");
+        }
+        if (pch == p) {
+            expr_error(mon, "invalid char '%c' in expression", *p);
+        }
+        pch = p;
+        while (qemu_isspace(*pch)) {
+            pch++;
+        }
+        break;
+    }
+    return n;
+}
+
+static int64_t expr_prod(Monitor *mon)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_unary(mon);
+    for (;;) {
+        op = *pch;
+        if (op != '*' && op != '/' && op != '%') {
+            break;
+        }
+        next();
+        val2 = expr_unary(mon);
+        switch (op) {
+        default:
+        case '*':
+            val *= val2;
+            break;
+        case '/':
+        case '%':
+            if (val2 == 0) {
+                expr_error(mon, "division by zero");
+            }
+            if (op == '/') {
+                val /= val2;
+            } else {
+                val %= val2;
+            }
+            break;
+        }
+    }
+    return val;
+}
+
+static int64_t expr_logic(Monitor *mon)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_prod(mon);
+    for (;;) {
+        op = *pch;
+        if (op != '&' && op != '|' && op != '^') {
+            break;
+        }
+        next();
+        val2 = expr_prod(mon);
+        switch (op) {
+        default:
+        case '&':
+            val &= val2;
+            break;
+        case '|':
+            val |= val2;
+            break;
+        case '^':
+            val ^= val2;
+            break;
+        }
+    }
+    return val;
+}
+
+static int64_t expr_sum(Monitor *mon)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_logic(mon);
+    for (;;) {
+        op = *pch;
+        if (op != '+' && op != '-') {
+            break;
+        }
+        next();
+        val2 = expr_logic(mon);
+        if (op == '+') {
+            val += val2;
+        } else {
+            val -= val2;
+        }
+    }
+    return val;
+}
+
+static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
+{
+    pch = *pp;
+    if (sigsetjmp(expr_env, 0)) {
+        *pp = pch;
+        return -1;
+    }
+    while (qemu_isspace(*pch)) {
+        pch++;
+    }
+    *pval = expr_sum(mon);
+    *pp = pch;
+    return 0;
+}
+
+static int get_double(Monitor *mon, double *pval, const char **pp)
+{
+    const char *p = *pp;
+    char *tailp;
+    double d;
+
+    d = strtod(p, &tailp);
+    if (tailp == p) {
+        monitor_printf(mon, "Number expected\n");
+        return -1;
+    }
+    if (d != d || d - d != 0) {
+        /* NaN or infinity */
+        monitor_printf(mon, "Bad number\n");
+        return -1;
+    }
+    *pval = d;
+    *pp = 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 = cmdline;
+    while (qemu_isspace(*p)) {
+        p++;
+    }
+    if (*p == '\0') {
+        return NULL;
+    }
+    pstart = p;
+    while (*p != '\0' && *p != '/' && !qemu_isspace(*p)) {
+        p++;
+    }
+    len = p - pstart;
+    if (len > nlen - 1) {
+        len = nlen - 1;
+    }
+    memcpy(cmdname, pstart, len);
+    cmdname[len] = '\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 == ',') {
+        type++;
+    }
+
+    p = strchr(type, ':');
+    if (!p) {
+        *key = NULL;
+        return NULL;
+    }
+    len = p - type;
+
+    str = g_malloc(len + 1);
+    memcpy(str, type, len);
+    str[len] = '\0';
+
+    *key = str;
+    return ++p;
+}
+
+static int default_fmt_format = 'x';
+static int default_fmt_size = 4;
+
+static int is_valid_option(const char *c, const char *typestr)
+{
+    char option[3];
+
+    option[0] = '-';
+    option[1] = *c;
+    option[2] = '\0';
+
+    typestr = strstr(typestr, option);
+    return (typestr != NULL);
+}
+
+static const HMPCommand *search_dispatch_table(const HMPCommand *disp_table,
+                                               const char *cmdname)
+{
+    const HMPCommand *cmd;
+
+    for (cmd = disp_table; cmd->name != 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 = &hmp_mon->common;
+    const char *p;
+    const HMPCommand *cmd;
+    char cmdname[256];
+
+    /* extract the command name */
+    p = get_command_name(*cmdp, cmdname, sizeof(cmdname));
+    if (!p) {
+        return NULL;
+    }
+
+    cmd = 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 = p;
+    /* search sub command */
+    if (cmd->sub_table != NULL && *p != '\0') {
+        return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table);
+    }
+
+    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 = *endp;
+    char buf[1024];
+    QDict *qdict = qdict_new();
+
+    /* parse the parameters */
+    typestr = cmd->args_type;
+    for (;;) {
+        typestr = key_get_info(typestr, &key);
+        if (!typestr) {
+            break;
+        }
+        c = *typestr;
+        typestr++;
+        switch (c) {
+        case 'F':
+        case 'B':
+        case 's':
+            {
+                int ret;
+
+                while (qemu_isspace(*p)) {
+                    p++;
+                }
+                if (*typestr == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        /* no optional string: NULL argument */
+                        break;
+                    }
+                }
+                ret = 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 expected\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 = 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 = 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 == '/') {
+                    /* format found */
+                    p++;
+                    count = 1;
+                    if (qemu_isdigit(*p)) {
+                        count = 0;
+                        while (qemu_isdigit(*p)) {
+                            count = count * 10 + (*p - '0');
+                            p++;
+                        }
+                    }
+                    size = -1;
+                    format = -1;
+                    for (;;) {
+                        switch (*p) {
+                        case 'o':
+                        case 'd':
+                        case 'u':
+                        case 'x':
+                        case 'i':
+                        case 'c':
+                            format = *p++;
+                            break;
+                        case 'b':
+                            size = 1;
+                            p++;
+                            break;
+                        case 'h':
+                            size = 2;
+                            p++;
+                            break;
+                        case 'w':
+                            size = 4;
+                            p++;
+                            break;
+                        case 'g':
+                        case 'L':
+                            size = 8;
+                            p++;
+                            break;
+                        default:
+                            goto next;
+                        }
+                    }
+                next:
+                    if (*p != '\0' && !qemu_isspace(*p)) {
+                        monitor_printf(mon, "invalid char in format: '%c'\n",
+                                       *p);
+                        goto fail;
+                    }
+                    if (format < 0) {
+                        format = default_fmt_format;
+                    }
+                    if (format != 'i') {
+                        /* for 'i', not specifying a size gives -1 as size */
+                        if (size < 0) {
+                            size = default_fmt_size;
+                        }
+                        default_fmt_size = size;
+                    }
+                    default_fmt_format = format;
+                } else {
+                    count = 1;
+                    format = default_fmt_format;
+                    if (format != 'i') {
+                        size = default_fmt_size;
+                    } else {
+                        size = -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 == '?' || *typestr == '.') {
+                    if (*typestr == '?') {
+                        if (*p == '\0') {
+                            typestr++;
+                            break;
+                        }
+                    } else {
+                        if (*p == '.') {
+                            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 == '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 == 'M') {
+                    if (val < 0) {
+                        monitor_printf(mon, "enter a positive value\n");
+                        goto fail;
+                    }
+                    val *= 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 == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        break;
+                    }
+                }
+                ret = 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 = end;
+            }
+            break;
+        case 'T':
+            {
+                double val;
+
+                while (qemu_isspace(*p)) {
+                    p++;
+                }
+                if (*typestr == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        break;
+                    }
+                }
+                if (get_double(mon, &val, &p) < 0) {
+                    goto fail;
+                }
+                if (p[0] && p[1] == 's') {
+                    switch (*p) {
+                    case 'm':
+                        val /= 1e3; p += 2; break;
+                    case 'u':
+                        val /= 1e6; p += 2; break;
+                    case 'n':
+                        val /= 1e9; p += 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 = p;
+                while (qemu_isgraph(*p)) {
+                    p++;
+                }
+                if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
+                    val = true;
+                } else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
+                    val = false;
+                } else {
+                    monitor_printf(mon, "Expected 'on' or 'off'\n");
+                    goto fail;
+                }
+                qdict_put_bool(qdict, key, val);
+            }
+            break;
+        case '-':
+            {
+                const char *tmp = p;
+                int skip_key = 0;
+                /* option */
+
+                c = *typestr++;
+                if (c == '\0') {
+                    goto bad_type;
+                }
+                while (qemu_isspace(*p)) {
+                    p++;
+                }
+                if (*p == '-') {
+                    p++;
+                    if (c != *p) {
+                        if (!is_valid_option(p, typestr)) {
+                            monitor_printf(mon, "%s: unsupported option -%c\n",
+                                           cmd->name, *p);
+                            goto fail;
+                        } else {
+                            skip_key = 1;
+                        }
+                    }
+                    if (skip_key) {
+                        p = 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 == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        /* no remaining string: NULL argument */
+                        break;
+                    }
+                }
+                len = strlen(p);
+                if (len <= 0) {
+                    monitor_printf(mon, "%s: string expected\n",
+                                   cmd->name);
+                    goto fail;
+                }
+                qdict_put_str(qdict, key, p);
+                p += len;
+            }
+            break;
+        default:
+        bad_type:
+            monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c);
+            goto fail;
+        }
+        g_free(key);
+        key = NULL;
+    }
+    /* check that all arguments were parsed */
+    while (qemu_isspace(*p)) {
+        p++;
+    }
+    if (*p != '\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 = cmdline;
+
+    trace_handle_hmp_command(mon, cmdline);
+
+    cmd = monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds);
+    if (!cmd) {
+        return;
+    }
+
+    qdict = 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 information\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 = list;
+    for (;;) {
+        pstart = p;
+        p = qemu_strchrnul(p, '|');
+        len = p - pstart;
+        if (len > sizeof(cmd) - 2) {
+            len = sizeof(cmd) - 2;
+        }
+        memcpy(cmd, pstart, len);
+        cmd[len] = '\0';
+        if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
+            readline_add_completion(mon->rs, cmd);
+        }
+        if (*p == '\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 = strrchr(input, '/');
+    if (!p) {
+        input_path_len = 0;
+        pstrcpy(file_prefix, sizeof(file_prefix), input);
+        pstrcpy(path, sizeof(path), ".");
+    } else {
+        input_path_len = p - input + 1;
+        memcpy(path, input, input_path_len);
+        if (input_path_len > sizeof(path) - 1) {
+            input_path_len = sizeof(path) - 1;
+        }
+        path[input_path_len] = '\0';
+        pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
+    }
+
+    ffs = opendir(path);
+    if (!ffs) {
+        return;
+    }
+    for (;;) {
+        struct stat sb;
+        d = readdir(ffs);
+        if (!d) {
+            break;
+        }
+
+        if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 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_len,
+                        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) == 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 = strchr(typestr, ':');
+    return (p != 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 = NULL;
+
+    if (nb_args <= 1) {
+        /* command completion */
+        if (nb_args == 0) {
+            cmdname = "";
+        } else {
+            cmdname = args[0];
+        }
+        readline_set_completion_index(mon->rs, strlen(cmdname));
+        for (cmd = cmd_table; cmd->name != NULL; cmd++) {
+            if (!runstate_check(RUN_STATE_PRECONFIG) ||
+                 cmd_can_preconfig(cmd)) {
+                cmd_completion(mon, cmdname, cmd->name);
+            }
+        }
+    } else {
+        /* find the command */
+        for (cmd = cmd_table; cmd->name != 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 = next_arg_type(cmd->args_type);
+        for (i = 0; i < nb_args - 2; i++) {
+            if (*ptype != '\0') {
+                ptype = next_arg_type(ptype);
+                while (*ptype == '?') {
+                    ptype = next_arg_type(ptype);
+                }
+            }
+        }
+        str = args[nb_args - 1];
+        old_ptype = NULL;
+        while (*ptype == '-' && old_ptype != ptype) {
+            old_ptype = ptype;
+            ptype = 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 = blk_next(blk)) != NULL) {
+                name = blk_name(blk);
+                if (str[0] == '\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 = 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 = strlen(cmdline);
+    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
+        if (nb_args >= MAX_ARGS) {
+            goto cleanup;
+        }
+        args[nb_args++] = 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 = cur_mon;
+    int i;
+
+    cur_mon = opaque;
+    mon = container_of(cur_mon, MonitorHMP, common);
+
+    if (mon->rs) {
+        for (i = 0; i < size; i++) {
+            readline_handle_byte(mon->rs, buf[i]);
+        }
+    } else {
+        if (size == 0 || buf[size - 1] != 0) {
+            monitor_printf(cur_mon, "corrupted command\n");
+        } else {
+            handle_hmp_command(mon, (char *)buf);
+        }
+    }
+
+    cur_mon = old_mon;
+}
+
+static void monitor_event(void *opaque, int event)
+{
+    Monitor *mon = opaque;
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+
+    switch (event) {
+    case CHR_EVENT_MUX_IN:
+        qemu_mutex_lock(&mon->mon_lock);
+        mon->mux_out = 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) == 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 = 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 = 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 = 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 = opaque;
+    monitor_flush(&mon->common);
+}
+
+void monitor_init_hmp(Chardev *chr, int flags)
+{
+    MonitorHMP *mon = g_malloc0(sizeof(*mon));
+    bool use_readline = 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 = 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_read,
+                             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 @@
 
 #include "qemu/osdep.h"
 #include "monitor-internal.h"
-#include "qemu/units.h"
 #include <dirent.h>
 #include "cpu.h"
 #include "hw/hw.h"
@@ -157,14 +156,10 @@ static QLIST_HEAD(, MonFdset) mon_fdsets;
 
 int mon_refcount;
 
-static HMPCommand hmp_cmds[];
 static HMPCommand hmp_info_cmds[];
 
 __thread Monitor *cur_mon;
 
-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);
 }
 
-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);
 
 static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
@@ -542,8 +512,6 @@ static void monitor_qapi_event_init(void)
                                                 qapi_event_throttle_equal);
 }
 
-static void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
-
 static void monitor_iothread_init(void);
 
 void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
@@ -612,245 +580,27 @@ out:
     return output;
 }
 
-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 = strlen(name);
     p = list;
-    for(;;) {
+    for (;;) {
         pstart = p;
         p = qemu_strchrnul(p, '|');
-        if ((p - pstart) == len && !memcmp(pstart, name, len))
+        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
             return 1;
-        if (*p == '\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 = buf;
-    p = *pp;
-    while (qemu_isspace(*p)) {
-        p++;
-    }
-    if (*p == '\0') {
-    fail:
-        *q = '\0';
-        *pp = p;
-        return -1;
-    }
-    if (*p == '\"') {
-        p++;
-        while (*p != '\0' && *p != '\"') {
-            if (*p == '\\') {
-                p++;
-                c = *p++;
-                switch (c) {
-                case 'n':
-                    c = '\n';
-                    break;
-                case 'r':
-                    c = '\r';
-                    break;
-                case '\\':
-                case '\'':
-                case '\"':
-                    break;
-                default:
-                    printf("unsupported escape code: '\\%c'\n", c);
-                    goto fail;
-                }
-                if ((q - buf) < buf_size - 1) {
-                    *q++ = c;
-                }
-            } else {
-                if ((q - buf) < buf_size - 1) {
-                    *q++ = *p;
-                }
-                p++;
-            }
-        }
-        if (*p != '\"') {
-            printf("unterminated string\n");
-            goto fail;
-        }
-        p++;
-    } else {
-        while (*p != '\0' && !qemu_isspace(*p)) {
-            if ((q - buf) < buf_size - 1) {
-                *q++ = *p;
-            }
-            p++;
-        }
-    }
-    *q = '\0';
-    *pp = p;
-    return 0;
-}
-
-#define MAX_ARGS 16
-
-static void free_cmdline_args(char **args, int nb_args)
-{
-    int i;
-
-    assert(nb_args <= MAX_ARGS);
-
-    for (i = 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. Number
- *       of args have a limit of MAX_ARGS. If cmdline contains more, it will
- *       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 = cmdline;
-    nb_args = 0;
-    for (;;) {
-        while (qemu_isspace(*p)) {
-            p++;
         }
         if (*p == '\0') {
             break;
         }
-        if (nb_args >= MAX_ARGS) {
-            goto fail;
-        }
-        ret = get_str(buf, sizeof(buf), &p);
-        if (ret < 0) {
-            goto fail;
-        }
-        args[nb_args] = g_strdup(buf);
-        nb_args++;
+        p++;
     }
-    *pnb_args = 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 = 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 >= nb_args) {
-        for (cmd = cmds; cmd->name != NULL; cmd++) {
-            help_cmd_dump_one(mon, cmd, args, arg_index);
-        }
-        return;
-    }
-
-    /* Find one entry to dump */
-    for (cmd = cmds; cmd->name != 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 = 0; i <= arg_index; i++) {
-        monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
-    }
-}
-
-static void help_cmd(Monitor *mon, const char *name)
-{
-    char *args[MAX_ARGS];
-    int nb_args = 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 = qemu_log_items; item->mask != 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 void do_help_cmd(Monitor *mon, const QDict *qdict)
@@ -2510,30 +2260,16 @@ static HMPCommand hmp_info_cmds[] = {
 };
 
 /* hmp_cmds and hmp_info_cmds would be sorted at runtime */
-static HMPCommand hmp_cmds[] = {
+HMPCommand hmp_cmds[] = {
 #include "hmp-commands.h"
     { NULL, NULL, },
 };
 
-/*******************************************************************/
-
-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 = target_monitor_defs();
     CPUState *cs = mon_get_cpu();
@@ -2546,7 +2282,7 @@ static int get_monitor_def(target_long *pval, const char *name)
     }
 
     for(; md->name != NULL; md++) {
-        if (compare_cmd(name, md->name)) {
+        if (hmp_compare_cmd(name, md->name)) {
             if (md->get_value) {
                 *pval = md->get_value(md, md->offset);
             } else {
@@ -2576,829 +2312,6 @@ static int get_monitor_def(target_long *pval, const char *name)
     return ret;
 }
 
-static void next(void)
-{
-    if (*pch != '\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 = expr_unary(mon);
-        break;
-    case '-':
-        next();
-        n = -expr_unary(mon);
-        break;
-    case '~':
-        next();
-        n = ~expr_unary(mon);
-        break;
-    case '(':
-        next();
-        n = expr_sum(mon);
-        if (*pch != ')') {
-            expr_error(mon, "')' expected");
-        }
-        next();
-        break;
-    case '\'':
-        pch++;
-        if (*pch == '\0')
-            expr_error(mon, "character constant expected");
-        n = *pch;
-        pch++;
-        if (*pch != '\'')
-            expr_error(mon, "missing terminating \' character");
-        next();
-        break;
-    case '$':
-        {
-            char buf[128], *q;
-            target_long reg=0;
-
-            pch++;
-            q = buf;
-            while ((*pch >= 'a' && *pch <= 'z') ||
-                   (*pch >= 'A' && *pch <= 'Z') ||
-                   (*pch >= '0' && *pch <= '9') ||
-                   *pch == '_' || *pch == '.') {
-                if ((q - buf) < sizeof(buf) - 1)
-                    *q++ = *pch;
-                pch++;
-            }
-            while (qemu_isspace(*pch))
-                pch++;
-            *q = 0;
-            ret = get_monitor_def(&reg, buf);
-            if (ret < 0)
-                expr_error(mon, "unknown register");
-            n = reg;
-        }
-        break;
-    case '\0':
-        expr_error(mon, "unexpected end of expression");
-        n = 0;
-        break;
-    default:
-        errno = 0;
-        n = strtoull(pch, &p, 0);
-        if (errno == ERANGE) {
-            expr_error(mon, "number too large");
-        }
-        if (pch == p) {
-            expr_error(mon, "invalid char '%c' in expression", *p);
-        }
-        pch = p;
-        while (qemu_isspace(*pch))
-            pch++;
-        break;
-    }
-    return n;
-}
-
-
-static int64_t expr_prod(Monitor *mon)
-{
-    int64_t val, val2;
-    int op;
-
-    val = expr_unary(mon);
-    for(;;) {
-        op = *pch;
-        if (op != '*' && op != '/' && op != '%')
-            break;
-        next();
-        val2 = expr_unary(mon);
-        switch(op) {
-        default:
-        case '*':
-            val *= val2;
-            break;
-        case '/':
-        case '%':
-            if (val2 == 0)
-                expr_error(mon, "division by zero");
-            if (op == '/')
-                val /= val2;
-            else
-                val %= val2;
-            break;
-        }
-    }
-    return val;
-}
-
-static int64_t expr_logic(Monitor *mon)
-{
-    int64_t val, val2;
-    int op;
-
-    val = expr_prod(mon);
-    for(;;) {
-        op = *pch;
-        if (op != '&' && op != '|' && op != '^')
-            break;
-        next();
-        val2 = expr_prod(mon);
-        switch(op) {
-        default:
-        case '&':
-            val &= val2;
-            break;
-        case '|':
-            val |= val2;
-            break;
-        case '^':
-            val ^= val2;
-            break;
-        }
-    }
-    return val;
-}
-
-static int64_t expr_sum(Monitor *mon)
-{
-    int64_t val, val2;
-    int op;
-
-    val = expr_logic(mon);
-    for(;;) {
-        op = *pch;
-        if (op != '+' && op != '-')
-            break;
-        next();
-        val2 = expr_logic(mon);
-        if (op == '+')
-            val += val2;
-        else
-            val -= val2;
-    }
-    return val;
-}
-
-static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
-{
-    pch = *pp;
-    if (sigsetjmp(expr_env, 0)) {
-        *pp = pch;
-        return -1;
-    }
-    while (qemu_isspace(*pch))
-        pch++;
-    *pval = expr_sum(mon);
-    *pp = pch;
-    return 0;
-}
-
-static int get_double(Monitor *mon, double *pval, const char **pp)
-{
-    const char *p = *pp;
-    char *tailp;
-    double d;
-
-    d = strtod(p, &tailp);
-    if (tailp == p) {
-        monitor_printf(mon, "Number expected\n");
-        return -1;
-    }
-    if (d != d || d - d != 0) {
-        /* NaN or infinity */
-        monitor_printf(mon, "Bad number\n");
-        return -1;
-    }
-    *pval = d;
-    *pp = 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 = cmdline;
-    while (qemu_isspace(*p))
-        p++;
-    if (*p == '\0')
-        return NULL;
-    pstart = p;
-    while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
-        p++;
-    len = p - pstart;
-    if (len > nlen - 1)
-        len = nlen - 1;
-    memcpy(cmdname, pstart, len);
-    cmdname[len] = '\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 == ',')
-        type++;
-
-    p = strchr(type, ':');
-    if (!p) {
-        *key = NULL;
-        return NULL;
-    }
-    len = p - type;
-
-    str = g_malloc(len + 1);
-    memcpy(str, type, len);
-    str[len] = '\0';
-
-    *key = str;
-    return ++p;
-}
-
-static int default_fmt_format = 'x';
-static int default_fmt_size = 4;
-
-static int is_valid_option(const char *c, const char *typestr)
-{
-    char option[3];
-  
-    option[0] = '-';
-    option[1] = *c;
-    option[2] = '\0';
-  
-    typestr = strstr(typestr, option);
-    return (typestr != NULL);
-}
-
-static const HMPCommand *search_dispatch_table(const HMPCommand *disp_table,
-                                               const char *cmdname)
-{
-    const HMPCommand *cmd;
-
-    for (cmd = disp_table; cmd->name != 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 = &hmp_mon->common;
-    const char *p;
-    const HMPCommand *cmd;
-    char cmdname[256];
-
-    /* extract the command name */
-    p = get_command_name(*cmdp, cmdname, sizeof(cmdname));
-    if (!p)
-        return NULL;
-
-    cmd = 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 = p;
-    /* search sub command */
-    if (cmd->sub_table != NULL && *p != '\0') {
-        return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table);
-    }
-
-    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 = *endp;
-    char buf[1024];
-    QDict *qdict = qdict_new();
-
-    /* parse the parameters */
-    typestr = cmd->args_type;
-    for(;;) {
-        typestr = key_get_info(typestr, &key);
-        if (!typestr)
-            break;
-        c = *typestr;
-        typestr++;
-        switch(c) {
-        case 'F':
-        case 'B':
-        case 's':
-            {
-                int ret;
-
-                while (qemu_isspace(*p))
-                    p++;
-                if (*typestr == '?') {
-                    typestr++;
-                    if (*p == '\0') {
-                        /* no optional string: NULL argument */
-                        break;
-                    }
-                }
-                ret = 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 expected\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 = 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 = 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 == '/') {
-                    /* format found */
-                    p++;
-                    count = 1;
-                    if (qemu_isdigit(*p)) {
-                        count = 0;
-                        while (qemu_isdigit(*p)) {
-                            count = count * 10 + (*p - '0');
-                            p++;
-                        }
-                    }
-                    size = -1;
-                    format = -1;
-                    for(;;) {
-                        switch(*p) {
-                        case 'o':
-                        case 'd':
-                        case 'u':
-                        case 'x':
-                        case 'i':
-                        case 'c':
-                            format = *p++;
-                            break;
-                        case 'b':
-                            size = 1;
-                            p++;
-                            break;
-                        case 'h':
-                            size = 2;
-                            p++;
-                            break;
-                        case 'w':
-                            size = 4;
-                            p++;
-                            break;
-                        case 'g':
-                        case 'L':
-                            size = 8;
-                            p++;
-                            break;
-                        default:
-                            goto next;
-                        }
-                    }
-                next:
-                    if (*p != '\0' && !qemu_isspace(*p)) {
-                        monitor_printf(mon, "invalid char in format: '%c'\n",
-                                       *p);
-                        goto fail;
-                    }
-                    if (format < 0)
-                        format = default_fmt_format;
-                    if (format != 'i') {
-                        /* for 'i', not specifying a size gives -1 as size */
-                        if (size < 0)
-                            size = default_fmt_size;
-                        default_fmt_size = size;
-                    }
-                    default_fmt_format = format;
-                } else {
-                    count = 1;
-                    format = default_fmt_format;
-                    if (format != 'i') {
-                        size = default_fmt_size;
-                    } else {
-                        size = -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 == '?' || *typestr == '.') {
-                    if (*typestr == '?') {
-                        if (*p == '\0') {
-                            typestr++;
-                            break;
-                        }
-                    } else {
-                        if (*p == '.') {
-                            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 == '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 == 'M') {
-                    if (val < 0) {
-                        monitor_printf(mon, "enter a positive value\n");
-                        goto fail;
-                    }
-                    val *= 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 == '?') {
-                    typestr++;
-                    if (*p == '\0') {
-                        break;
-                    }
-                }
-                ret = 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 = end;
-            }
-            break;
-        case 'T':
-            {
-                double val;
-
-                while (qemu_isspace(*p))
-                    p++;
-                if (*typestr == '?') {
-                    typestr++;
-                    if (*p == '\0') {
-                        break;
-                    }
-                }
-                if (get_double(mon, &val, &p) < 0) {
-                    goto fail;
-                }
-                if (p[0] && p[1] == 's') {
-                    switch (*p) {
-                    case 'm':
-                        val /= 1e3; p += 2; break;
-                    case 'u':
-                        val /= 1e6; p += 2; break;
-                    case 'n':
-                        val /= 1e9; p += 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 = p;
-                while (qemu_isgraph(*p)) {
-                    p++;
-                }
-                if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
-                    val = true;
-                } else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
-                    val = false;
-                } else {
-                    monitor_printf(mon, "Expected 'on' or 'off'\n");
-                    goto fail;
-                }
-                qdict_put_bool(qdict, key, val);
-            }
-            break;
-        case '-':
-            {
-                const char *tmp = p;
-                int skip_key = 0;
-                /* option */
-
-                c = *typestr++;
-                if (c == '\0')
-                    goto bad_type;
-                while (qemu_isspace(*p))
-                    p++;
-                if (*p == '-') {
-                    p++;
-                    if(c != *p) {
-                        if(!is_valid_option(p, typestr)) {
-                  
-                            monitor_printf(mon, "%s: unsupported option -%c\n",
-                                           cmd->name, *p);
-                            goto fail;
-                        } else {
-                            skip_key = 1;
-                        }
-                    }
-                    if(skip_key) {
-                        p = 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 == '?') {
-                    typestr++;
-                    if (*p == '\0') {
-                        /* no remaining string: NULL argument */
-                        break;
-                    }
-                }
-                len = strlen(p);
-                if (len <= 0) {
-                    monitor_printf(mon, "%s: string expected\n",
-                                   cmd->name);
-                    goto fail;
-                }
-                qdict_put_str(qdict, key, p);
-                p += len;
-            }
-            break;
-        default:
-        bad_type:
-            monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c);
-            goto fail;
-        }
-        g_free(key);
-        key = NULL;
-    }
-    /* check that all arguments were parsed */
-    while (qemu_isspace(*p))
-        p++;
-    if (*p != '\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 = cmdline;
-
-    trace_handle_hmp_command(mon, cmdline);
-
-    cmd = monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds);
-    if (!cmd) {
-        return;
-    }
-
-    qdict = 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 information\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 = list;
-    for(;;) {
-        pstart = p;
-        p = qemu_strchrnul(p, '|');
-        len = p - pstart;
-        if (len > sizeof(cmd) - 2)
-            len = sizeof(cmd) - 2;
-        memcpy(cmd, pstart, len);
-        cmd[len] = '\0';
-        if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
-            readline_add_completion(mon->rs, cmd);
-        }
-        if (*p == '\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 = strrchr(input, '/');
-    if (!p) {
-        input_path_len = 0;
-        pstrcpy(file_prefix, sizeof(file_prefix), input);
-        pstrcpy(path, sizeof(path), ".");
-    } else {
-        input_path_len = p - input + 1;
-        memcpy(path, input, input_path_len);
-        if (input_path_len > sizeof(path) - 1)
-            input_path_len = sizeof(path) - 1;
-        path[input_path_len] = '\0';
-        pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
-    }
-
-    ffs = opendir(path);
-    if (!ffs)
-        return;
-    for(;;) {
-        struct stat sb;
-        d = readdir(ffs);
-        if (!d)
-            break;
-
-        if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 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_len,
-                        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) == 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 = strchr(typestr, ':');
-    return (p != 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_args, const char *str)
     }
 }
 
-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 = NULL;
-
-    if (nb_args <= 1) {
-        /* command completion */
-        if (nb_args == 0)
-            cmdname = "";
-        else
-            cmdname = args[0];
-        readline_set_completion_index(mon->rs, strlen(cmdname));
-        for (cmd = cmd_table; cmd->name != NULL; cmd++) {
-            if (!runstate_check(RUN_STATE_PRECONFIG) ||
-                 cmd_can_preconfig(cmd)) {
-                cmd_completion(mon, cmdname, cmd->name);
-            }
-        }
-    } else {
-        /* find the command */
-        for (cmd = cmd_table; cmd->name != 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 = next_arg_type(cmd->args_type);
-        for(i = 0; i < nb_args - 2; i++) {
-            if (*ptype != '\0') {
-                ptype = next_arg_type(ptype);
-                while (*ptype == '?')
-                    ptype = next_arg_type(ptype);
-            }
-        }
-        str = args[nb_args - 1];
-        old_ptype = NULL;
-        while (*ptype == '-' && old_ptype != ptype) {
-            old_ptype = ptype;
-            ptype = 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 = blk_next(blk)) != NULL) {
-                name = blk_name(blk);
-                if (str[0] == '\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 = 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 = strlen(cmdline);
-    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
-        if (nb_args >= MAX_ARGS) {
-            goto cleanup;
-        }
-        args[nb_args++] = 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 = opaque;
@@ -3957,38 +2749,6 @@ int monitor_can_read(void *opaque)
     return !atomic_mb_read(&mon->suspend_cnt);
 }
 
-static void monitor_read(void *opaque, const uint8_t *buf, int size)
-{
-    MonitorHMP *mon;
-    Monitor *old_mon = cur_mon;
-    int i;
-
-    cur_mon = opaque;
-    mon = container_of(cur_mon, MonitorHMP, common);
-
-    if (mon->rs) {
-        for (i = 0; i < size; i++)
-            readline_handle_byte(mon->rs, buf[i]);
-    } else {
-        if (size == 0 || buf[size - 1] != 0)
-            monitor_printf(cur_mon, "corrupted command\n");
-        else
-            handle_hmp_command(mon, (char *)buf);
-    }
-
-    cur_mon = old_mon;
-}
-
-static void monitor_command_cb(void *opaque, const char *cmdline,
-                               void *readline_opaque)
-{
-    MonitorHMP *mon = 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);
 }
 
-static void monitor_event(void *opaque, int event)
-{
-    Monitor *mon = opaque;
-    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
-
-    switch (event) {
-    case CHR_EVENT_MUX_IN:
-        qemu_mutex_lock(&mon->mon_lock);
-        mon->mux_out = 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) == 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 = 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 = 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);
 }
 
-/* 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 = 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 = 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)
     }
 }
 
-static void monitor_init_hmp(Chardev *chr, int flags)
-{
-    MonitorHMP *mon = g_malloc0(sizeof(*mon));
-    bool use_readline = 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 = 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_read,
-                             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 += misc.o
-common-obj-y += qmp.o
+common-obj-y += qmp.o hmp.o
 common-obj-y += 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.
 
+# 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=%d data=%p"
 monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
 monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64
-handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s"
 monitor_suspend(void *ptr, int cnt) "mon %p: %d"
 
 # qmp.c
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (10 preceding siblings ...)
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c Kevin Wolf
@ 2019-06-13 15:34 ` Kevin Wolf
  2019-06-14  8:29   ` Markus Armbruster
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools Kevin Wolf
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
---
 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);
 
 void monitor_init_globals(void);
+void monitor_init_globals_core(void);
 void monitor_init(Chardev *chr, int flags);
 void monitor_cleanup(void);
 
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;
 };
 
-/*
- * 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
 
-/* 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;
 
-int mon_refcount;
-
 static HMPCommand hmp_info_cmds[];
 
-__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 = opaque;
-
-    qemu_mutex_lock(&mon->mon_lock);
-    mon->out_watch = 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 = qstring_get_str(mon->outbuf);
-    len = qstring_get_length(mon->outbuf);
-
-    if (len && !mon->mux_out) {
-        rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len);
-        if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
-            /* all flushed or error */
-            qobject_unref(mon->outbuf);
-            mon->outbuf = qstring_new();
-            return;
-        }
-        if (rc > 0) {
-            /* partial write */
-            QString *tmp = qstring_from_str(buf + rc);
-            qobject_unref(mon->outbuf);
-            mon->outbuf = tmp;
-        }
-        if (mon->out_watch == 0) {
-            mon->out_watch =
-                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 = 0; str[i]; i++) {
-        c = str[i];
-        if (c == '\n') {
-            qstring_append_chr(mon->outbuf, '\r');
-        }
-        qstring_append_chr(mon->outbuf, c);
-        if (c == '\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 = g_strdup_vprintf(fmt, ap);
-    n = 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 = monitor_vprintf(mon, fmt, ap);
-    va_end(ap);
-    return ret;
-}
-
-static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
-    /* Limit guest-triggerable events to 1 per second */
-    [QAPI_EVENT_RTC_CHANGE]        = { 1000 * SCALE_MS },
-    [QAPI_EVENT_WATCHDOG]          = { 1000 * SCALE_MS },
-    [QAPI_EVENT_BALLOON_CHANGE]    = { 1000 * SCALE_MS },
-    [QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS },
-    [QAPI_EVENT_QUORUM_FAILURE]    = { 1000 * SCALE_MS },
-    [QAPI_EVENT_VSERPORT_CHANGE]   = { 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 = container_of(mon, MonitorQMP, common);
-        if (qmp_mon->commands != &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 = &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 = qobject_to(QDict, qdict_get(qdict, "data"));
-        MonitorQAPIEventState key = { .event = event, .data = data };
-
-        evstate = 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 = 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 = qemu_clock_get_ns(monitor_get_event_clock());
-
-            monitor_qapi_event_emit(event, qdict);
-
-            evstate = g_new(MonitorQAPIEventState, 1);
-            evstate->event = event;
-            evstate->data = qobject_ref(data);
-            evstate->qdict = NULL;
-            evstate->timer = 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 = g_new(MonitorQapiEvent, 1);
-    ev->qdict = qobject_ref(qdict);
-    ev->event = event;
-    QSIMPLEQ_INSERT_TAIL(&event_queue, ev, entry);
-    if (reentered) {
-        return;
-    }
-
-    reentered = true;
-
-    while ((ev = QSIMPLEQ_FIRST(&event_queue)) != 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 = 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 = opaque;
-    MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
-
-    trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
-    qemu_mutex_lock(&monitor_lock);
-
-    if (evstate->qdict) {
-        int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
-
-        monitor_qapi_event_emit(evstate->event, evstate->qdict);
-        qobject_unref(evstate->qdict);
-        evstate->qdict = 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 = key;
-    unsigned int hash = evstate->event * 255;
-
-    if (evstate->event == QAPI_EVENT_VSERPORT_CHANGE) {
-        hash += g_str_hash(qdict_get_str(evstate->data, "id"));
-    }
-
-    if (evstate->event == QAPI_EVENT_QUORUM_REPORT_BAD) {
-        hash += 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 = a;
-    const MonitorQAPIEventState *evb = b;
-
-    if (eva->event != evb->event) {
-        return FALSE;
-    }
-
-    if (eva->event == QAPI_EVENT_VSERPORT_CHANGE) {
-        return !strcmp(qdict_get_str(eva->data, "id"),
-                       qdict_get_str(evb->data, "id"));
-    }
-
-    if (eva->event == 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 = 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 = qstring_new();
-    mon->skip_flush = skip_flush;
-    mon->use_io_thread = use_io_thread;
-    mon->flags = 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 = container_of(mon, MonitorQMP, common);
-        monitor_data_destroy_qmp(qmp_mon);
-    } else {
-        MonitorHMP *hmp_mon = 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_index,
                                 int64_t cpu_index, Error **errp)
 {
@@ -2742,67 +2327,6 @@ void loadvm_completion(ReadLineState *rs, int nb_args, const char *str)
     }
 }
 
-int monitor_can_read(void *opaque)
-{
-    Monitor *mon = 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 = 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) == 0) {
-        AioContext *ctx;
-
-        if (mon->use_io_thread) {
-            ctx = iothread_get_aio_context(mon_iothread);
-        } else {
-            ctx = qemu_get_aio_context();
-        }
-
-        if (!monitor_is_qmp(mon)) {
-            MonitorHMP *hmp_mon = 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);
 }
 
-static void monitor_iothread_init(void)
-{
-    mon_iothread = 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 = 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 = 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);
-    }
 }
 
-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 = true;
-    while (!QTAILQ_EMPTY(&mon_list)) {
-        Monitor *mon = 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 = NULL;
-    if (mon_iothread) {
-        iothread_destroy(mon_iothread);
-        mon_iothread = NULL;
-    }
-}
-
-QemuOptsList qemu_mon_opts = {
-    .name = "mon",
-    .implied_opt_name = "chardev",
-    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
-    .desc = {
-        {
-            .name = "mode",
-            .type = QEMU_OPT_STRING,
-        },{
-            .name = "chardev",
-            .type = QEMU_OPT_STRING,
-        },{
-            .name = "pretty",
-            .type = QEMU_OPT_BOOL,
-        },
-        { /* end of list */ }
-    },
-};
-
 HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
 {
     MachineState *ms = 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"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * 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 OTHER
+ * 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 = opaque;
+
+    qemu_mutex_lock(&mon->mon_lock);
+    mon->out_watch = 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 = qstring_get_str(mon->outbuf);
+    len = qstring_get_length(mon->outbuf);
+
+    if (len && !mon->mux_out) {
+        rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len);
+        if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
+            /* all flushed or error */
+            qobject_unref(mon->outbuf);
+            mon->outbuf = qstring_new();
+            return;
+        }
+        if (rc > 0) {
+            /* partial write */
+            QString *tmp = qstring_from_str(buf + rc);
+            qobject_unref(mon->outbuf);
+            mon->outbuf = tmp;
+        }
+        if (mon->out_watch == 0) {
+            mon->out_watch =
+                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 = 0; str[i]; i++) {
+        c = str[i];
+        if (c == '\n') {
+            qstring_append_chr(mon->outbuf, '\r');
+        }
+        qstring_append_chr(mon->outbuf, c);
+        if (c == '\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 = g_strdup_vprintf(fmt, ap);
+    n = 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 = 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] = {
+    /* Limit guest-triggerable events to 1 per second */
+    [QAPI_EVENT_RTC_CHANGE]        = { 1000 * SCALE_MS },
+    [QAPI_EVENT_WATCHDOG]          = { 1000 * SCALE_MS },
+    [QAPI_EVENT_BALLOON_CHANGE]    = { 1000 * SCALE_MS },
+    [QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS },
+    [QAPI_EVENT_QUORUM_FAILURE]    = { 1000 * SCALE_MS },
+    [QAPI_EVENT_VSERPORT_CHANGE]   = { 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 = container_of(mon, MonitorQMP, common);
+        if (qmp_mon->commands != &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 = &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 = qobject_to(QDict, qdict_get(qdict, "data"));
+        MonitorQAPIEventState key = { .event = event, .data = data };
+
+        evstate = 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 = 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 = qemu_clock_get_ns(monitor_get_event_clock());
+
+            monitor_qapi_event_emit(event, qdict);
+
+            evstate = g_new(MonitorQAPIEventState, 1);
+            evstate->event = event;
+            evstate->data = qobject_ref(data);
+            evstate->qdict = NULL;
+            evstate->timer = 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 = g_new(MonitorQapiEvent, 1);
+    ev->qdict = qobject_ref(qdict);
+    ev->event = event;
+    QSIMPLEQ_INSERT_TAIL(&event_queue, ev, entry);
+    if (reentered) {
+        return;
+    }
+
+    reentered = true;
+
+    while ((ev = QSIMPLEQ_FIRST(&event_queue)) != 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 = 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 = opaque;
+    MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
+
+    trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
+    qemu_mutex_lock(&monitor_lock);
+
+    if (evstate->qdict) {
+        int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
+
+        monitor_qapi_event_emit(evstate->event, evstate->qdict);
+        qobject_unref(evstate->qdict);
+        evstate->qdict = 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 = key;
+    unsigned int hash = evstate->event * 255;
+
+    if (evstate->event == QAPI_EVENT_VSERPORT_CHANGE) {
+        hash += g_str_hash(qdict_get_str(evstate->data, "id"));
+    }
+
+    if (evstate->event == QAPI_EVENT_QUORUM_REPORT_BAD) {
+        hash += 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 = a;
+    const MonitorQAPIEventState *evb = b;
+
+    if (eva->event != evb->event) {
+        return FALSE;
+    }
+
+    if (eva->event == QAPI_EVENT_VSERPORT_CHANGE) {
+        return !strcmp(qdict_get_str(eva->data, "id"),
+                       qdict_get_str(evb->data, "id"));
+    }
+
+    if (eva->event == 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 = 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) == 0) {
+        AioContext *ctx;
+
+        if (mon->use_io_thread) {
+            ctx = iothread_get_aio_context(mon_iothread);
+        } else {
+            ctx = qemu_get_aio_context();
+        }
+
+        if (!monitor_is_qmp(mon)) {
+            MonitorHMP *hmp_mon = 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 = 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 = NULL;
+    }
+    qemu_mutex_unlock(&monitor_lock);
+
+    if (mon) {
+        monitor_data_destroy(mon);
+        g_free(mon);
+    }
+}
+
+static void monitor_iothread_init(void)
+{
+    mon_iothread = 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 = qstring_new();
+    mon->skip_flush = skip_flush;
+    mon->use_io_thread = use_io_thread;
+    mon->flags = 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 = container_of(mon, MonitorQMP, common);
+        monitor_data_destroy_qmp(qmp_mon);
+    } else {
+        MonitorHMP *hmp_mon = 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 = true;
+    while (!QTAILQ_EMPTY(&mon_list)) {
+        Monitor *mon = 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 = NULL;
+    if (mon_iothread) {
+        iothread_destroy(mon_iothread);
+        mon_iothread = NULL;
+    }
+}
+
+static void monitor_qapi_event_init(void)
+{
+    monitor_qapi_event_state = 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 = aio_bh_new(iohandler_get_aio_context(),
+                                   monitor_qmp_bh_dispatcher,
+                                   NULL);
+}
+
+QemuOptsList qemu_mon_opts = {
+    .name = "mon",
+    .implied_opt_name = "chardev",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
+    .desc = {
+        {
+            .name = "mode",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "chardev",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "pretty",
+            .type = 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 <dgilbert@redhat.com>
 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 += misc.o
-common-obj-y += qmp.o hmp.o
+common-obj-y += monitor.o qmp.o hmp.o
 common-obj-y += 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"
 
-# misc.c
+# monitor.c
 monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p"
 monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
 monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (11 preceding siblings ...)
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c Kevin Wolf
@ 2019-06-13 15:34 ` Kevin Wolf
  2019-06-14  8:48   ` Markus Armbruster
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}() Kevin Wolf
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
---
 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;
 
@@ -116,6 +116,7 @@ struct Monitor {
 
 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 happen
@@ -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;
 }
 
 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);
 
 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 = g_malloc0(sizeof(*mon));
-    bool use_readline = flags & MONITOR_USE_READLINE;
 
-    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);
 
-    if (use_readline) {
+    mon->use_readline = flags & MONITOR_USE_READLINE;
+    if (mon->use_readline) {
         mon->rs = 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_line, bool has_cpu_index,
     Monitor *old_mon;
     MonitorHMP hmp = {};
 
-    monitor_data_init(&hmp.common, 0, true, false);
+    monitor_data_init(&hmp.common, false, true, false);
 
     old_mon = cur_mon;
     cur_mon = &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;
 }
 
 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));
 }
 
 static void monitor_flush_locked(Monitor *mon);
@@ -523,17 +527,17 @@ static void monitor_iothread_init(void)
     mon_iothread = iothread_create("mon_iothread", &error_abort);
 }
 
-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 = is_qmp;
     mon->outbuf = qstring_new();
     mon->skip_flush = skip_flush;
     mon->use_io_thread = use_io_thread;
-    mon->flags = flags;
 }
 
 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 = QOBJECT(rsp);
     QString *json;
 
-    json = mon->common.flags & MONITOR_USE_PRETTY ?
-           qobject_to_json_pretty(data) : qobject_to_json(data);
+    json = mon->pretty ? qobject_to_json_pretty(data) : qobject_to_json(data);
     assert(json != NULL);
 
     qstring_append_chr(json, '\n');
@@ -372,9 +371,11 @@ void monitor_init_qmp(Chardev *chr, int flags)
     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,
+    monitor_data_init(&mon->common, true, false,
                       qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
 
+    mon->pretty = flags & MONITOR_USE_PRETTY;
+
     qemu_mutex_init(&mon->qmp_queue_lock);
     mon->qmp_requests = g_queue_new();
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}()
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (12 preceding siblings ...)
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools Kevin Wolf
@ 2019-06-13 15:34 ` Kevin Wolf
  2019-06-14  8:50   ` Markus Armbruster
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors Kevin Wolf
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

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 <kwolf@redhat.com>
---
 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;
 
-/* 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
 
 bool monitor_cur_is_qmp(void);
 
 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);
 
 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;
 
 extern HMPCommand hmp_cmds[];
 
-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,
 
     if (qemu_opt_get_bool(opts, "mux", 0)) {
         assert(permit_mux_mon);
-        monitor_init(chr, MONITOR_USE_READLINE);
+        monitor_init_hmp(chr, true);
     }
 
 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 = 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 = 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);
 }
 
-void monitor_init_hmp(Chardev *chr, int flags)
+void monitor_init_hmp(Chardev *chr, bool use_readline)
 {
     MonitorHMP *mon = g_malloc0(sizeof(*mon));
 
     monitor_data_init(&mon->common, false, false, false);
     qemu_chr_fe_init(&mon->common.chr, chr, &error_abort);
 
-    mon->use_readline = flags & MONITOR_USE_READLINE;
+    mon->use_readline = use_readline;
     if (mon->use_readline) {
         mon->rs = 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);
 }
 
-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 *opaque)
     monitor_list_append(&mon->common);
 }
 
-void monitor_init_qmp(Chardev *chr, int flags)
+void monitor_init_qmp(Chardev *chr, bool pretty)
 {
     MonitorQMP *mon = 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, true, false,
                       qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
 
-    mon->pretty = flags & MONITOR_USE_PRETTY;
+    mon->pretty = pretty;
 
     qemu_mutex_init(&mon->qmp_queue_lock);
     mon->qmp_requests = 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;
 }
 
-void monitor_init(Chardev *chr, int flags)
+void monitor_init_qmp(Chardev *chr, bool pretty)
+{
+}
+
+void monitor_init_hmp(Chardev *chr, bool use_readline)
 {
 }
 
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, Error **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) {}
 
 
 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 = false;
     const char *chardev;
     const char *mode;
-    int flags;
 
     mode = qemu_opt_get(opts, "mode");
     if (mode == NULL) {
         mode = "readline";
     }
     if (strcmp(mode, "readline") == 0) {
-        flags = MONITOR_USE_READLINE;
+        qmp = false;
     } else if (strcmp(mode, "control") == 0) {
-        flags = MONITOR_USE_CONTROL;
+        qmp = true;
     } else {
         error_setg(errp, "unknown monitor mode \"%s\"", mode);
         return -1;
     }
 
-    if (qemu_opt_get_bool(opts, "pretty", 0))
-        flags |= MONITOR_USE_PRETTY;
+    if (qemu_opt_get_bool(opts, "pretty", 0)) {
+        pretty = true;
+    }
 
     chardev = qemu_opt_get(opts, "chardev");
     if (!chardev) {
@@ -2330,7 +2332,11 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
         return -1;
     }
 
-    monitor_init(chr, flags);
+    if (qmp) {
+        monitor_init_qmp(chr, pretty);
+    } else {
+        monitor_init_hmp(chr, true);
+    }
     return 0;
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (13 preceding siblings ...)
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}() Kevin Wolf
@ 2019-06-13 15:34 ` Kevin Wolf
  2019-06-14  9:01   ` Markus Armbruster
  2019-06-13 17:31 ` [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc no-reply
  2019-06-14  9:06 ` Markus Armbruster
  16 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-13 15:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

The -mon pretty=on|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 <kwolf@redhat.com>
---
 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 *opts, Error **errp)
         return -1;
     }
 
+    if (!qmp && qemu_opt_get(opts, "pretty")) {
+        warn_report("'pretty' is deprecated for HMP monitors, it has no effect "
+                    "and will be removed in future versions");
+    }
     if (qemu_opt_get_bool(opts, "pretty", 0)) {
         pretty = true;
     }
@@ -2362,7 +2366,11 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty)
     opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, &error_fatal);
     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 == false);
+    }
     monitor_device_index++;
 }
 
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 ease migration to
 the new format, the ``-audiodev-help'' option can be used to convert
 the current values of the environment variables to ``-audiodev'' options.
 
+@subsection -mon ...,control=readline,pretty=on|off (since 4.1)
+
+The @code{pretty=on|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)
 
 The @code{-realtime mlock=on|off} argument has been replaced by the
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (14 preceding siblings ...)
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors Kevin Wolf
@ 2019-06-13 17:31 ` no-reply
  2019-06-14  9:06 ` Markus Armbruster
  16 siblings, 0 replies; 40+ messages in thread
From: no-reply @ 2019-06-13 17:31 UTC (permalink / raw)
  To: kwolf; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert, qemu-devel

Patchew URL: https://patchew.org/QEMU/20190613153405.24769-1-kwolf@redhat.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Message-id: 20190613153405.24769-1-kwolf@redhat.com
Subject: [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
Type: series

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
6d522fb vl: Deprecate -mon pretty=... for HMP monitors
e34ac59 monitor: Replace monitor_init() with monitor_init_{hmp, qmp}()
e75b96d monitor: Split Monitor.flags into separate bools
24a36f9 monitor: Split out monitor/monitor.c
27c4127 monitor: Split out monitor/hmp.c
26f727a monitor: Split out monitor/qmp.c
b2685af monitor: Create monitor-internal.h with common definitions
e1f6a6e monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
ea374f7 Move monitor.c to monitor/misc.c
21e390e monitor: Rename HMP command type and tables
3335bfc monitor: Remove Monitor.cmd_table indirection
b935214 monitor: Create MonitorHMP with readline state
0800382 monitor: Make MonitorQMP a child class of Monitor
7c3f4f7 monitor: Split monitor_init in HMP and QMP function
6e68255 monitor: Remove unused password prompting fields

=== OUTPUT BEGIN ===
1/15 Checking commit 6e68255df41e (monitor: Remove unused password prompting fields)
2/15 Checking commit 7c3f4f792c86 (monitor: Split monitor_init in HMP and QMP function)
3/15 Checking commit 080038232dc8 (monitor: Make MonitorQMP a child class of Monitor)
4/15 Checking commit b935214b2c2c (monitor: Create MonitorHMP with readline state)
5/15 Checking commit 3335bfc40060 (monitor: Remove Monitor.cmd_table indirection)
6/15 Checking commit 21e390e01266 (monitor: Rename HMP command type and tables)
ERROR: spaces required around that '/' (ctx:VxV)
#226: FILE: monitor.c:4543:
+    array_num = sizeof(hmp_cmds)/elem_size-1;
                                 ^

ERROR: spaces required around that '-' (ctx:VxV)
#226: FILE: monitor.c:4543:
+    array_num = sizeof(hmp_cmds)/elem_size-1;
                                           ^

ERROR: spaces required around that '/' (ctx:VxV)
#231: FILE: monitor.c:4546:
+    array_num = sizeof(hmp_info_cmds)/elem_size-1;
                                      ^

ERROR: spaces required around that '-' (ctx:VxV)
#231: FILE: monitor.c:4546:
+    array_num = sizeof(hmp_info_cmds)/elem_size-1;
                                                ^

total: 4 errors, 0 warnings, 194 lines checked

Patch 6/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

7/15 Checking commit ea374f7b2aad (Move monitor.c to monitor/misc.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#80: 
new file mode 100644

total: 0 errors, 1 warnings, 78 lines checked

Patch 7/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
8/15 Checking commit e1f6a6ef1c06 (monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#104: 
rename from hmp.c

total: 0 errors, 1 warnings, 73 lines checked

Patch 8/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
9/15 Checking commit b2685af3a437 (monitor: Create monitor-internal.h with common definitions)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#175: 
new file mode 100644

total: 0 errors, 1 warnings, 290 lines checked

Patch 9/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
10/15 Checking commit 26f727a38094 (monitor: Split out monitor/qmp.c)
ERROR: return is not a function, parentheses are not required
#564: FILE: monitor/monitor-internal.h:153:
+    return (mon->flags & MONITOR_USE_CONTROL);

WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#590: 
new file mode 100644

total: 1 errors, 1 warnings, 954 lines checked

Patch 10/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

11/15 Checking commit 27c412749fec (monitor: Split out monitor/hmp.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#28: 
new file mode 100644

ERROR: consider using qemu_strtoull in preference to strtoull
#432: FILE: monitor/hmp.c:400:
+        n = strtoull(pch, &p, 0);

WARNING: Block comments use a leading /* on a separate line
#1314: FILE: monitor/hmp.c:1282:
+    /* if the line ends with a space, it means we want to complete the

WARNING: Block comments use a trailing */ on a separate line
#1315: FILE: monitor/hmp.c:1283:
+     * next arg */

total: 1 errors, 3 warnings, 2919 lines checked

Patch 11/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

12/15 Checking commit 24a36f947bcb (monitor: Split out monitor/monitor.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#725: 
new file mode 100644

WARNING: Block comments use a leading /* on a separate line
#1364: FILE: monitor/monitor.c:635:
+        { /* end of list */ }

total: 0 errors, 2 warnings, 1316 lines checked

Patch 12/15 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
13/15 Checking commit e75b96deb320 (monitor: Split Monitor.flags into separate bools)
14/15 Checking commit e34ac5963a50 (monitor: Replace monitor_init() with monitor_init_{hmp, qmp}())
15/15 Checking commit 6d522fb23163 (vl: Deprecate -mon pretty=... for HMP monitors)
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190613153405.24769-1-kwolf@redhat.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection Kevin Wolf
@ 2019-06-14  5:51   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  5:51 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables Kevin Wolf
@ 2019-06-14  5:52   ` Markus Armbruster
  2019-06-14  6:01   ` Markus Armbruster
  1 sibling, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  5:52 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables Kevin Wolf
  2019-06-14  5:52   ` Markus Armbruster
@ 2019-06-14  6:01   ` Markus Armbruster
  1 sibling, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  6:01 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>

checkpatch.pl gripes:

> ---
>  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
[...]
> @@ -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);
>  }
>  
>  static void sortcmdlist(void)
>  {
>      int array_num;
> -    int elem_size = sizeof(mon_cmd_t);
> +    int elem_size = sizeof(HMPCommand);
>  
> -    array_num = sizeof(mon_cmds)/elem_size-1;
> -    qsort((void *)mon_cmds, array_num, elem_size, compare_mon_cmd);
> +    array_num = sizeof(hmp_cmds)/elem_size-1;

229: ERROR: spaces required around that '/' (ctx:VxV)
229: ERROR: spaces required around that '-' (ctx:VxV)

> +    qsort((void *)hmp_cmds, array_num, elem_size, compare_mon_cmd);
>  
> -    array_num = sizeof(info_cmds)/elem_size-1;
> -    qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
> +    array_num = sizeof(hmp_info_cmds)/elem_size-1;

Likewise.

I figure we should simply use ARRAY_SIZE().

static void sortcmdlist(void)
{
    qsort(hmp_cmds, ARRAY_SIZE(hmp_cmds), sizeof(*hmp_cmds),
          compare_mon_cmd);
    qsort(hmp_info_cmds, ARRAY_SIZE(hmp_info_cmds), sizeof(*hmp_info_cmds),
          compare_mon_cmd);
}

Can touch up in my tree.

> +    qsort((void *)hmp_info_cmds, array_num, elem_size, compare_mon_cmd);
>  }
>  
>  static void monitor_iothread_init(void)
[...]


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c Kevin Wolf
@ 2019-06-14  6:04   ` Markus Armbruster
  2019-06-14  6:25     ` Markus Armbruster
  0 siblings, 1 reply; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  6:04 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
> ---
>  docs/devel/writing-qmp-commands.txt |  2 +-
>  monitor.c => 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 => monitor/misc.c (99%)
>  create mode 100644 monitor/Makefile.objs
>  create mode 100644 monitor/trace-events

I still think we should move hmp.h to include/monitor/.
hmp-commands-info.hx and hmp-commands.hx, too.  Not worth a respin by
itself.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c
  2019-06-14  6:04   ` Markus Armbruster
@ 2019-06-14  6:25     ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  6:25 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Markus Armbruster <armbru@redhat.com> writes:

> Kevin Wolf <kwolf@redhat.com> writes:
>
>> 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 <kwolf@redhat.com>
>> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> Reviewed-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  docs/devel/writing-qmp-commands.txt |  2 +-
>>  monitor.c => 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 => monitor/misc.c (99%)
>>  create mode 100644 monitor/Makefile.objs
>>  create mode 100644 monitor/trace-events
>
> I still think we should move hmp.h to include/monitor/.

Comment applies to the next patch, sorry.

> hmp-commands-info.hx and hmp-commands.hx, too.  Not worth a respin by
> itself.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions Kevin Wolf
@ 2019-06-14  6:37   ` Markus Armbruster
  2019-06-14  8:47     ` Kevin Wolf
  0 siblings, 1 reply; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  6:37 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  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"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * 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 OTHER
> + * 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

Rename to MONITOR_INTERNAL_H, so it again matches the file name.  Can
touch up in my tree.

> +
> +#include "monitor/monitor.h"
> +#include "qapi/qmp/qdict.h"

These too are superfluous.  I'm willing to tolerate monitor.h anyway,
since anything including monitor-internal.h is almost certainly going to
need monitor.h, too.

> +#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"

Another superfluous one.

Happy to drop these two #include in my tree.

[...]

With that:
Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c Kevin Wolf
@ 2019-06-14  6:46   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  6:46 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  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;
>  
> +/**
> + * Is @mon a QMP monitor?
> + */
> +static inline bool monitor_is_qmp(const Monitor *mon)
> +{
> +    return (mon->flags & MONITOR_USE_CONTROL);

checkpatch.pl complains:

    ERROR: return is not a function, parentheses are not required

Can touch up in my tree.

Reviewed-by: Markus Armbruster <armbru@redhat.com>

Two reminders for myself below.

[...]
> 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"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * 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 OTHER
> + * 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;

Note to self: consider fusing these two in a follow-up patch.

> +
> +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] = 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 = QOBJECT(rsp);
> +    QString *json;
> +
> +    json = mon->common.flags & MONITOR_USE_PRETTY ?
> +           qobject_to_json_pretty(data) : qobject_to_json(data);
> +    assert(json != 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);
> +    }
> +}

Note to self: of the two callers, only one can pass null @rsp.
Eliminate this function.

[...]


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c Kevin Wolf
@ 2019-06-14  8:23   ` Markus Armbruster
  2019-06-14  9:17     ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:23 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> ---
[...]
> 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 @@
[...]
> +static int64_t expr_unary(Monitor *mon)
> +{
> +    int64_t n;
> +    char *p;
> +    int ret;
> +
> +    switch (*pch) {
> +    case '+':
> +        next();
> +        n = expr_unary(mon);
> +        break;
> +    case '-':
> +        next();
> +        n = -expr_unary(mon);
> +        break;
> +    case '~':
> +        next();
> +        n = ~expr_unary(mon);
> +        break;
> +    case '(':
> +        next();
> +        n = expr_sum(mon);
> +        if (*pch != ')') {
> +            expr_error(mon, "')' expected");
> +        }
> +        next();
> +        break;
> +    case '\'':
> +        pch++;
> +        if (*pch == '\0') {
> +            expr_error(mon, "character constant expected");
> +        }
> +        n = *pch;
> +        pch++;
> +        if (*pch != '\'') {
> +            expr_error(mon, "missing terminating \' character");
> +        }
> +        next();
> +        break;
> +    case '$':
> +        {
> +            char buf[128], *q;
> +            int64_t reg = 0;
> +
> +            pch++;
> +            q = buf;
> +            while ((*pch >= 'a' && *pch <= 'z') ||
> +                   (*pch >= 'A' && *pch <= 'Z') ||
> +                   (*pch >= '0' && *pch <= '9') ||
> +                   *pch == '_' || *pch == '.') {
> +                if ((q - buf) < sizeof(buf) - 1) {
> +                    *q++ = *pch;
> +                }
> +                pch++;
> +            }
> +            while (qemu_isspace(*pch)) {
> +                pch++;
> +            }
> +            *q = 0;
> +            ret = get_monitor_def(&reg, buf);
> +            if (ret < 0) {
> +                expr_error(mon, "unknown register");
> +            }
> +            n = reg;
> +        }
> +        break;
> +    case '\0':
> +        expr_error(mon, "unexpected end of expression");
> +        n = 0;
> +        break;
> +    default:
> +        errno = 0;
> +        n = strtoull(pch, &p, 0);

checkpatch.pl gripes:

    ERROR: consider using qemu_strtoull in preference to strtoull


Let's add a TODO comment.  

> +        if (errno == ERANGE) {
> +            expr_error(mon, "number too large");
> +        }
> +        if (pch == p) {
> +            expr_error(mon, "invalid char '%c' in expression", *p);
> +        }
> +        pch = p;
> +        while (qemu_isspace(*pch)) {
> +            pch++;
> +        }
> +        break;
> +    }
> +    return n;
> +}
[...]
> +static void monitor_find_completion(void *opaque,
> +                                    const char *cmdline)
> +{
> +    MonitorHMP *mon = 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 */

checkpatch.pl again:

    WARNING: Block comments use a leading /* on a separate line
    WARNING: Block comments use a trailing */ on a separate line

Can touch up in my tree.

> +    len = strlen(cmdline);
> +    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
> +        if (nb_args >= MAX_ARGS) {
> +            goto cleanup;
> +        }
> +        args[nb_args++] = 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);
> +}
[...]
> diff --git a/monitor/misc.c b/monitor/misc.c
> index 368b8297d4..c8289959c0 100644
> --- a/monitor/misc.c
> +++ b/monitor/misc.c
[...]
> @@ -612,245 +580,27 @@ out:
>      return output;
>  }
>  
> -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 = strlen(name);
>      p = list;
> -    for(;;) {
> +    for (;;) {
>          pstart = p;
>          p = qemu_strchrnul(p, '|');
> -        if ((p - pstart) == len && !memcmp(pstart, name, len))
> +        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
>              return 1;

The diff gets confusing here.  The function remains unchanged.  Good.

> -        if (*p == '\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 = buf;
> -    p = *pp;
> -    while (qemu_isspace(*p)) {
> -        p++;
> -    }
> -    if (*p == '\0') {
> -    fail:
> -        *q = '\0';
> -        *pp = p;
> -        return -1;
> -    }
> -    if (*p == '\"') {
> -        p++;
> -        while (*p != '\0' && *p != '\"') {
> -            if (*p == '\\') {
> -                p++;
> -                c = *p++;
> -                switch (c) {
> -                case 'n':
> -                    c = '\n';
> -                    break;
> -                case 'r':
> -                    c = '\r';
> -                    break;
> -                case '\\':
> -                case '\'':
> -                case '\"':
> -                    break;
> -                default:
> -                    printf("unsupported escape code: '\\%c'\n", c);
> -                    goto fail;
> -                }
> -                if ((q - buf) < buf_size - 1) {
> -                    *q++ = c;
> -                }
> -            } else {
> -                if ((q - buf) < buf_size - 1) {
> -                    *q++ = *p;
> -                }
> -                p++;
> -            }
> -        }
> -        if (*p != '\"') {
> -            printf("unterminated string\n");
> -            goto fail;
> -        }
> -        p++;
> -    } else {
> -        while (*p != '\0' && !qemu_isspace(*p)) {
> -            if ((q - buf) < buf_size - 1) {
> -                *q++ = *p;
> -            }
> -            p++;
> -        }
> -    }
> -    *q = '\0';
> -    *pp = p;
> -    return 0;
> -}
> -
> -#define MAX_ARGS 16
> -
> -static void free_cmdline_args(char **args, int nb_args)
> -{
> -    int i;
> -
> -    assert(nb_args <= MAX_ARGS);
> -
> -    for (i = 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. Number
> - *       of args have a limit of MAX_ARGS. If cmdline contains more, it will
> - *       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 = cmdline;
> -    nb_args = 0;
> -    for (;;) {
> -        while (qemu_isspace(*p)) {
> -            p++;
>          }
>          if (*p == '\0') {
>              break;
>          }
> -        if (nb_args >= MAX_ARGS) {
> -            goto fail;
> -        }
> -        ret = get_str(buf, sizeof(buf), &p);
> -        if (ret < 0) {
> -            goto fail;
> -        }
> -        args[nb_args] = g_strdup(buf);
> -        nb_args++;
> +        p++;
>      }
> -    *pnb_args = 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 = 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 >= nb_args) {
> -        for (cmd = cmds; cmd->name != NULL; cmd++) {
> -            help_cmd_dump_one(mon, cmd, args, arg_index);
> -        }
> -        return;
> -    }
> -
> -    /* Find one entry to dump */
> -    for (cmd = cmds; cmd->name != 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 = 0; i <= arg_index; i++) {
> -        monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
> -    }
> -}
> -
> -static void help_cmd(Monitor *mon, const char *name)
> -{
> -    char *args[MAX_ARGS];
> -    int nb_args = 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 = qemu_log_items; item->mask != 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);
>  }
[...]

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c Kevin Wolf
@ 2019-06-14  8:29   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:29 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
[...]
> 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 @@
[...]
> +QemuOptsList qemu_mon_opts = {
> +    .name = "mon",
> +    .implied_opt_name = "chardev",
> +    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
> +    .desc = {
> +        {
> +            .name = "mode",
> +            .type = QEMU_OPT_STRING,
> +        },{
> +            .name = "chardev",
> +            .type = QEMU_OPT_STRING,
> +        },{
> +            .name = "pretty",
> +            .type = QEMU_OPT_BOOL,
> +        },
> +        { /* end of list */ }

checkpatch.pl gripes:

    WARNING: Block comments use a leading /* on a separate line

I agree with ignoring this one, because it's the way it looks
everywhere.

> +    },
> +};
[...]

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions
  2019-06-14  6:37   ` Markus Armbruster
@ 2019-06-14  8:47     ` Kevin Wolf
  0 siblings, 0 replies; 40+ messages in thread
From: Kevin Wolf @ 2019-06-14  8:47 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 14.06.2019 um 08:37 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > 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 <kwolf@redhat.com>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > ---
> >  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"), to deal
> > + * in the Software without restriction, including without limitation the rights
> > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> > + * 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 OTHER
> > + * 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
> 
> Rename to MONITOR_INTERNAL_H, so it again matches the file name.  Can
> touch up in my tree.

Oops, yes, please do.

> > +
> > +#include "monitor/monitor.h"
> > +#include "qapi/qmp/qdict.h"
> 
> These too are superfluous.  I'm willing to tolerate monitor.h anyway,
> since anything including monitor-internal.h is almost certainly going to
> need monitor.h, too.

I tried to drop them because you suggested so, but it results in compile
errors. On closer look, I think qdict.h can go because the typedef will
be present through qemu/osdep.h, which must be included before this one,
but MonitorHMP is only defined by monitor/monitor.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"
> 
> Another superfluous one.

IOThread is only defined by system/iothread.h, so I don't think you can
remove this one either.

> Happy to drop these two #include in my tree.

As long as the result still builds, feel free to drop includes from the
header (and probably add them to source files instead where they will be
missing then).

Kevin


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools Kevin Wolf
@ 2019-06-14  8:48   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:48 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> ---
>  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;
>  
> @@ -116,6 +116,7 @@ struct Monitor {
>  
>  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 happen
> @@ -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;
>  }

The function was marginal before, and it's pointless now.  Let's kill it
in a follow-up patch.  No need to do it in this series.

>  
>  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);
>  
>  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 = g_malloc0(sizeof(*mon));
> -    bool use_readline = flags & MONITOR_USE_READLINE;
>  
> -    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);
>  
> -    if (use_readline) {
> +    mon->use_readline = flags & MONITOR_USE_READLINE;
> +    if (mon->use_readline) {
>          mon->rs = 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_line, bool has_cpu_index,
>      Monitor *old_mon;
>      MonitorHMP hmp = {};
>  
> -    monitor_data_init(&hmp.common, 0, true, false);
> +    monitor_data_init(&hmp.common, false, true, false);
>  
>      old_mon = cur_mon;
>      cur_mon = &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;
>  }

Another one to kill.

>  
>  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));
>  }
>  

Not sure about this one.  We'll see.

>  static void monitor_flush_locked(Monitor *mon);
> @@ -523,17 +527,17 @@ static void monitor_iothread_init(void)
>      mon_iothread = iothread_create("mon_iothread", &error_abort);
>  }
>  
> -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 = is_qmp;
>      mon->outbuf = qstring_new();
>      mon->skip_flush = skip_flush;
>      mon->use_io_thread = use_io_thread;
> -    mon->flags = flags;
>  }
>  
>  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 = QOBJECT(rsp);
>      QString *json;
>  
> -    json = mon->common.flags & MONITOR_USE_PRETTY ?
> -           qobject_to_json_pretty(data) : qobject_to_json(data);
> +    json = mon->pretty ? qobject_to_json_pretty(data) : qobject_to_json(data);
>      assert(json != NULL);
>  
>      qstring_append_chr(json, '\n');
> @@ -372,9 +371,11 @@ void monitor_init_qmp(Chardev *chr, int flags)
>      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,
> +    monitor_data_init(&mon->common, true, false,
>                        qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
>  
> +    mon->pretty = flags & MONITOR_USE_PRETTY;
> +
>      qemu_mutex_init(&mon->qmp_queue_lock);
>      mon->qmp_requests = g_queue_new();

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}()
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}() Kevin Wolf
@ 2019-06-14  8:50   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:50 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>

Neater now.  Thanks!

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
@ 2019-06-14  8:51   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:51 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
> ---
>  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);
>  
>  static void monitor_iothread_init(void);
>  
> -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) {
           monitor_iothread_init();
       }
       memset(mon, 0, sizeof(Monitor));

I'd like to replace this memset() by ...

       qemu_mutex_init(&mon->mon_lock);
       qemu_mutex_init(&mon->qmp.qmp_queue_lock);
       mon->outbuf = qstring_new();
       /* Use *mon_cmds by default. */
       mon->cmd_table = mon_cmds;
> @@ -719,6 +719,7 @@ static void monitor_data_init(Monitor *mon, bool skip_flush,
>      mon->skip_flush = skip_flush;
>      mon->use_io_thread = use_io_thread;
>      mon->qmp.qmp_requests = g_queue_new();
> +    mon->flags = flags;
>  }
>  
>  static void monitor_data_destroy(Monitor *mon)
> @@ -742,7 +743,7 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
>      char *output = NULL;
>      Monitor *old_mon, hmp;

... hmp = {} here (moved from PATCH 04), and ...

>  
> -    monitor_data_init(&hmp, true, false);
> +    monitor_data_init(&hmp, 0, true, false);
>  
>      old_mon = cur_mon;
>      cur_mon = &hmp;
> @@ -4605,19 +4606,51 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
>      monitor_list_append(mon);
>  }
>  
> -void monitor_init(Chardev *chr, int flags)
> +static void monitor_init_qmp(Chardev *chr, int flags)
>  {
>      Monitor *mon = g_malloc(sizeof(*mon));

... g_malloc0() here (moved from PATCH 03), and ...

> -    bool use_readline = flags & MONITOR_USE_READLINE;
> +
> +    /* 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, 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));
>  
>      qemu_chr_fe_init(&mon->chr, chr, &error_abort);
> -    mon->flags = flags;
> +    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=on.
> +         */
> +        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 = g_malloc(sizeof(*mon));

... and g_malloc0() here (moved from PATCH 04).

This way, the responsibility for zeroing moves just once, right when its
new owners get created.  Saves us explaining in PATCH 03+04 why we make
these changes.  They were confusing enough for me to ask for an
explanation in my review of v2.

Happy do to it in my tree.

I'd be tempted to assert(!(flags & MONITOR_USE_CONTROL)) here, and the
opposite in monitor_init_qmp(), if your PATCH 14 didn't get rid of
@flags.  Okay as it is.

> +    bool use_readline = 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 = readline_init(monitor_readline_printf,
>                                  monitor_readline_flush,
[...]


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
@ 2019-06-14  8:54   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:54 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, berrange, qemu-devel, qemu-block, armbru

Kevin Wolf <kwolf@redhat.com> writes:

> 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 <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  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 {
[...]
> @@ -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 = qstring_new();
>      /* Use *mon_cmds by default. */
>      mon->cmd_table = mon_cmds;
>      mon->skip_flush = skip_flush;
>      mon->use_io_thread = use_io_thread;
> -    mon->qmp.qmp_requests = g_queue_new();
>      mon->flags = flags;
>  }
>  
> +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 = container_of(mon, MonitorQMP, common);
> +        monitor_data_destroy_qmp(qmp_mon);

I dislike declarations hiding among statements, and variables used just
once.  If the variable was used more than once, or its use was in a
complicated expression, or a lengthy line, I'd ask for a blank line to
separate declaration from statement.  But here, I'd prefer

           monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));

Can touch up in my tree.

>      }
>      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);
>  }
>  
>  char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
> @@ -1087,8 +1096,12 @@ static void query_commands_cb(QmpCommand *cmd, void *opaque)
>  CommandInfoList *qmp_query_commands(Error **errp)
>  {
>      CommandInfoList *list = NULL;
> +    MonitorQMP *mon;
> +
> +    assert(monitor_is_qmp(cur_mon));

Could use monitor_cur_is_qmp().  If I mess with it in my tree anyway,
I'll consider changing to it.

> +    mon = container_of(cur_mon, MonitorQMP, common);
>  
> -    qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
> +    qmp_for_each_command(mon->commands, query_commands_cb, &list);
>  
>      return list;
>  }
> @@ -1155,16 +1168,16 @@ static void monitor_init_qmp_commands(void)
>                           qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
>  }
>  
> -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];
>  }
>  
> -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] = 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] = mon->common.use_io_thread;
>  }
>  
>  /*
> @@ -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 = NULL;
> @@ -1181,7 +1194,7 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
>      memset(capab, 0, sizeof(capab));
>  
>      for (; list; list = list->next) {
> -        if (!mon->qmp.capab_offered[list->value]) {
> +        if (!mon->capab_offered[list->value]) {
>              if (!unavailable) {
>                  unavailable = g_string_new(QMPCapability_str(list->value));
>              } else {
> @@ -1198,25 +1211,30 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
>          return false;
>      }
>  
> -    memcpy(mon->qmp.capab, capab, sizeof(capab));
> +    memcpy(mon->capab, capab, sizeof(capab));
>      return true;
>  }
>  
>  void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
>                            Error **errp)
>  {
> -    if (cur_mon->qmp.commands == &qmp_commands) {
> +    MonitorQMP *mon;
> +
> +    assert(monitor_is_qmp(cur_mon));

Likewise.

> +    mon = container_of(cur_mon, MonitorQMP, common);
> +
> +    if (mon->commands == &qmp_commands) {
>          error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
>                    "Capabilities negotiation is already complete, command "
>                    "ignored");
>          return;
>      }
>  
> -    if (!qmp_caps_accept(cur_mon, enable, errp)) {
> +    if (!qmp_caps_accept(mon, enable, errp)) {
>          return;
>      }
>  
> -    cur_mon->qmp.commands = &qmp_commands;
> +    mon->commands = &qmp_commands;
>  }
>  
>  /* Set the current CPU defined by the user. Callers must hold BQL. */
[...]

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state
  2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state Kevin Wolf
@ 2019-06-14  8:55   ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  8:55 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, berrange, qemu-devel, qemu-block, armbru

Kevin Wolf <kwolf@redhat.com> writes:

> The ReadLineState in Monitor is only used for HMP monitors. Create
> MonitorHMP and move it there.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  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"
>  
>  extern __thread Monitor *cur_mon;
> +typedef struct MonitorHMP MonitorHMP;
>  
>  /* 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);
>  
> -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);
>  
>  AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
> 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 char *password,
>  
>  void hmp_change(Monitor *mon, const QDict *qdict)
>  {
> +    /* FIXME Make MonitorHMP public and use container_of */

I think this FIXME should be resolved in PATCH 09.  Recommend to mention
in the commit message.  Can give it a try in my tree.

> +    MonitorHMP *hmp_mon = (MonitorHMP *) mon;

Drop the space before mon.  Can touch up in my tree.

>      const char *device = qdict_get_str(qdict, "device");
>      const char *target = qdict_get_str(qdict, "target");
>      const char *arg = qdict_get_try_str(qdict, "arg");
> @@ -1960,7 +1962,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
>          if (strcmp(target, "passwd") == 0 ||
>              strcmp(target, "password") == 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;
>  
> -    /*
> -     * 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;
>  };
>  
> +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 happen
> +     * 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);
>  }
>  
> -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);
>  }
>  
> -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 *readline_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);
>  }
>  
> -static void handle_hmp_command(Monitor *mon, const char *cmdline);
> +static void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
>  
>  static void monitor_iothread_init(void);
>  
> @@ -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 = 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 = container_of(mon, MonitorQMP, common);
>          monitor_data_destroy_qmp(qmp_mon);
> +    } else {
> +        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
> +        readline_free(hmp_mon->rs);

With the style tweak from the previous patch, this one should be tweaked
to match, so we get

       if (monitor_is_qmp(mon)) {
           monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));
       } else {
           readline_free(container_of(mon, MonitorHMP, common)->rs);
       }

Can touch up in my tree.

>      }
> -    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_line, bool has_cpu_index,
>                                  int64_t cpu_index, Error **errp)
>  {
>      char *output = NULL;
> -    Monitor *old_mon, hmp;
> +    Monitor *old_mon;
> +    MonitorHMP hmp = {};
>  
> -    monitor_data_init(&hmp, 0, true, false);
> +    monitor_data_init(&hmp.common, 0, true, false);
>  
>      old_mon = cur_mon;
> -    cur_mon = &hmp;
> +    cur_mon = &hmp.common;
>  
>      if (has_cpu_index) {
>          int ret = monitor_set_cpu(cpu_index);
> @@ -770,16 +777,16 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
>      handle_hmp_command(&hmp, command_line);
>      cur_mon = old_mon;
>  
> -    qemu_mutex_lock(&hmp.mon_lock);
> -    if (qstring_get_length(hmp.outbuf) > 0) {
> -        output = g_strdup(qstring_get_str(hmp.outbuf));
> +    qemu_mutex_lock(&hmp.common.mon_lock);
> +    if (qstring_get_length(hmp.common.outbuf) > 0) {
> +        output = g_strdup(qstring_get_str(hmp.common.outbuf));
>      } else {
>          output = g_strdup("");
>      }
> -    qemu_mutex_unlock(&hmp.mon_lock);
> +    qemu_mutex_unlock(&hmp.common.mon_lock);
>  
>  out:
> -    monitor_data_destroy(&hmp);
> +    monitor_data_destroy(&hmp.common);
>      return output;
>  }
>  
> @@ -1349,16 +1356,19 @@ static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
>  
>  static void hmp_info_history(Monitor *mon, const QDict *qdict)
>  {
> +    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
>      int i;
>      const char *str;
>  
> -    if (!mon->rs)
> +    if (!hmp_mon->rs) {
>          return;
> +    }
>      i = 0;
>      for(;;) {
> -        str = readline_get_history(mon->rs, i);
> -        if (!str)
> +        str = 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 = &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 = p;
>      /* search sub command */
>      if (cmd->sub_table != NULL && *p != '\0') {
> -        return monitor_parse_command(mon, cmdp_start, cmdp, cmd->sub_table);
> +        return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table);
>      }
>  
>      return cmd;
> @@ -3468,7 +3479,7 @@ fail:
>      return NULL;
>  }
>  
> -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)
>  
>      trace_handle_hmp_command(mon, cmdline);
>  
> -    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
> +    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_table);
>      if (!cmd) {
>          return;
>      }
>  
> -    qdict = monitor_parse_arguments(mon, &cmdline, cmd);
> +    qdict = 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 information\n",
>                         (int)(cmdline - cmd_start), cmd_start);
>          return;
>      }
>  
> -    cmd->cmd(mon, qdict);
> +    cmd->cmd(&mon->common, qdict);
>      qobject_unref(qdict);
>  }
>  
> -static void cmd_completion(Monitor *mon, const char *name, const char *list)
> +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)
>      }
>  }
>  
> -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)
>      }
>  }
>  
> -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 = opaque;
> +    MonitorHMP *mon = opaque;
>      char *args[MAX_ARGS];
>      int nb_args, len;
>  
> @@ -4123,7 +4134,7 @@ static void monitor_find_completion(void *opaque,
>      }
>  
>      /* 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);
>  
>  cleanup:
>      free_cmdline_args(args, nb_args);
> @@ -4334,19 +4345,21 @@ static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
>  
>  static void monitor_read(void *opaque, const uint8_t *buf, int size)
>  {
> +    MonitorHMP *mon;
>      Monitor *old_mon = cur_mon;
>      int i;
>  
>      cur_mon = opaque;
> +    mon = container_of(cur_mon, MonitorHMP, common);
>  
> -    if (cur_mon->rs) {
> +    if (mon->rs) {
>          for (i = 0; i < size; i++)
> -            readline_handle_byte(cur_mon->rs, buf[i]);
> +            readline_handle_byte(mon->rs, buf[i]);
>      } else {
>          if (size == 0 || buf[size - 1] != 0)
>              monitor_printf(cur_mon, "corrupted command\n");
>          else
> -            handle_hmp_command(cur_mon, (char *)buf);
> +            handle_hmp_command(mon, (char *)buf);
>      }
>  
>      cur_mon = 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 = opaque;
> +    MonitorHMP *mon = opaque;
>  
> -    monitor_suspend(mon);
> +    monitor_suspend(&mon->common);
>      handle_hmp_command(mon, cmdline);
> -    monitor_resume(mon);
> +    monitor_resume(&mon->common);
>  }
>  
>  int monitor_suspend(Monitor *mon)
> @@ -4405,8 +4418,9 @@ void monitor_resume(Monitor *mon)
>          }
>  
>          if (!monitor_is_qmp(mon)) {
> -            assert(mon->rs);
> -            readline_show_prompt(mon->rs);
> +            MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);

Blank line between declaration and statement, please.  Can touch up in
my tree.

> +            assert(hmp_mon->rs);
> +            readline_show_prompt(hmp_mon->rs);
>          }
>  
>          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 = opaque;
> +    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
>  
>      switch (event) {
>      case CHR_EVENT_MUX_IN:
> @@ -4475,7 +4490,7 @@ static void monitor_event(void *opaque, int event)
>          mon->mux_out = 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 = 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 = opaque;
>      va_list ap;
>      va_start(ap, fmt);
> -    monitor_vprintf(opaque, fmt, ap);
> +    monitor_vprintf(&mon->common, fmt, ap);
>      va_end(ap);
>  }
>  
>  static void monitor_readline_flush(void *opaque)
>  {
> -    monitor_flush(opaque);
> +    MonitorHMP *mon = opaque;
> +    monitor_flush(&mon->common);
>  }
>  
>  /*
> @@ -4673,11 +4690,11 @@ static void monitor_init_qmp(Chardev *chr, int flags)
>  
>  static void monitor_init_hmp(Chardev *chr, int flags)
>  {
> -    Monitor *mon = g_malloc(sizeof(*mon));
> +    MonitorHMP *mon = g_malloc0(sizeof(*mon));
>      bool use_readline = flags & MONITOR_USE_READLINE;
>  
> -    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);
>  
>      if (use_readline) {
>          mon->rs = readline_init(monitor_readline_printf,
> @@ -4687,9 +4704,9 @@ static void monitor_init_hmp(Chardev *chr, int flags)
>          monitor_read_command(mon, 0);
>      }
>  
> -    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_read,
> +                             monitor_event, NULL, &mon->common, NULL, true);
> +    monitor_list_append(&mon->common);
>  }
>  
>  void monitor_init(Chardev *chr, int flags)

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors
  2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors Kevin Wolf
@ 2019-06-14  9:01   ` Markus Armbruster
  2019-06-14  9:13     ` Kevin Wolf
  0 siblings, 1 reply; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  9:01 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> The -mon pretty=on|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 <kwolf@redhat.com>
> ---
>  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 *opts, Error **errp)
>          return -1;
>      }
>  
> +    if (!qmp && qemu_opt_get(opts, "pretty")) {
> +        warn_report("'pretty' is deprecated for HMP monitors, it has no effect "
> +                    "and will be removed in future versions");
> +    }
>      if (qemu_opt_get_bool(opts, "pretty", 0)) {
>          pretty = true;
>      }
> @@ -2362,7 +2366,11 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty)
>      opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, &error_fatal);
>      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 == false);
> +    }
>      monitor_device_index++;
>  }
>  
> 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 ease migration to
>  the new format, the ``-audiodev-help'' option can be used to convert
>  the current values of the environment variables to ``-audiodev'' options.
>  
> +@subsection -mon ...,control=readline,pretty=on|off (since 4.1)
> +
> +The @code{pretty=on|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)
>  
>  The @code{-realtime mlock=on|off} argument has been replaced by the

Good move.

Reviewed-by: Markus Armbruster <armbru@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (15 preceding siblings ...)
  2019-06-13 17:31 ` [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc no-reply
@ 2019-06-14  9:06 ` Markus Armbruster
  2019-06-14  9:32   ` Kevin Wolf
  16 siblings, 1 reply; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14  9:06 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> monitor.c mixes a lot of different things in a single file: The core
> monitor infrastructure, HMP infrastrcture, QMP infrastructure, and the
> implementation of several HMP and QMP commands. Almost worse, struct
> Monitor mixes state for HMP, for QMP, and state actually shared between
> all monitors. monitor.c must be linked with a system emulator and even
> requires per-target compilation because some of the commands it
> implements access system emulator state.
>
> The reason why I care about this is that I'm working on a protoype for a
> storage daemon, which wants to use QMP (but probably not HMP) and
> obviously doesn't have any system emulator state. So I'm interested in
> some core monitor parts that can be linked to non-system-emulator tools.
>
> This series first creates separate structs MonitorQMP and MonitorHMP
> which inherit from Monitor, and then moves the associated infrastructure
> code into separate source files.
>
> While the split is probably not perfect, I think it's an improvement of
> the current state even for QEMU proper, and it's good enough so I can
> link my storage daemon against just monitor/core.o and monitor/qmp.o and
> get a useless QMP monitor that parses the JSON input and rejects
> everything as an unknown command.
>
> Next I'll try to teach it a subset of QMP commands that can actually be
> supported in a tool, but while there will be a few follow-up patches to
> achieve this, I don't expect that this work will bring up much that
> needs to be changed in the splitting process done in this series.

I think I can address the remaining rather minor issues without a
respin.  Please let me know if you disagree with any of my remarks.

Thanks for helping out with the monitor code!  I know it's rather crusty
in places.

Dave, I'll take this through my tree, if you don't mind.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors
  2019-06-14  9:01   ` Markus Armbruster
@ 2019-06-14  9:13     ` Kevin Wolf
  2019-06-14 11:14       ` Markus Armbruster
  0 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-14  9:13 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 14.06.2019 um 11:01 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > The -mon pretty=on|off switch of the -mon option applies only the QMP

s/the QMP/to QMP/

Can you fix up this one as well while you're at it?

> > 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 <kwolf@redhat.com>

Kevin


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c
  2019-06-14  8:23   ` Markus Armbruster
@ 2019-06-14  9:17     ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 40+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-14  9:17 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, berrange, qemu-devel, qemu-block

* Markus Armbruster (armbru@redhat.com) wrote:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > 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 <kwolf@redhat.com>
> > ---
> [...]
> > 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 @@
> [...]
> > +static int64_t expr_unary(Monitor *mon)
> > +{
> > +    int64_t n;
> > +    char *p;
> > +    int ret;
> > +
> > +    switch (*pch) {
> > +    case '+':
> > +        next();
> > +        n = expr_unary(mon);
> > +        break;
> > +    case '-':
> > +        next();
> > +        n = -expr_unary(mon);
> > +        break;
> > +    case '~':
> > +        next();
> > +        n = ~expr_unary(mon);
> > +        break;
> > +    case '(':
> > +        next();
> > +        n = expr_sum(mon);
> > +        if (*pch != ')') {
> > +            expr_error(mon, "')' expected");
> > +        }
> > +        next();
> > +        break;
> > +    case '\'':
> > +        pch++;
> > +        if (*pch == '\0') {
> > +            expr_error(mon, "character constant expected");
> > +        }
> > +        n = *pch;
> > +        pch++;
> > +        if (*pch != '\'') {
> > +            expr_error(mon, "missing terminating \' character");
> > +        }
> > +        next();
> > +        break;
> > +    case '$':
> > +        {
> > +            char buf[128], *q;
> > +            int64_t reg = 0;
> > +
> > +            pch++;
> > +            q = buf;
> > +            while ((*pch >= 'a' && *pch <= 'z') ||
> > +                   (*pch >= 'A' && *pch <= 'Z') ||
> > +                   (*pch >= '0' && *pch <= '9') ||
> > +                   *pch == '_' || *pch == '.') {
> > +                if ((q - buf) < sizeof(buf) - 1) {
> > +                    *q++ = *pch;
> > +                }
> > +                pch++;
> > +            }
> > +            while (qemu_isspace(*pch)) {
> > +                pch++;
> > +            }
> > +            *q = 0;
> > +            ret = get_monitor_def(&reg, buf);
> > +            if (ret < 0) {
> > +                expr_error(mon, "unknown register");
> > +            }
> > +            n = reg;
> > +        }
> > +        break;
> > +    case '\0':
> > +        expr_error(mon, "unexpected end of expression");
> > +        n = 0;
> > +        break;
> > +    default:
> > +        errno = 0;
> > +        n = strtoull(pch, &p, 0);
> 
> checkpatch.pl gripes:
> 
>     ERROR: consider using qemu_strtoull in preference to strtoull
> 
> 
> Let's add a TODO comment.  
> 
> > +        if (errno == ERANGE) {
> > +            expr_error(mon, "number too large");
> > +        }
> > +        if (pch == p) {
> > +            expr_error(mon, "invalid char '%c' in expression", *p);
> > +        }
> > +        pch = p;
> > +        while (qemu_isspace(*pch)) {
> > +            pch++;
> > +        }
> > +        break;
> > +    }
> > +    return n;
> > +}
> [...]
> > +static void monitor_find_completion(void *opaque,
> > +                                    const char *cmdline)
> > +{
> > +    MonitorHMP *mon = 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 */
> 
> checkpatch.pl again:
> 
>     WARNING: Block comments use a leading /* on a separate line
>     WARNING: Block comments use a trailing */ on a separate line
> 
> Can touch up in my tree.

I wouldn't worry too much about fixing the existing problems here -
let's get the reorg done through kwolf's patches and then it's easier
to clean up later.

Dave

> > +    len = strlen(cmdline);
> > +    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
> > +        if (nb_args >= MAX_ARGS) {
> > +            goto cleanup;
> > +        }
> > +        args[nb_args++] = 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);
> > +}
> [...]
> > diff --git a/monitor/misc.c b/monitor/misc.c
> > index 368b8297d4..c8289959c0 100644
> > --- a/monitor/misc.c
> > +++ b/monitor/misc.c
> [...]
> > @@ -612,245 +580,27 @@ out:
> >      return output;
> >  }
> >  
> > -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 = strlen(name);
> >      p = list;
> > -    for(;;) {
> > +    for (;;) {
> >          pstart = p;
> >          p = qemu_strchrnul(p, '|');
> > -        if ((p - pstart) == len && !memcmp(pstart, name, len))
> > +        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
> >              return 1;
> 
> The diff gets confusing here.  The function remains unchanged.  Good.
> 
> > -        if (*p == '\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 = buf;
> > -    p = *pp;
> > -    while (qemu_isspace(*p)) {
> > -        p++;
> > -    }
> > -    if (*p == '\0') {
> > -    fail:
> > -        *q = '\0';
> > -        *pp = p;
> > -        return -1;
> > -    }
> > -    if (*p == '\"') {
> > -        p++;
> > -        while (*p != '\0' && *p != '\"') {
> > -            if (*p == '\\') {
> > -                p++;
> > -                c = *p++;
> > -                switch (c) {
> > -                case 'n':
> > -                    c = '\n';
> > -                    break;
> > -                case 'r':
> > -                    c = '\r';
> > -                    break;
> > -                case '\\':
> > -                case '\'':
> > -                case '\"':
> > -                    break;
> > -                default:
> > -                    printf("unsupported escape code: '\\%c'\n", c);
> > -                    goto fail;
> > -                }
> > -                if ((q - buf) < buf_size - 1) {
> > -                    *q++ = c;
> > -                }
> > -            } else {
> > -                if ((q - buf) < buf_size - 1) {
> > -                    *q++ = *p;
> > -                }
> > -                p++;
> > -            }
> > -        }
> > -        if (*p != '\"') {
> > -            printf("unterminated string\n");
> > -            goto fail;
> > -        }
> > -        p++;
> > -    } else {
> > -        while (*p != '\0' && !qemu_isspace(*p)) {
> > -            if ((q - buf) < buf_size - 1) {
> > -                *q++ = *p;
> > -            }
> > -            p++;
> > -        }
> > -    }
> > -    *q = '\0';
> > -    *pp = p;
> > -    return 0;
> > -}
> > -
> > -#define MAX_ARGS 16
> > -
> > -static void free_cmdline_args(char **args, int nb_args)
> > -{
> > -    int i;
> > -
> > -    assert(nb_args <= MAX_ARGS);
> > -
> > -    for (i = 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. Number
> > - *       of args have a limit of MAX_ARGS. If cmdline contains more, it will
> > - *       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 = cmdline;
> > -    nb_args = 0;
> > -    for (;;) {
> > -        while (qemu_isspace(*p)) {
> > -            p++;
> >          }
> >          if (*p == '\0') {
> >              break;
> >          }
> > -        if (nb_args >= MAX_ARGS) {
> > -            goto fail;
> > -        }
> > -        ret = get_str(buf, sizeof(buf), &p);
> > -        if (ret < 0) {
> > -            goto fail;
> > -        }
> > -        args[nb_args] = g_strdup(buf);
> > -        nb_args++;
> > +        p++;
> >      }
> > -    *pnb_args = 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 = 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 >= nb_args) {
> > -        for (cmd = cmds; cmd->name != NULL; cmd++) {
> > -            help_cmd_dump_one(mon, cmd, args, arg_index);
> > -        }
> > -        return;
> > -    }
> > -
> > -    /* Find one entry to dump */
> > -    for (cmd = cmds; cmd->name != 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 = 0; i <= arg_index; i++) {
> > -        monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
> > -    }
> > -}
> > -
> > -static void help_cmd(Monitor *mon, const char *name)
> > -{
> > -    char *args[MAX_ARGS];
> > -    int nb_args = 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 = qemu_log_items; item->mask != 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);
> >  }
> [...]
> 
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-14  9:06 ` Markus Armbruster
@ 2019-06-14  9:32   ` Kevin Wolf
  2019-06-15 20:31     ` Markus Armbruster
  0 siblings, 1 reply; 40+ messages in thread
From: Kevin Wolf @ 2019-06-14  9:32 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 14.06.2019 um 11:06 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > monitor.c mixes a lot of different things in a single file: The core
> > monitor infrastructure, HMP infrastrcture, QMP infrastructure, and the
> > implementation of several HMP and QMP commands. Almost worse, struct
> > Monitor mixes state for HMP, for QMP, and state actually shared between
> > all monitors. monitor.c must be linked with a system emulator and even
> > requires per-target compilation because some of the commands it
> > implements access system emulator state.
> >
> > The reason why I care about this is that I'm working on a protoype for a
> > storage daemon, which wants to use QMP (but probably not HMP) and
> > obviously doesn't have any system emulator state. So I'm interested in
> > some core monitor parts that can be linked to non-system-emulator tools.
> >
> > This series first creates separate structs MonitorQMP and MonitorHMP
> > which inherit from Monitor, and then moves the associated infrastructure
> > code into separate source files.
> >
> > While the split is probably not perfect, I think it's an improvement of
> > the current state even for QEMU proper, and it's good enough so I can
> > link my storage daemon against just monitor/core.o and monitor/qmp.o and
> > get a useless QMP monitor that parses the JSON input and rejects
> > everything as an unknown command.
> >
> > Next I'll try to teach it a subset of QMP commands that can actually be
> > supported in a tool, but while there will be a few follow-up patches to
> > achieve this, I don't expect that this work will bring up much that
> > needs to be changed in the splitting process done in this series.
> 
> I think I can address the remaining rather minor issues without a
> respin.  Please let me know if you disagree with any of my remarks.

Feel free to make the changes you suggested, possibly with the exception
of the #includes in monitor-internal.h where I think you're only
partially right (see my reply there).

Please also consider fixing the commit message typo I pointed out for
patch 15.

Kevin


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors
  2019-06-14  9:13     ` Kevin Wolf
@ 2019-06-14 11:14       ` Markus Armbruster
  0 siblings, 0 replies; 40+ messages in thread
From: Markus Armbruster @ 2019-06-14 11:14 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> Am 14.06.2019 um 11:01 hat Markus Armbruster geschrieben:
>> Kevin Wolf <kwolf@redhat.com> writes:
>> 
>> > The -mon pretty=on|off switch of the -mon option applies only the QMP
>
> s/the QMP/to QMP/
>
> Can you fix up this one as well while you're at it?

Sure!

>> > 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 <kwolf@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-14  9:32   ` Kevin Wolf
@ 2019-06-15 20:31     ` Markus Armbruster
  2019-06-17  8:53       ` Kevin Wolf
  0 siblings, 1 reply; 40+ messages in thread
From: Markus Armbruster @ 2019-06-15 20:31 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> Am 14.06.2019 um 11:06 hat Markus Armbruster geschrieben:
>> Kevin Wolf <kwolf@redhat.com> writes:
>> 
>> > monitor.c mixes a lot of different things in a single file: The core
>> > monitor infrastructure, HMP infrastrcture, QMP infrastructure, and the
>> > implementation of several HMP and QMP commands. Almost worse, struct
>> > Monitor mixes state for HMP, for QMP, and state actually shared between
>> > all monitors. monitor.c must be linked with a system emulator and even
>> > requires per-target compilation because some of the commands it
>> > implements access system emulator state.
>> >
>> > The reason why I care about this is that I'm working on a protoype for a
>> > storage daemon, which wants to use QMP (but probably not HMP) and
>> > obviously doesn't have any system emulator state. So I'm interested in
>> > some core monitor parts that can be linked to non-system-emulator tools.
>> >
>> > This series first creates separate structs MonitorQMP and MonitorHMP
>> > which inherit from Monitor, and then moves the associated infrastructure
>> > code into separate source files.
>> >
>> > While the split is probably not perfect, I think it's an improvement of
>> > the current state even for QEMU proper, and it's good enough so I can
>> > link my storage daemon against just monitor/core.o and monitor/qmp.o and
>> > get a useless QMP monitor that parses the JSON input and rejects
>> > everything as an unknown command.
>> >
>> > Next I'll try to teach it a subset of QMP commands that can actually be
>> > supported in a tool, but while there will be a few follow-up patches to
>> > achieve this, I don't expect that this work will bring up much that
>> > needs to be changed in the splitting process done in this series.
>> 
>> I think I can address the remaining rather minor issues without a
>> respin.  Please let me know if you disagree with any of my remarks.
>
> Feel free to make the changes you suggested, possibly with the exception
> of the #includes in monitor-internal.h where I think you're only
> partially right (see my reply there).
>
> Please also consider fixing the commit message typo I pointed out for
> patch 15.

Done.  Result in my public repository https://repo.or.cz/qemu/armbru.git
tag pull-monitor-2019-06-15, just in case you want to run your eyes over
it.  Incremental diff appended.

 monitor/hmp-cmds.c         |  5 ++---
 monitor/hmp.c              | 13 +++++++------
 monitor/misc.c             | 27 ++++++---------------------
 monitor/monitor-internal.h | 14 +++++---------
 monitor/monitor.c          | 10 +++-------
 monitor/qmp.c              |  5 +++--
 6 files changed, 26 insertions(+), 48 deletions(-)

diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 712737cd18..c283dde0e9 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -24,7 +24,7 @@
 #include "qemu/option.h"
 #include "qemu/timer.h"
 #include "qemu/sockets.h"
-#include "monitor/monitor.h"
+#include "monitor/monitor-internal.h"
 #include "monitor/qdev.h"
 #include "qapi/error.h"
 #include "qapi/opts-visitor.h"
@@ -1943,8 +1943,7 @@ static void hmp_change_read_arg(void *opaque, const char *password,
 
 void hmp_change(Monitor *mon, const QDict *qdict)
 {
-    /* FIXME Make MonitorHMP public and use container_of */
-    MonitorHMP *hmp_mon = (MonitorHMP *) mon;
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
     const char *device = qdict_get_str(qdict, "device");
     const char *target = qdict_get_str(qdict, "target");
     const char *arg = qdict_get_try_str(qdict, "arg");
diff --git a/monitor/hmp.c b/monitor/hmp.c
index 43185a7445..5349a81307 100644
--- a/monitor/hmp.c
+++ b/monitor/hmp.c
@@ -24,18 +24,17 @@
 
 #include "qemu/osdep.h"
 #include "monitor-internal.h"
-
 #include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qnum.h"
-
 #include "qemu/config-file.h"
 #include "qemu/ctype.h"
+#include "qemu/cutils.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,
@@ -1279,8 +1278,10 @@ static void monitor_find_completion(void *opaque,
         return;
     }
 
-    /* if the line ends with a space, it means we want to complete the
-     * next arg */
+    /*
+     * if the line ends with a space, it means we want to complete the
+     * next arg
+     */
     len = strlen(cmdline);
     if (len > 0 && qemu_isspace(cmdline[len - 1])) {
         if (nb_args >= MAX_ARGS) {
@@ -1395,7 +1396,7 @@ static void monitor_readline_flush(void *opaque)
 
 void monitor_init_hmp(Chardev *chr, bool use_readline)
 {
-    MonitorHMP *mon = g_malloc0(sizeof(*mon));
+    MonitorHMP *mon = g_new0(MonitorHMP, 1);
 
     monitor_data_init(&mon->common, false, false, false);
     qemu_chr_fe_init(&mon->common.chr, chr, &error_abort);
diff --git a/monitor/misc.c b/monitor/misc.c
index 49d8c445c4..10f24673f8 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -35,18 +35,12 @@
 #include "exec/gdbstub.h"
 #include "net/net.h"
 #include "net/slirp.h"
-#include "chardev/char-fe.h"
-#include "chardev/char-io.h"
 #include "chardev/char-mux.h"
 #include "ui/qemu-spice.h"
 #include "sysemu/numa.h"
-#include "monitor/monitor.h"
-#include "qemu/config-file.h"
 #include "qemu/ctype.h"
-#include "qemu/readline.h"
 #include "ui/console.h"
 #include "ui/input.h"
-#include "sysemu/block-backend.h"
 #include "audio/audio.h"
 #include "disas/disas.h"
 #include "sysemu/balloon.h"
@@ -58,11 +52,7 @@
 #include "sysemu/tpm.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qerror.h"
-#include "qapi/qmp/qnum.h"
 #include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/json-parser.h"
-#include "qapi/qmp/qlist.h"
 #include "qom/object_interfaces.h"
 #include "trace/control.h"
 #include "monitor/hmp-target.h"
@@ -71,7 +61,6 @@
 #endif
 #include "exec/memory.h"
 #include "exec/exec-all.h"
-#include "qemu/log.h"
 #include "qemu/option.h"
 #include "hmp.h"
 #include "qemu/thread.h"
@@ -81,9 +70,7 @@
 #include "qapi/error.h"
 #include "qapi/qmp-event.h"
 #include "qapi/qapi-introspect.h"
-#include "sysemu/qtest.h"
 #include "sysemu/cpus.h"
-#include "sysemu/iothread.h"
 #include "qemu/cutils.h"
 #include "tcg/tcg.h"
 
@@ -2336,14 +2323,12 @@ compare_mon_cmd(const void *a, const void *b)
 
 static void sortcmdlist(void)
 {
-    int array_num;
-    int elem_size = sizeof(HMPCommand);
-
-    array_num = sizeof(hmp_cmds)/elem_size-1;
-    qsort((void *)hmp_cmds, array_num, elem_size, compare_mon_cmd);
-
-    array_num = sizeof(hmp_info_cmds)/elem_size-1;
-    qsort((void *)hmp_info_cmds, array_num, elem_size, compare_mon_cmd);
+    qsort(hmp_cmds, ARRAY_SIZE(hmp_cmds) - 1,
+          sizeof(*hmp_cmds),
+          compare_mon_cmd);
+    qsort(hmp_info_cmds, ARRAY_SIZE(hmp_info_cmds) - 1,
+          sizeof(*hmp_info_cmds),
+          compare_mon_cmd);
 }
 
 void monitor_init_globals(void)
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 333ebf89e4..7760b22ba3 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -22,19 +22,15 @@
  * THE SOFTWARE.
  */
 
-#ifndef MONITOR_INT_H
-#define MONITOR_INT_H
+#ifndef MONITOR_INTERNAL_H
+#define MONITOR_INTERNAL_H
 
+#include "chardev/char-fe.h"
 #include "monitor/monitor.h"
-#include "qemu/cutils.h"
-
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/json-parser.h"
-#include "qapi/qmp/dispatch.h"
 #include "qapi/qapi-types-misc.h"
-
+#include "qapi/qmp/dispatch.h"
+#include "qapi/qmp/json-parser.h"
 #include "qemu/readline.h"
-#include "chardev/char-fe.h"
 #include "sysemu/iothread.h"
 
 /*
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 01d8fb5d30..3ef28171c0 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -24,15 +24,13 @@
 
 #include "qemu/osdep.h"
 #include "monitor-internal.h"
-
 #include "qapi/error.h"
 #include "qapi/qapi-emit-events.h"
+#include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qstring.h"
-
 #include "qemu/error-report.h"
 #include "qemu/option.h"
 #include "sysemu/qtest.h"
-
 #include "trace.h"
 
 /*
@@ -545,11 +543,9 @@ 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 = container_of(mon, MonitorQMP, common);
-        monitor_data_destroy_qmp(qmp_mon);
+        monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));
     } else {
-        MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
-        readline_free(hmp_mon->rs);
+        readline_free(container_of(mon, MonitorHMP, common)->rs);
     }
     qobject_unref(mon->outbuf);
     qemu_mutex_destroy(&mon->mon_lock);
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 7258f2b088..e1b196217d 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -28,9 +28,10 @@
 #include "monitor-internal.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-misc.h"
+#include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qstring.h"
 #include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qstring.h"
 #include "trace.h"
 
 struct QMPRequest {
@@ -365,7 +366,7 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
 
 void monitor_init_qmp(Chardev *chr, bool pretty)
 {
-    MonitorQMP *mon = g_malloc0(sizeof(*mon));
+    MonitorQMP *mon = g_new0(MonitorQMP, 1);
 
     /* Note: we run QMP monitor in I/O thread when @chr supports that */
     monitor_data_init(&mon->common, true, false,


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-15 20:31     ` Markus Armbruster
@ 2019-06-17  8:53       ` Kevin Wolf
  0 siblings, 0 replies; 40+ messages in thread
From: Kevin Wolf @ 2019-06-17  8:53 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 15.06.2019 um 22:31 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Am 14.06.2019 um 11:06 hat Markus Armbruster geschrieben:
> >> Kevin Wolf <kwolf@redhat.com> writes:
> >> 
> >> > monitor.c mixes a lot of different things in a single file: The core
> >> > monitor infrastructure, HMP infrastrcture, QMP infrastructure, and the
> >> > implementation of several HMP and QMP commands. Almost worse, struct
> >> > Monitor mixes state for HMP, for QMP, and state actually shared between
> >> > all monitors. monitor.c must be linked with a system emulator and even
> >> > requires per-target compilation because some of the commands it
> >> > implements access system emulator state.
> >> >
> >> > The reason why I care about this is that I'm working on a protoype for a
> >> > storage daemon, which wants to use QMP (but probably not HMP) and
> >> > obviously doesn't have any system emulator state. So I'm interested in
> >> > some core monitor parts that can be linked to non-system-emulator tools.
> >> >
> >> > This series first creates separate structs MonitorQMP and MonitorHMP
> >> > which inherit from Monitor, and then moves the associated infrastructure
> >> > code into separate source files.
> >> >
> >> > While the split is probably not perfect, I think it's an improvement of
> >> > the current state even for QEMU proper, and it's good enough so I can
> >> > link my storage daemon against just monitor/core.o and monitor/qmp.o and
> >> > get a useless QMP monitor that parses the JSON input and rejects
> >> > everything as an unknown command.
> >> >
> >> > Next I'll try to teach it a subset of QMP commands that can actually be
> >> > supported in a tool, but while there will be a few follow-up patches to
> >> > achieve this, I don't expect that this work will bring up much that
> >> > needs to be changed in the splitting process done in this series.
> >> 
> >> I think I can address the remaining rather minor issues without a
> >> respin.  Please let me know if you disagree with any of my remarks.
> >
> > Feel free to make the changes you suggested, possibly with the exception
> > of the #includes in monitor-internal.h where I think you're only
> > partially right (see my reply there).
> >
> > Please also consider fixing the commit message typo I pointed out for
> > patch 15.
> 
> Done.  Result in my public repository https://repo.or.cz/qemu/armbru.git
> tag pull-monitor-2019-06-15, just in case you want to run your eyes over
> it.  Incremental diff appended.

I didn't actually apply the patch or checkout your branch, but at least
from reading the diff it looks okay.

Kevin


^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2019-06-17  8:55 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-13 15:33 [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 01/15] monitor: Remove unused password prompting fields Kevin Wolf
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 02/15] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
2019-06-14  8:51   ` Markus Armbruster
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 03/15] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
2019-06-14  8:54   ` Markus Armbruster
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 04/15] monitor: Create MonitorHMP with readline state Kevin Wolf
2019-06-14  8:55   ` Markus Armbruster
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 05/15] monitor: Remove Monitor.cmd_table indirection Kevin Wolf
2019-06-14  5:51   ` Markus Armbruster
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 06/15] monitor: Rename HMP command type and tables Kevin Wolf
2019-06-14  5:52   ` Markus Armbruster
2019-06-14  6:01   ` Markus Armbruster
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 07/15] Move monitor.c to monitor/misc.c Kevin Wolf
2019-06-14  6:04   ` Markus Armbruster
2019-06-14  6:25     ` Markus Armbruster
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 08/15] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
2019-06-13 15:33 ` [Qemu-devel] [PATCH v3 09/15] monitor: Create monitor-internal.h with common definitions Kevin Wolf
2019-06-14  6:37   ` Markus Armbruster
2019-06-14  8:47     ` Kevin Wolf
2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 10/15] monitor: Split out monitor/qmp.c Kevin Wolf
2019-06-14  6:46   ` Markus Armbruster
2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 11/15] monitor: Split out monitor/hmp.c Kevin Wolf
2019-06-14  8:23   ` Markus Armbruster
2019-06-14  9:17     ` Dr. David Alan Gilbert
2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 12/15] monitor: Split out monitor/monitor.c Kevin Wolf
2019-06-14  8:29   ` Markus Armbruster
2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 13/15] monitor: Split Monitor.flags into separate bools Kevin Wolf
2019-06-14  8:48   ` Markus Armbruster
2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 14/15] monitor: Replace monitor_init() with monitor_init_{hmp, qmp}() Kevin Wolf
2019-06-14  8:50   ` Markus Armbruster
2019-06-13 15:34 ` [Qemu-devel] [PATCH v3 15/15] vl: Deprecate -mon pretty=... for HMP monitors Kevin Wolf
2019-06-14  9:01   ` Markus Armbruster
2019-06-14  9:13     ` Kevin Wolf
2019-06-14 11:14       ` Markus Armbruster
2019-06-13 17:31 ` [Qemu-devel] [PATCH v3 00/15] monitor: Split monitor.c in core/HMP/QMP/misc no-reply
2019-06-14  9:06 ` Markus Armbruster
2019-06-14  9:32   ` Kevin Wolf
2019-06-15 20:31     ` Markus Armbruster
2019-06-17  8:53       ` Kevin Wolf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.