All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc
@ 2019-06-11 13:40 Kevin Wolf
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields Kevin Wolf
                   ` (13 more replies)
  0 siblings, 14 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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.

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 (11):
  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: Move cmd_table to MonitorHMP
  Move monitor.c to monitor/misc.c
  monitor: Move {hmp,qmp}.c to monitor/{hmp,qmp}-cmds.c
  monitor: Create monitor_int.h with common definitions
  monitor: Split out monitor/qmp.c
  monitor: Split out monitor/hmp.c
  monitor: Split out monitor/monitor.c

 docs/devel/writing-qmp-commands.txt |   11 +-
 include/monitor/monitor.h           |    8 +-
 monitor/monitor_int.h               |  208 ++
 monitor.c                           | 4727 ---------------------------
 hmp.c => monitor/hmp-cmds.c         |    6 +-
 monitor/hmp.c                       | 1387 ++++++++
 monitor/misc.c                      | 2407 ++++++++++++++
 monitor/monitor.c                   |  605 ++++
 qmp.c => monitor/qmp-cmds.c         |    2 +-
 monitor/qmp.c                       |  404 +++
 MAINTAINERS                         |   13 +-
 Makefile.objs                       |    4 +-
 Makefile.target                     |    3 +-
 monitor/Makefile.objs               |    3 +
 monitor/trace-events                |   15 +
 trace-events                        |   10 -
 16 files changed, 5060 insertions(+), 4753 deletions(-)
 create mode 100644 monitor/monitor_int.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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12  6:43   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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>
---
 monitor.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/monitor.c b/monitor.c
index 6428eb3b7e..70ce9e8a77 100644
--- a/monitor.c
+++ b/monitor.c
@@ -220,8 +220,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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12  6:12   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 monitor.c | 86 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 49 insertions(+), 37 deletions(-)

diff --git a/monitor.c b/monitor.c
index 70ce9e8a77..bb23cc0450 100644
--- a/monitor.c
+++ b/monitor.c
@@ -702,7 +702,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) {
@@ -717,6 +717,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)
@@ -740,7 +741,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;
@@ -4603,19 +4604,48 @@ 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;
 
     /* 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,
@@ -4624,36 +4654,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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields Kevin Wolf
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12  7:59   ` Markus Armbruster
                     ` (2 more replies)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state Kevin Wolf
                   ` (10 subsequent siblings)
  13 siblings, 3 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 monitor.c | 214 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 118 insertions(+), 96 deletions(-)

diff --git a/monitor.c b/monitor.c
index bb23cc0450..d18cf18393 100644
--- a/monitor.c
+++ b/monitor.c
@@ -166,26 +166,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
@@ -218,7 +198,6 @@ struct Monitor {
      */
     ReadLineState *rs;
 
-    MonitorQMP qmp;
     gchar *mon_cpu_path;
     mon_cmd_t *cmd_table;
     QTAILQ_ENTRY(Monitor) entry;
@@ -239,6 +218,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;
 
@@ -247,7 +247,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)
@@ -355,18 +355,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);
 }
 
 
@@ -478,17 +478,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);
 }
@@ -511,12 +511,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);
         }
     }
 }
@@ -710,29 +715,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,
@@ -1085,8 +1094,9 @@ static void query_commands_cb(QmpCommand *cmd, void *opaque)
 CommandInfoList *qmp_query_commands(Error **errp)
 {
     CommandInfoList *list = NULL;
+    MonitorQMP *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;
 }
@@ -1153,16 +1163,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;
 }
 
 /*
@@ -1170,7 +1180,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;
@@ -1179,7 +1189,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 {
@@ -1196,25 +1206,27 @@ 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 = 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. */
@@ -4121,27 +4133,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"),
@@ -4166,24 +4178,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) {
@@ -4205,7 +4223,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;
@@ -4214,8 +4232,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;
@@ -4231,7 +4249,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);
 
@@ -4241,7 +4259,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;
@@ -4273,7 +4291,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
@@ -4282,8 +4300,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);
     }
 
     /*
@@ -4291,9 +4309,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);
@@ -4301,9 +4319,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)
@@ -4389,7 +4407,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;
@@ -4398,7 +4416,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));
         }
     }
@@ -4411,11 +4429,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);
@@ -4430,8 +4448,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();
@@ -4593,30 +4611,34 @@ 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));
 
     /* 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.
@@ -4631,10 +4653,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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (2 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12  9:07   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP Kevin Wolf
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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                 | 127 +++++++++++++++++++++-----------------
 3 files changed, 78 insertions(+), 58 deletions(-)

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 86656297f1..1ba354f811 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -7,6 +7,7 @@
 #include "qemu/readline.h"
 
 extern __thread Monitor *cur_mon;
+typedef struct MonitorHMP MonitorHMP;
 
 /* flags for monitor_init */
 /* 0x01 unused */
@@ -35,8 +36,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 d18cf18393..f8730e4462 100644
--- a/monitor.c
+++ b/monitor.c
@@ -190,14 +190,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;
@@ -218,6 +210,17 @@ 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.
+     * Else, it's the main thread.
+     * These members can be safely accessed without locks.
+     */
+    ReadLineState *rs;
+};
+
 typedef struct {
     Monitor common;
     JSONMessageParser parser;
@@ -324,7 +327,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;
@@ -334,7 +337,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) {
@@ -342,7 +345,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;
     }
 }
@@ -703,7 +707,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);
 
@@ -738,8 +742,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);
 }
@@ -748,12 +754,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);
@@ -768,16 +775,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;
 }
 
@@ -1341,16 +1348,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++;
     }
@@ -3048,11 +3058,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];
@@ -3083,7 +3094,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;
@@ -3460,7 +3471,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;
@@ -3468,26 +3479,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];
@@ -3511,7 +3522,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;
@@ -4000,7 +4011,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)
@@ -4095,7 +4106,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;
 
@@ -4115,7 +4126,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);
@@ -4326,19 +4337,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;
@@ -4347,11 +4360,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)
@@ -4397,8 +4410,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);
@@ -4460,6 +4474,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(cur_mon, MonitorHMP, common);
 
     switch (event) {
     case CHR_EVENT_MUX_IN:
@@ -4467,7 +4482,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 {
@@ -4494,8 +4509,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++;
@@ -4556,15 +4571,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);
 }
 
 /*
@@ -4662,11 +4679,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,
@@ -4676,9 +4693,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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (3 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12 11:45   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c Kevin Wolf
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

Monitor.cmd_table contains the handlers for HMP commands, so there is no
reason to keep it in the state shared with QMP. Move it to MonitorHMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 monitor.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/monitor.c b/monitor.c
index f8730e4462..56af8ed448 100644
--- a/monitor.c
+++ b/monitor.c
@@ -191,7 +191,6 @@ struct Monitor {
     bool use_io_thread;
 
     gchar *mon_cpu_path;
-    mon_cmd_t *cmd_table;
     QTAILQ_ENTRY(Monitor) entry;
 
     /*
@@ -219,6 +218,7 @@ struct MonitorHMP {
      * These members can be safely accessed without locks.
      */
     ReadLineState *rs;
+    mon_cmd_t *cmd_table;
 };
 
 typedef struct {
@@ -720,13 +720,19 @@ static void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
     memset(mon, 0, sizeof(Monitor));
     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;
 }
 
+static void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
+{
+    monitor_data_init(&mon->common, flags, skip_flush, false);
+
+    /* Use *mon_cmds by default. */
+    mon->cmd_table = mon_cmds;
+}
+
 static void monitor_data_destroy_qmp(MonitorQMP *mon)
 {
     json_message_parser_destroy(&mon->parser);
@@ -757,7 +763,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(&hmp, 0, true);
 
     old_mon = cur_mon;
     cur_mon = &hmp.common;
@@ -1002,6 +1008,7 @@ static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
 
 static void help_cmd(Monitor *mon, const char *name)
 {
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
     char *args[MAX_ARGS];
     int nb_args = 0;
 
@@ -1024,7 +1031,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, hmp_mon->cmd_table, args, nb_args, 0);
 
     free_cmdline_args(args, nb_args);
 }
@@ -3479,7 +3486,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->cmd_table);
     if (!cmd) {
         return;
     }
@@ -4126,7 +4133,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->cmd_table, args, nb_args);
 
 cleanup:
     free_cmdline_args(args, nb_args);
@@ -4682,7 +4689,7 @@ 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);
+    monitor_data_init_hmp(mon, flags, false);
     qemu_chr_fe_init(&mon->common.chr, chr, &error_abort);
 
     if (use_readline) {
-- 
2.20.1



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

* [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (4 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-11 15:38   ` Dr. David Alan Gilbert
  2019-06-12 11:57   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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>
---
 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 56af8ed448..ea3de5cac1 100644
--- a/monitor.c
+++ b/monitor/misc.c
@@ -62,7 +62,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 7be1225415..10c082314c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1924,7 +1924,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
@@ -2046,7 +2046,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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (5 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-11 16:09   ` Dr. David Alan Gilbert
  2019-06-12 12:01   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions Kevin Wolf
                   ` (6 subsequent siblings)
  13 siblings, 2 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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>
---
 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 fa1b3c1577..65520222ca 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 10c082314c..8789c82e5c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1925,7 +1925,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
@@ -2045,7 +2046,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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (6 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12 12:18   ` Markus Armbruster
  2019-06-12 12:43   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c Kevin Wolf
                   ` (5 subsequent siblings)
  13 siblings, 2 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert

Before we can split monitor.c, we need to create a header file that
contains the common definitions that will be used by multiple source
files.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 monitor/monitor_int.h | 148 ++++++++++++++++++++++++++++++++++++++++++
 monitor/misc.c        | 110 +------------------------------
 MAINTAINERS           |   2 +
 3 files changed, 151 insertions(+), 109 deletions(-)
 create mode 100644 monitor/monitor_int.h

diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
new file mode 100644
index 0000000000..7122418955
--- /dev/null
+++ b/monitor/monitor_int.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 "qemu-common.h"
+#include "monitor/monitor.h"
+
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/json-parser.h"
+#include "qapi/qapi-commands.h"
+
+#include "qemu/readline.h"
+#include "chardev/char-fe.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 mon_cmd_t {
+    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 mon_cmd_t *sub_table;
+    void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
+} mon_cmd_t;
+
+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.
+     * Else, it's the main thread.
+     * These members can be safely accessed without locks.
+     */
+    ReadLineState *rs;
+    mon_cmd_t *cmd_table;
+};
+
+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 ea3de5cac1..aa3342c1e5 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "monitor_int.h"
 #include "qemu/units.h"
 #include <dirent.h>
 #include "cpu.h"
@@ -91,55 +92,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 mon_cmd_t {
-    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 mon_cmd_t *sub_table;
-    void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
-} mon_cmd_t;
-
 /* file descriptors passed via SCM_RIGHTS */
 typedef struct mon_fd_t mon_fd_t;
 struct mon_fd_t {
@@ -182,66 +134,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.
-     * Else, it's the main thread.
-     * These members can be safely accessed without locks.
-     */
-    ReadLineState *rs;
-    mon_cmd_t *cmd_table;
-};
-
-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 8789c82e5c..0c98719f4e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1924,6 +1924,7 @@ F: qapi/run-state.json
 Human Monitor (HMP)
 M: Dr. David Alan Gilbert <dgilbert@redhat.com>
 S: Maintained
+F: monitor/monitor_int.h
 F: monitor/misc.c
 F: monitor/hmp*
 F: hmp.h
@@ -2046,6 +2047,7 @@ F: tests/check-qom-proplist.c
 QMP
 M: Markus Armbruster <armbru@redhat.com>
 S: Supported
+F: monitor/monitor_int.h
 F: monitor/qmp*
 F: monitor/misc.c
 F: docs/devel/*qmp-*
-- 
2.20.1



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

* [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (7 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12 13:11   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c Kevin Wolf
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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>
---
 include/monitor/monitor.h |   1 +
 monitor/monitor_int.h     |  30 ++-
 monitor/misc.c            | 394 +------------------------------------
 monitor/qmp.c             | 404 ++++++++++++++++++++++++++++++++++++++
 Makefile.objs             |   1 +
 monitor/Makefile.objs     |   1 +
 monitor/trace-events      |   4 +-
 7 files changed, 448 insertions(+), 387 deletions(-)
 create mode 100644 monitor/qmp.c

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 1ba354f811..7bbab05320 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -21,6 +21,7 @@ bool monitor_cur_is_qmp(void);
 
 void monitor_init_globals(void);
 void monitor_init(Chardev *chr, int flags);
+void monitor_init_qmp(Chardev *chr, int flags);
 void monitor_cleanup(void);
 
 int monitor_suspend(Monitor *mon);
diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
index 7122418955..4aabee54e1 100644
--- a/monitor/monitor_int.h
+++ b/monitor/monitor_int.h
@@ -30,10 +30,11 @@
 
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/json-parser.h"
-#include "qapi/qapi-commands.h"
+#include "qapi/qmp/dispatch.h"
 
 #include "qemu/readline.h"
 #include "chardev/char-fe.h"
+#include "sysemu/iothread.h"
 
 /*
  * Supported types:
@@ -145,4 +146,31 @@ 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;
+
+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 aa3342c1e5..7e6f09106c 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -140,51 +140,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 mon_cmd_t mon_cmds[];
 static mon_cmd_t 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
@@ -243,28 +221,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);
 
@@ -324,7 +280,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;
@@ -374,21 +330,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 },
@@ -603,8 +544,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();
@@ -625,14 +566,6 @@ static void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
     mon->cmd_table = mon_cmds;
 }
 
-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);
@@ -1069,18 +1002,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.
@@ -2253,7 +2174,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;
@@ -4031,209 +3952,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;
@@ -4320,56 +4045,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;
@@ -4505,7 +4180,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);
     /*
@@ -4525,57 +4200,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));
-
-    /* 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..d425b0f2ba
--- /dev/null
+++ b/monitor/qmp.c
@@ -0,0 +1,404 @@
+/*
+ * 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_int.h"
+
+#include "chardev/char-io.h"
+
+#include "qapi/error.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qapi-commands-misc.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));
+
+    /* 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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (8 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12 13:17   ` Markus Armbruster
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 11/11] monitor: Split out monitor/monitor.c Kevin Wolf
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 include/monitor/monitor.h |    1 +
 monitor/monitor_int.h     |   31 +
 monitor/hmp.c             | 1387 +++++++++++++++++++++++++++++++++++++
 monitor/misc.c            | 1338 +----------------------------------
 monitor/Makefile.objs     |    2 +-
 monitor/trace-events      |    4 +-
 6 files changed, 1429 insertions(+), 1334 deletions(-)
 create mode 100644 monitor/hmp.c

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 7bbab05320..8547529e49 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -22,6 +22,7 @@ bool monitor_cur_is_qmp(void);
 void monitor_init_globals(void);
 void monitor_init(Chardev *chr, int flags);
 void monitor_init_qmp(Chardev *chr, int flags);
+void monitor_init_hmp(Chardev *chr, int flags);
 void monitor_cleanup(void);
 
 int monitor_suspend(Monitor *mon);
diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
index 4aabee54e1..88eaed9c5c 100644
--- a/monitor/monitor_int.h
+++ b/monitor/monitor_int.h
@@ -27,6 +27,7 @@
 
 #include "qemu-common.h"
 #include "monitor/monitor.h"
+#include "qemu/cutils.h"
 
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/json-parser.h"
@@ -154,6 +155,29 @@ static inline bool monitor_is_qmp(const Monitor *mon)
     return (mon->flags & MONITOR_USE_CONTROL);
 }
 
+/**
+ * Is @name in the '|' separated list of names @list?
+ */
+static inline int compare_cmd(const char *name, const char *list)
+{
+    const char *p, *pstart;
+    int len;
+    len = strlen(name);
+    p = list;
+    for (;;) {
+        pstart = p;
+        p = qemu_strchrnul(p, '|');
+        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
+            return 1;
+        }
+        if (*p == '\0') {
+            break;
+        }
+        p++;
+    }
+    return 0;
+}
+
 typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
 extern IOThread *mon_iothread;
 extern QEMUBH *qmp_dispatcher_bh;
@@ -162,6 +186,8 @@ extern QemuMutex monitor_lock;
 extern MonitorList mon_list;
 extern int mon_refcount;
 
+extern mon_cmd_t mon_cmds[];
+
 int monitor_puts(Monitor *mon, const char *str);
 void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
                        bool use_io_thread);
@@ -173,4 +199,9 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp);
 void monitor_data_destroy_qmp(MonitorQMP *mon);
 void monitor_qmp_bh_dispatcher(void *data);
 
+void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush);
+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);
+
 #endif
diff --git a/monitor/hmp.c b/monitor/hmp.c
new file mode 100644
index 0000000000..bb5a59b8c8
--- /dev/null
+++ b/monitor/hmp.c
@@ -0,0 +1,1387 @@
+/*
+ * 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_int.h"
+
+#include "qapi/error.h"
+#include "qapi/qmp/qnum.h"
+
+#include "qemu/config-file.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 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 mon_cmd_t *cmd)
+{
+    if (!cmd->flags) {
+        return false;
+    }
+
+    return strchr(cmd->flags, 'p');
+}
+
+static void help_cmd_dump_one(Monitor *mon,
+                              const mon_cmd_t *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 mon_cmd_t *cmds,
+                          char **args, int nb_args, int arg_index)
+{
+    const mon_cmd_t *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" : " ");
+    }
+}
+
+void help_cmd(Monitor *mon, const char *name)
+{
+    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
+    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_mon->cmd_table, 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 mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
+                                              const char *cmdname)
+{
+    const mon_cmd_t *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 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];
+
+    /* 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 mon_cmd_t *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 mon_cmd_t *cmd;
+    const char *cmd_start = cmdline;
+
+    trace_handle_hmp_command(mon, cmdline);
+
+    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
+    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 mon_cmd_t *cmd_table,
+                                             char **args,
+                                             int nb_args)
+{
+    const char *cmdname;
+    int i;
+    const char *ptype, *old_ptype, *str, *name;
+    const mon_cmd_t *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, mon->cmd_table, 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_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
+{
+    monitor_data_init(&mon->common, flags, skip_flush, false);
+
+    /* Use *mon_cmds by default. */
+    mon->cmd_table = mon_cmds;
+}
+
+void monitor_init_hmp(Chardev *chr, int flags)
+{
+    MonitorHMP *mon = g_malloc0(sizeof(*mon));
+    bool use_readline = flags & MONITOR_USE_READLINE;
+
+    monitor_data_init_hmp(mon, flags, 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 7e6f09106c..4f1168b7c3 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -24,7 +24,6 @@
 
 #include "qemu/osdep.h"
 #include "monitor_int.h"
-#include "qemu/units.h"
 #include <dirent.h>
 #include "cpu.h"
 #include "hw/hw.h"
@@ -155,7 +154,6 @@ static QLIST_HEAD(, MonFdset) mon_fdsets;
 
 int mon_refcount;
 
-static mon_cmd_t mon_cmds[];
 static mon_cmd_t info_cmds[];
 
 __thread Monitor *cur_mon;
@@ -540,8 +538,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,
@@ -558,14 +554,6 @@ void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
     mon->flags = flags;
 }
 
-static void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
-{
-    monitor_data_init(&mon->common, flags, skip_flush, false);
-
-    /* Use *mon_cmds by default. */
-    mon->cmd_table = mon_cmds;
-}
-
 static void monitor_data_destroy(Monitor *mon)
 {
     g_free(mon->mon_cpu_path);
@@ -619,248 +607,6 @@ out:
     return output;
 }
 
-static int compare_cmd(const char *name, const char *list)
-{
-    const char *p, *pstart;
-    int len;
-    len = strlen(name);
-    p = list;
-    for(;;) {
-        pstart = p;
-        p = qemu_strchrnul(p, '|');
-        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++;
-    }
-    *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 mon_cmd_t *cmd)
-{
-    if (!cmd->flags) {
-        return false;
-    }
-
-    return strchr(cmd->flags, 'p');
-}
-
-static void help_cmd_dump_one(Monitor *mon,
-                              const mon_cmd_t *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 mon_cmd_t *cmds,
-                          char **args, int nb_args, int arg_index)
-{
-    const mon_cmd_t *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)
-{
-    MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
-    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_mon->cmd_table, args, nb_args, 0);
-
-    free_cmdline_args(args, nb_args);
-}
-
 static void do_help_cmd(Monitor *mon, const QDict *qdict)
 {
     help_cmd(mon, qdict_get_try_str(qdict, "name"));
@@ -2512,30 +2258,16 @@ static mon_cmd_t info_cmds[] = {
 };
 
 /* mon_cmds and info_cmds would be sorted at runtime */
-static mon_cmd_t mon_cmds[] = {
+mon_cmd_t mon_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();
@@ -2578,829 +2310,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 mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
-                                              const char *cmdname)
-{
-    const mon_cmd_t *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 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];
-
-    /* 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 mon_cmd_t *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 mon_cmd_t *cmd;
-    const char *cmd_start = cmdline;
-
-    trace_handle_hmp_command(mon, cmdline);
-
-    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
-    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)
 {
@@ -3831,127 +2740,6 @@ 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,
-                                             char **args,
-                                             int nb_args)
-{
-    const char *cmdname;
-    int i;
-    const char *ptype, *old_ptype, *str, *name;
-    const mon_cmd_t *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, mon->cmd_table, args, nb_args);
-
-cleanup:
-    free_cmdline_args(args, nb_args);
-}
-
 int monitor_can_read(void *opaque)
 {
     Monitor *mon = opaque;
@@ -3959,28 +2747,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)
 {
@@ -4045,58 +2811,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(cur_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)
 {
@@ -4139,25 +2853,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.
  */
@@ -4200,27 +2895,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_hmp(mon, flags, 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] 46+ messages in thread

* [Qemu-devel] [PATCH v2 11/11] monitor: Split out monitor/monitor.c
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (9 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c Kevin Wolf
@ 2019-06-11 13:40 ` Kevin Wolf
  2019-06-12 13:49   ` Markus Armbruster
  2019-06-11 14:18 ` [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc no-reply
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-11 13:40 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 and code that requires a system emulator or is
even target-dependent.

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>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 include/monitor/monitor.h |   1 +
 monitor/monitor_int.h     |   1 +
 monitor/misc.c            | 568 +----------------------------------
 monitor/monitor.c         | 605 ++++++++++++++++++++++++++++++++++++++
 MAINTAINERS               |   2 +
 monitor/Makefile.objs     |   2 +-
 monitor/trace-events      |   2 +-
 7 files changed, 612 insertions(+), 569 deletions(-)
 create mode 100644 monitor/monitor.c

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 8547529e49..b9f8d175ed 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -20,6 +20,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_init_qmp(Chardev *chr, int flags);
 void monitor_init_hmp(Chardev *chr, int flags);
diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
index 88eaed9c5c..d5fb5162f3 100644
--- a/monitor/monitor_int.h
+++ b/monitor/monitor_int.h
@@ -191,6 +191,7 @@ extern mon_cmd_t mon_cmds[];
 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 4f1168b7c3..a4ec850493 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -62,7 +62,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
@@ -117,43 +116,13 @@ 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 mon_cmd_t info_cmds[];
 
 __thread Monitor *cur_mon;
@@ -161,32 +130,6 @@ __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
- * 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?
  */
@@ -220,355 +163,6 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func,
 }
 
 
-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();
-    }
-    memset(mon, 0, sizeof(Monitor));
-    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)
 {
@@ -2740,13 +2334,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);
-}
-
 static void monitor_command_cb(void *opaque, const char *cmdline,
                                void *readline_opaque)
 {
@@ -2757,60 +2344,6 @@ static void monitor_command_cb(void *opaque, const char *cmdline,
     monitor_resume(&mon->common);
 }
 
-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)
 {
@@ -2830,27 +2363,12 @@ static void sortcmdlist(void)
     qsort((void *)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);
 }
 
 /*
@@ -2875,90 +2393,6 @@ int error_vprintf_unless_qmp(const char *fmt, va_list 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..ee111e657e
--- /dev/null
+++ b/monitor/monitor.c
@@ -0,0 +1,605 @@
+/*
+ * 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_int.h"
+
+#include "qapi/error.h"
+#include "qapi/qapi-emit-events.h"
+#include "qapi/qmp/qstring.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;
+
+/**
+ * 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;
+}
+
+
+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();
+    }
+    memset(mon, 0, sizeof(Monitor));
+    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 0c98719f4e..0fa418d27b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1926,6 +1926,7 @@ M: Dr. David Alan Gilbert <dgilbert@redhat.com>
 S: Maintained
 F: monitor/monitor_int.h
 F: monitor/misc.c
+F: monitor/monitor.c
 F: monitor/hmp*
 F: hmp.h
 F: hmp-commands*.hx
@@ -2050,6 +2051,7 @@ S: Supported
 F: monitor/monitor_int.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] 46+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (10 preceding siblings ...)
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 11/11] monitor: Split out monitor/monitor.c Kevin Wolf
@ 2019-06-11 14:18 ` no-reply
  2019-06-11 15:24 ` no-reply
  2019-06-12 14:22 ` Markus Armbruster
  13 siblings, 0 replies; 46+ messages in thread
From: no-reply @ 2019-06-11 14:18 UTC (permalink / raw)
  To: kwolf; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert, qemu-devel

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



Hi,

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

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

=== 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 ===

From https://github.com/patchew-project/qemu
 * [new tag]               patchew/20190611134043.9524-1-kwolf@redhat.com -> patchew/20190611134043.9524-1-kwolf@redhat.com
Switched to a new branch 'test'
4db331c519 monitor: Split out monitor/monitor.c
899a21f035 monitor: Split out monitor/hmp.c
50416d4aeb monitor: Split out monitor/qmp.c
31d1fe8e42 monitor: Create monitor_int.h with common definitions
2c1ac4ecbf monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
37f8c28eca Move monitor.c to monitor/misc.c
00674ed1c9 monitor: Move cmd_table to MonitorHMP
8a46bc8c85 monitor: Create MonitorHMP with readline state
af6e2aad95 monitor: Make MonitorQMP a child class of Monitor
c48181e5ab monitor: Split monitor_init in HMP and QMP function
82eb18147f monitor: Remove unused password prompting fields

=== OUTPUT BEGIN ===
1/11 Checking commit 82eb18147fdf (monitor: Remove unused password prompting fields)
2/11 Checking commit c48181e5ab24 (monitor: Split monitor_init in HMP and QMP function)
3/11 Checking commit af6e2aad957c (monitor: Make MonitorQMP a child class of Monitor)
4/11 Checking commit 8a46bc8c859e (monitor: Create MonitorHMP with readline state)
5/11 Checking commit 00674ed1c9c7 (monitor: Move cmd_table to MonitorHMP)
6/11 Checking commit 37f8c28eca6f (Move monitor.c to monitor/misc.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#78: 
new file mode 100644

total: 0 errors, 1 warnings, 78 lines checked

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

total: 0 errors, 1 warnings, 73 lines checked

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

total: 0 errors, 1 warnings, 290 lines checked

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

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

total: 1 errors, 1 warnings, 966 lines checked

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

10/11 Checking commit 899a21f0358e (monitor: Split out monitor/hmp.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#41: 
new file mode 100644

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

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

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

total: 1 errors, 3 warnings, 2878 lines checked

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

11/11 Checking commit 4db331c5192d (monitor: Split out monitor/monitor.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#706: 
new file mode 100644

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

total: 0 errors, 2 warnings, 1273 lines checked

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

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190611134043.9524-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] 46+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (11 preceding siblings ...)
  2019-06-11 14:18 ` [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc no-reply
@ 2019-06-11 15:24 ` no-reply
  2019-06-12 14:22 ` Markus Armbruster
  13 siblings, 0 replies; 46+ messages in thread
From: no-reply @ 2019-06-11 15:24 UTC (permalink / raw)
  To: kwolf; +Cc: kwolf, berrange, qemu-block, armbru, dgilbert, qemu-devel

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



Hi,

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

Message-id: 20190611134043.9524-1-kwolf@redhat.com
Subject: [Qemu-devel] [PATCH v2 00/11] 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 ===

From https://github.com/patchew-project/qemu
 - [tag update]      patchew/20190611134043.9524-1-kwolf@redhat.com -> patchew/20190611134043.9524-1-kwolf@redhat.com
Switched to a new branch 'test'
a38b11f monitor: Split out monitor/monitor.c
2e3d743 monitor: Split out monitor/hmp.c
ec837c0 monitor: Split out monitor/qmp.c
7768f93 monitor: Create monitor_int.h with common definitions
212dab6 monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
f91cabf Move monitor.c to monitor/misc.c
29cf561 monitor: Move cmd_table to MonitorHMP
bdc1972 monitor: Create MonitorHMP with readline state
b9b4f94 monitor: Make MonitorQMP a child class of Monitor
96e8406 monitor: Split monitor_init in HMP and QMP function
56ef4bc monitor: Remove unused password prompting fields

=== OUTPUT BEGIN ===
1/11 Checking commit 56ef4bc625de (monitor: Remove unused password prompting fields)
2/11 Checking commit 96e84064dbfb (monitor: Split monitor_init in HMP and QMP function)
3/11 Checking commit b9b4f94fff3f (monitor: Make MonitorQMP a child class of Monitor)
4/11 Checking commit bdc1972d7f1c (monitor: Create MonitorHMP with readline state)
5/11 Checking commit 29cf56123d68 (monitor: Move cmd_table to MonitorHMP)
6/11 Checking commit f91cabfa3ac2 (Move monitor.c to monitor/misc.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#78: 
new file mode 100644

total: 0 errors, 1 warnings, 78 lines checked

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

total: 0 errors, 1 warnings, 73 lines checked

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

total: 0 errors, 1 warnings, 290 lines checked

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

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

total: 1 errors, 1 warnings, 967 lines checked

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

10/11 Checking commit 2e3d7432ffd3 (monitor: Split out monitor/hmp.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#41: 
new file mode 100644

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

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

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

total: 1 errors, 3 warnings, 2878 lines checked

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

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

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

total: 0 errors, 2 warnings, 1273 lines checked

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

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190611134043.9524-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] 46+ messages in thread

* Re: [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c Kevin Wolf
@ 2019-06-11 15:38   ` Dr. David Alan Gilbert
  2019-06-12 11:57   ` Markus Armbruster
  1 sibling, 0 replies; 46+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-11 15:38 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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>

> ---
>  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 56af8ed448..ea3de5cac1 100644
> --- a/monitor.c
> +++ b/monitor/misc.c
> @@ -62,7 +62,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 7be1225415..10c082314c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1924,7 +1924,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
> @@ -2046,7 +2046,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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
@ 2019-06-11 16:09   ` Dr. David Alan Gilbert
  2019-06-12 12:01   ` Markus Armbruster
  1 sibling, 0 replies; 46+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-11 16:09 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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>

> ---
>  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 fa1b3c1577..65520222ca 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 10c082314c..8789c82e5c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1925,7 +1925,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
> @@ -2045,7 +2046,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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
@ 2019-06-12  6:12   ` Markus Armbruster
  2019-06-12  6:43     ` Markus Armbruster
  0 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  6:12 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.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  monitor.c | 86 +++++++++++++++++++++++++++++++------------------------
>  1 file changed, 49 insertions(+), 37 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index 70ce9e8a77..bb23cc0450 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -702,7 +702,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) {
> @@ -717,6 +717,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)
> @@ -740,7 +741,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;

Explicit initialization replaced implicit zero-initialization.  Okay.

> @@ -4603,19 +4604,48 @@ 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;
>  
>      /* 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,
> @@ -4624,36 +4654,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)

This part of the diff is hard to read.  I'm inserting a no-op patch just
for review: make two identical copies of monitor_init() called
monitor_init_qmp() and monitor_init_hmp(), have monitor_init() call them
depending on MONITOR_USE_CONTROL.  Rebasing this patch on top of that
yields a more readable git-diff -w (readable for me, YMMV):

| @@ -4606,28 +4607,15 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
|  static void monitor_init_qmp(Chardev *chr, int flags)
|  {
|      Monitor *mon = g_malloc(sizeof(*mon));
| -    bool use_readline = flags & MONITOR_USE_READLINE;

See below.

|  
|      /* 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));

Partially evaluated: flags & MONITOR_USE_CONTROL is true.  Good.

|  
|      qemu_chr_fe_init(&mon->chr, chr, &error_abort);
| -    mon->flags = flags;

Moved into monitor_data_init().  Good.

| -    if (use_readline) {
| -        mon->rs = readline_init(monitor_readline_printf,
| -                                monitor_readline_flush,
| -                                mon,
| -                                monitor_find_completion);
| -        monitor_read_command(mon, 0);
| -    }

Deleting readline support here is not a regression, because nothing ever
passes MONITOR_USE_READLINE along with MONITOR_USE_CONTROL.  We use only
three of the four cases:

* Neither flag: gdbstub.c (I have no idea why and how this uses the
  monitor code, and why it doesn't use readline)

* Just MONITOR_USE_READLINE:

  - vl.c on behalf of -mon mode=readline,... and its various sugared
    forms

  - chardev/char.c for implicit mux monitor (you don't want to know)

* Just MONITOR_USE_CONTROL:

  - vl.c on behalf of -mon mode=control,... and its various sugared
    forms

QMP with readline could perhaps be convenient for testing.  I use
socat's READLINE address type myself.

Speaking of odd flag combinations: MONITOR_USE_PRETTY is silently
ignored unless MONITOR_USE_CONTROL.

Deleting the unused (and untried) code to use QMP with readline is fine
with me, but please document MONITOR_USE_READLINE is silently ignored
with MONITOR_USE_CONTROL, or replace all the flags by an enumeration of
the actual cases: HMP without readline, HMP with readline, QMP, pretty
QMP.

| -
| -    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);
| +
| +    json_message_parser_init(&mon->qmp.parser, handle_qmp_command, mon, NULL);

Partially evaluated: monitor_is_qmp(mon) is true.  Good.

Keep the line break, please.

|      if (mon->use_io_thread) {
|          /*
|           * Make sure the old iowatch is gone.  It's possible when
| @@ -4642,33 +4630,22 @@ static void monitor_init_qmp(Chardev *chr, int flags)
|          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);
| -        }
| -    } else {

This else belongs to if (!monitor_is_qmp(mon)).  Good.

| -        qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
| -                                 monitor_event, NULL, mon, NULL, true);
| -    }
| -
|          monitor_list_append(mon);
|      }
| +}

You simplified

       if (mon->use_io_thread) {
           ...
           /* The bottom half will add @mon to @mon_list */
           return;
       } else {
           ...
       }

       monitor_list_append(mon);

to
           
       if (mon->use_io_thread) {
           ...
           /* The bottom half will add @mon to @mon_list */
       } else {
           ...
           monitor_list_append(mon);
       }

Good.

|  
|  static void monitor_init_hmp(Chardev *chr, int flags)
|  {
|      Monitor *mon = g_malloc(sizeof(*mon));
|      bool use_readline = 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, false);

Partially evaluated: flags & MONITOR_USE_CONTROL is false.  Good.

|      qemu_chr_fe_init(&mon->chr, chr, &error_abort);
| -    mon->flags = flags;
| +

Moved into monitor_data_init().  Good.

|      if (use_readline) {
|          mon->rs = readline_init(monitor_readline_printf,
|                                  monitor_readline_flush,
| @@ -4677,35 +4654,8 @@ static void monitor_init_hmp(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);
| -        }
| -    } else {
|      qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
|                               monitor_event, NULL, mon, NULL, true);
| -    }
| -

Partially evaluated: monitor_is_qmp(mon) is false.  Good.

|      monitor_list_append(mon);
|  }
|  

Duplicates qemu_chr_fe_init(&mon->chr, chr, &error_abort).  Quite
tolerable.

Much clearer overall.


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

* Re: [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function
  2019-06-12  6:12   ` Markus Armbruster
@ 2019-06-12  6:43     ` Markus Armbruster
  0 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  6:43 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Markus Armbruster <armbru@redhat.com> writes:

[...]
> Much clearer overall.

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


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

* Re: [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields Kevin Wolf
@ 2019-06-12  6:43   ` Markus Armbruster
  0 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  6:43 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> 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>
> ---
>  monitor.c | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index 6428eb3b7e..70ce9e8a77 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -220,8 +220,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;

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


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

* Re: [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
@ 2019-06-12  7:59   ` Markus Armbruster
  2019-06-12 11:28     ` Kevin Wolf
  2019-06-12  8:05   ` [Qemu-devel] [PATCH v2.1 02.5/11] monitor: Restrict use of Monitor member qmp to actual QMP monitors Markus Armbruster
  2019-06-12  8:05   ` [Qemu-devel] [PATCH v2.1 03/11] monitor: Make MonitorQMP a child class of Monitor Markus Armbruster
  2 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  7:59 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

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.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

This is a bit harder to review than necessary, because it mixes the
largely mechanical "replace QMP member by child class" with the
necessary prerequisite "clean up to access QMP stuff only when the
monitor is actually a QMP monitor".  I'm going to post a split.

Effectively preexisting: we go from Monitor * to MonitorQMP * without
checking in several places.  I'll throw in assertions.

Incremental diff over your patch:

diff --git a/monitor.c b/monitor.c
index d18cf18393..62a3c06aeb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -736,8 +736,7 @@ 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);
+        monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));
     }
     readline_free(mon->rs);
     qobject_unref(mon->outbuf);
@@ -1094,7 +1093,10 @@ static void query_commands_cb(QmpCommand *cmd, void *opaque)
 CommandInfoList *qmp_query_commands(Error **errp)
 {
     CommandInfoList *list = NULL;
-    MonitorQMP *mon = container_of(cur_mon, MonitorQMP, common);
+    MonitorQMP *mon;
+
+    assert(monitor_is_qmp(cur_mon));
+    mon = container_of(cur_mon, MonitorQMP, common);
 
     qmp_for_each_command(mon->commands, query_commands_cb, &list);
 
@@ -1213,7 +1215,10 @@ static bool qmp_caps_accept(MonitorQMP *mon, QMPCapabilityList *list,
 void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
                           Error **errp)
 {
-    MonitorQMP *mon = container_of(cur_mon, MonitorQMP, common);
+    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,


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

* [Qemu-devel] [PATCH v2.1 02.5/11] monitor: Restrict use of Monitor member qmp to actual QMP monitors
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
  2019-06-12  7:59   ` Markus Armbruster
@ 2019-06-12  8:05   ` Markus Armbruster
  2019-06-12  8:05   ` [Qemu-devel] [PATCH v2.1 03/11] monitor: Make MonitorQMP a child class of Monitor Markus Armbruster
  2 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  8:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, dgilbert, qemu-block

From: Kevin Wolf <kwolf@redhat.com>

We currently use Monitor member qmp even in HMP monitors.  Harmless,
but it's in the next commit's way.  Restrict its use to QMP monitors.

Several functions have a tacit "is a QMP monitor" precondition.  Add
explicit assertions there.  The next commit will replace most of them
by compile-time type checks.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 monitor.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/monitor.c b/monitor.c
index bb23cc0450..0e145959d7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -357,6 +357,8 @@ 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)
 {
+    assert(monitor_is_qmp(mon));
+
     while (!g_queue_is_empty(mon->qmp.qmp_requests)) {
         qmp_request_free(g_queue_pop_head(mon->qmp.qmp_requests));
     }
@@ -364,6 +366,8 @@ static void monitor_qmp_cleanup_req_queue_locked(Monitor *mon)
 
 static void monitor_qmp_cleanup_queues(Monitor *mon)
 {
+    assert(monitor_is_qmp(mon));
+
     qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
     monitor_qmp_cleanup_req_queue_locked(mon);
     qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
@@ -710,29 +714,32 @@ 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(Monitor *mon)
+{
+    json_message_parser_destroy(&mon->qmp.parser);
+    qemu_mutex_destroy(&mon->qmp.qmp_queue_lock);
+    monitor_qmp_cleanup_req_queue_locked(mon);
+    g_queue_free(mon->qmp.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);
+        monitor_data_destroy_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,
@@ -1086,6 +1093,7 @@ CommandInfoList *qmp_query_commands(Error **errp)
 {
     CommandInfoList *list = NULL;
 
+    assert(monitor_is_qmp(cur_mon));
     qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
 
     return list;
@@ -1155,11 +1163,13 @@ static void monitor_init_qmp_commands(void)
 
 static bool qmp_oob_enabled(Monitor *mon)
 {
+    assert(monitor_is_qmp(mon));
     return mon->qmp.capab[QMP_CAPABILITY_OOB];
 }
 
 static void monitor_qmp_caps_reset(Monitor *mon)
 {
+    assert(monitor_is_qmp(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;
@@ -1176,6 +1186,7 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
     GString *unavailable = NULL;
     bool capab[QMP_CAPABILITY__MAX];
 
+    assert(monitor_is_qmp(mon));
     memset(capab, 0, sizeof(capab));
 
     for (; list; list = list->next) {
@@ -1203,6 +1214,7 @@ static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
 void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
                           Error **errp)
 {
+    assert(monitor_is_qmp(cur_mon));
     if (cur_mon->qmp.commands == &qmp_commands) {
         error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
                   "Capabilities negotiation is already complete, command "
@@ -4134,6 +4146,7 @@ static void monitor_qmp_dispatch(Monitor *mon, QObject *req)
     QDict *rsp;
     QDict *error;
 
+    assert(monitor_is_qmp(mon));
     old_mon = cur_mon;
     cur_mon = mon;
 
@@ -4177,6 +4190,9 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
     qemu_mutex_lock(&monitor_lock);
 
     QTAILQ_FOREACH(mon, &mon_list, entry) {
+        if (!monitor_is_qmp(mon)) {
+            continue;
+        }
         qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
         req_obj = g_queue_pop_head(mon->qmp.qmp_requests);
         if (req_obj) {
@@ -4212,6 +4228,7 @@ static void monitor_qmp_bh_dispatcher(void *data)
     }
 
     mon = req_obj->mon;
+    assert(monitor_is_qmp(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;
@@ -4395,6 +4412,8 @@ static QDict *qmp_greeting(Monitor *mon)
     QObject *ver = NULL;
     QMPCapability cap;
 
+    assert(monitor_is_qmp(mon));
+
     qmp_marshal_query_version(NULL, &ver, NULL);
 
     for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) {
@@ -4612,6 +4631,9 @@ static void monitor_init_qmp(Chardev *chr, int flags)
     monitor_data_init(mon, flags, false,
                       qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT));
 
+    qemu_mutex_init(&mon->qmp.qmp_queue_lock);
+    mon->qmp.qmp_requests = g_queue_new();
+
     qemu_chr_fe_init(&mon->chr, chr, &error_abort);
     qemu_chr_fe_set_echo(&mon->chr, true);
 
-- 
2.21.0



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

* [Qemu-devel] [PATCH v2.1 03/11] monitor: Make MonitorQMP a child class of Monitor
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
  2019-06-12  7:59   ` Markus Armbruster
  2019-06-12  8:05   ` [Qemu-devel] [PATCH v2.1 02.5/11] monitor: Restrict use of Monitor member qmp to actual QMP monitors Markus Armbruster
@ 2019-06-12  8:05   ` Markus Armbruster
  2 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  8:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, berrange, dgilbert, qemu-block

From: Kevin Wolf <kwolf@redhat.com>

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.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 monitor.c | 221 ++++++++++++++++++++++++++++--------------------------
 1 file changed, 113 insertions(+), 108 deletions(-)

diff --git a/monitor.c b/monitor.c
index 0e145959d7..62a3c06aeb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -166,26 +166,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
@@ -218,7 +198,6 @@ struct Monitor {
      */
     ReadLineState *rs;
 
-    MonitorQMP qmp;
     gchar *mon_cpu_path;
     mon_cmd_t *cmd_table;
     QTAILQ_ENTRY(Monitor) entry;
@@ -239,6 +218,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;
 
@@ -247,7 +247,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)
@@ -355,22 +355,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)
 {
-    assert(monitor_is_qmp(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)
 {
-    assert(monitor_is_qmp(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);
 }
 
 
@@ -482,17 +478,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);
 }
@@ -515,12 +511,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);
         }
     }
 }
@@ -722,12 +723,12 @@ static void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
     mon->flags = flags;
 }
 
-static void monitor_data_destroy_qmp(Monitor *mon)
+static void monitor_data_destroy_qmp(MonitorQMP *mon)
 {
-    json_message_parser_destroy(&mon->qmp.parser);
-    qemu_mutex_destroy(&mon->qmp.qmp_queue_lock);
+    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.qmp_requests);
+    g_queue_free(mon->qmp_requests);
 }
 
 static void monitor_data_destroy(Monitor *mon)
@@ -735,7 +736,7 @@ 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)) {
-        monitor_data_destroy_qmp(mon);
+        monitor_data_destroy_qmp(container_of(mon, MonitorQMP, common));
     }
     readline_free(mon->rs);
     qobject_unref(mon->outbuf);
@@ -1092,9 +1093,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));
-    qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
+    mon = container_of(cur_mon, MonitorQMP, common);
+
+    qmp_for_each_command(mon->commands, query_commands_cb, &list);
 
     return list;
 }
@@ -1161,18 +1165,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)
 {
-    assert(monitor_is_qmp(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)
 {
-    assert(monitor_is_qmp(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;
 }
 
 /*
@@ -1180,17 +1182,16 @@ 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;
     bool capab[QMP_CAPABILITY__MAX];
 
-    assert(monitor_is_qmp(mon));
     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 {
@@ -1207,26 +1208,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)
 {
+    MonitorQMP *mon;
+
     assert(monitor_is_qmp(cur_mon));
-    if (cur_mon->qmp.commands == &qmp_commands) {
+    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. */
@@ -4133,28 +4138,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;
 
-    assert(monitor_is_qmp(mon));
     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"),
@@ -4179,13 +4183,14 @@ 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);
 
@@ -4193,13 +4198,15 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
         if (!monitor_is_qmp(mon)) {
             continue;
         }
-        qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
-        req_obj = g_queue_pop_head(mon->qmp.qmp_requests);
+
+        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) {
@@ -4221,18 +4228,17 @@ 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;
     }
 
     mon = req_obj->mon;
-    assert(monitor_is_qmp(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;
@@ -4248,7 +4254,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);
 
@@ -4258,7 +4264,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;
@@ -4290,7 +4296,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
@@ -4299,8 +4305,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);
     }
 
     /*
@@ -4308,9 +4314,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);
@@ -4318,9 +4324,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)
@@ -4406,18 +4412,16 @@ 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;
     QMPCapability cap;
 
-    assert(monitor_is_qmp(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));
         }
     }
@@ -4430,11 +4434,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);
@@ -4449,8 +4453,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();
@@ -4612,33 +4616,34 @@ 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));
 
     /* 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_mutex_init(&mon->qmp.qmp_queue_lock);
-    mon->qmp.qmp_requests = g_queue_new();
+    qemu_mutex_init(&mon->qmp_queue_lock);
+    mon->qmp_requests = g_queue_new();
 
-    qemu_chr_fe_init(&mon->chr, chr, &error_abort);
-    qemu_chr_fe_set_echo(&mon->chr, true);
+    qemu_chr_fe_init(&mon->common.chr, chr, &error_abort);
+    qemu_chr_fe_set_echo(&mon->common.chr, true);
 
-    json_message_parser_init(&mon->qmp.parser, handle_qmp_command, mon, NULL);
-    if (mon->use_io_thread) {
+    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.
@@ -4653,10 +4658,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.21.0



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

* Re: [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state Kevin Wolf
@ 2019-06-12  9:07   ` Markus Armbruster
  2019-06-12  9:54     ` Peter Xu
  2019-06-12 10:03     ` Kevin Wolf
  0 siblings, 2 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12  9:07 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Peter Xu, berrange, qemu-devel, qemu-block, dgilbert

Cc: Peter for a monitor I/O thread question.

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                 | 127 +++++++++++++++++++++-----------------
>  3 files changed, 78 insertions(+), 58 deletions(-)
>
> diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> index 86656297f1..1ba354f811 100644
> --- a/include/monitor/monitor.h
> +++ b/include/monitor/monitor.h
> @@ -7,6 +7,7 @@
>  #include "qemu/readline.h"
>  
>  extern __thread Monitor *cur_mon;
> +typedef struct MonitorHMP MonitorHMP;
>  
>  /* flags for monitor_init */
>  /* 0x01 unused */
> @@ -35,8 +36,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;

No space between (MonitorHMP *) and 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 d18cf18393..f8730e4462 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -190,14 +190,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;
> @@ -218,6 +210,17 @@ 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.
> +     * Else, it's the main thread.
> +     * These members can be safely accessed without locks.
> +     */
> +    ReadLineState *rs;
> +};
> +

Hmm.

The monitor I/O thread code makes an effort not to restrict I/O thread
use to QMP, even though we only use it there.  Whether the code would
actually work for HMP as well we don't know.

Readline was similar until your PATCH 02: the code made an effort not to
restrict it to HMP, even though we only use it there.  Whether the code
would actually work for QMP as well we don't know.

Should we stop pretending and hard-code "I/O thread only for QMP"?

If yes, the comment above gets simplified by the patch that hard-codes
"I/O thread only for QMP".

If no, we should perhaps point out that we currently don't use an I/O
thread with HMP.  The comment above seems like a good place for that.

Perhaps restricting readline to HMP should be a separate patch before
PATCH 02.

>  typedef struct {
>      Monitor common;
>      JSONMessageParser parser;
> @@ -324,7 +327,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;
> @@ -334,7 +337,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) {
> @@ -342,7 +345,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;
>      }
>  }

Aside: this is an instance of the

       if condition
           do work
       else
           error out

anti-pattern.  Better:

       if !condition
           error out
       do work

I'm not asking you to clean that up.

> @@ -703,7 +707,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);
>  
> @@ -738,8 +742,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);

If we used a separate patch to restrict readline to QMP, then making
this readline_free() conditional would be part of it.

>      qobject_unref(mon->outbuf);
>      qemu_mutex_destroy(&mon->mon_lock);
>  }
> @@ -748,12 +754,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 = {};

Any particular reason for adding the initializer?

>  
> -    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);
> @@ -768,16 +775,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;
>  }
>  
> @@ -1341,16 +1348,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);

Unchecked conversion.  Tolerable, I think, since HMP command handlers
generally don't get invoked manually, unlike QMP command handlers.

>      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++;
>      }
> @@ -3048,11 +3058,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];
> @@ -3083,7 +3094,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;
> @@ -3460,7 +3471,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;
> @@ -3468,26 +3479,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];
> @@ -3511,7 +3522,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;
> @@ -4000,7 +4011,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)
> @@ -4095,7 +4106,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;
>  
> @@ -4115,7 +4126,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);
> @@ -4326,19 +4337,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;
> @@ -4347,11 +4360,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)
> @@ -4397,8 +4410,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.

> +            assert(hmp_mon->rs);
> +            readline_show_prompt(hmp_mon->rs);
>          }
>  
>          aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon);
> @@ -4460,6 +4474,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(cur_mon, MonitorHMP, common);

Any particular reason for changing from @opaque to @cur_mon?

>  
>      switch (event) {
>      case CHR_EVENT_MUX_IN:
> @@ -4467,7 +4482,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 {
> @@ -4494,8 +4509,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++;
> @@ -4556,15 +4571,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);
>  }

Monitor would suffice.  I guess you switch to MonitorHMP just to signal
"HMP here".  Okay.

>  
>  static void monitor_readline_flush(void *opaque)
>  {
> -    monitor_flush(opaque);
> +    MonitorHMP *mon = opaque;
> +    monitor_flush(&mon->common);
>  }

Likewise.

>  
>  /*
> @@ -4662,11 +4679,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));

Any particular reason for changing to g_malloc0()?

You hid the same change for monitor_init_qmp() in PATCH 03, where I
missed it until now.

>      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,
> @@ -4676,9 +4693,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)


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

* Re: [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-12  9:07   ` Markus Armbruster
@ 2019-06-12  9:54     ` Peter Xu
  2019-06-12 10:03     ` Kevin Wolf
  1 sibling, 0 replies; 46+ messages in thread
From: Peter Xu @ 2019-06-12  9:54 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, berrange, qemu-devel, qemu-block, dgilbert

On Wed, Jun 12, 2019 at 11:07:01AM +0200, Markus Armbruster wrote:

[...]

> > +struct MonitorHMP {
> > +    Monitor common;
> > +    /*
> > +     * 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;
> > +};
> > +
> 
> Hmm.
> 
> The monitor I/O thread code makes an effort not to restrict I/O thread
> use to QMP, even though we only use it there.  Whether the code would
> actually work for HMP as well we don't know.
> 
> Readline was similar until your PATCH 02: the code made an effort not to
> restrict it to HMP, even though we only use it there.  Whether the code
> would actually work for QMP as well we don't know.
> 
> Should we stop pretending and hard-code "I/O thread only for QMP"?
> 
> If yes, the comment above gets simplified by the patch that hard-codes
> "I/O thread only for QMP".
> 
> If no, we should perhaps point out that we currently don't use an I/O
> thread with HMP.  The comment above seems like a good place for that.

Yes I agree on that if we're refactoring the comment then we can make
it more explicit here.  For my own preference, I would prefer the
latter one, even we can have a bigger comment above MonitorHMP
mentioning that it's only used in main thread so no lock is needed for
all the HMP only structs (until someone wants to hammer on HMP again).

Thanks,

-- 
Peter Xu


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

* Re: [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-12  9:07   ` Markus Armbruster
  2019-06-12  9:54     ` Peter Xu
@ 2019-06-12 10:03     ` Kevin Wolf
  2019-06-12 14:08       ` Markus Armbruster
  1 sibling, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-12 10:03 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Peter Xu, berrange, qemu-devel, qemu-block, dgilbert

Am 12.06.2019 um 11:07 hat Markus Armbruster geschrieben:
> Cc: Peter for a monitor I/O thread question.
> 
> 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>

> > @@ -218,6 +210,17 @@ 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.
> > +     * Else, it's the main thread.
> > +     * These members can be safely accessed without locks.
> > +     */
> > +    ReadLineState *rs;
> > +};
> > +
> 
> Hmm.
> 
> The monitor I/O thread code makes an effort not to restrict I/O thread
> use to QMP, even though we only use it there.  Whether the code would
> actually work for HMP as well we don't know.
> 
> Readline was similar until your PATCH 02: the code made an effort not to
> restrict it to HMP, even though we only use it there.  Whether the code
> would actually work for QMP as well we don't know.
> 
> Should we stop pretending and hard-code "I/O thread only for QMP"?
> 
> If yes, the comment above gets simplified by the patch that hard-codes
> "I/O thread only for QMP".
> 
> If no, we should perhaps point out that we currently don't use an I/O
> thread with HMP.  The comment above seems like a good place for that.
> 
> Perhaps restricting readline to HMP should be a separate patch before
> PATCH 02.

Yes, possibly iothreads could be restricted to QMP. It doesn't help me
in splitting the monitor in any way, though, so I don't see it within
the scope of this series.

Keeping readline around for QMP, on the other hand, would probably have
been harder than making the restriction.

As for splitting patch 2, I don't think that reorganising a patch that
already does its job and already received review is the most productive
thing we could do, but if you insist on a separate patch, I can do that.

> > @@ -748,12 +754,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 = {};
> 
> Any particular reason for adding the initializer?

Yes:

> >  
> > -    monitor_data_init(&hmp, 0, true, false);
> > +    monitor_data_init(&hmp.common, 0, true, false);

monitor_data_init() does a memset(), but only on hmp.common, so the
fields outside of hmp.common would remain uniniitialised. Specifically,
hmp.rs wouldn't be initialised to NULL and attempting to free it in the
end would crash.

> >      old_mon = cur_mon;
> > -    cur_mon = &hmp;
> > +    cur_mon = &hmp.common;
> >  
> >      if (has_cpu_index) {
> >          int ret = monitor_set_cpu(cpu_index);

> > @@ -1341,16 +1348,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);
> 
> Unchecked conversion.  Tolerable, I think, since HMP command handlers
> generally don't get invoked manually, unlike QMP command handlers.

I would like to see all HMP command handlers take MonitorHMP* instead of
Monitor*, but that would be a big ugly patch touching everything that
isn't really needed for the goal of this series, so I didn't include it.

If you consider it valuable to get rid of this container_of(), that's
probably the follow-up you could do.

> > @@ -4460,6 +4474,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(cur_mon, MonitorHMP, common);
> 
> Any particular reason for changing from @opaque to @cur_mon?

Probably a copy & paste error, thanks for catching it! I'll fix it.

> > @@ -4662,11 +4679,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));
> 
> Any particular reason for changing to g_malloc0()?
> 
> You hid the same change for monitor_init_qmp() in PATCH 03, where I
> missed it until now.

As above, initialising the fields outside mon->common.

Kevin


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

* Re: [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor
  2019-06-12  7:59   ` Markus Armbruster
@ 2019-06-12 11:28     ` Kevin Wolf
  2019-06-12 14:18       ` Markus Armbruster
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-12 11:28 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 12.06.2019 um 09:59 hat Markus Armbruster geschrieben:
> 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.
> >
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> 
> This is a bit harder to review than necessary, because it mixes the
> largely mechanical "replace QMP member by child class" with the
> necessary prerequisite "clean up to access QMP stuff only when the
> monitor is actually a QMP monitor".  I'm going to post a split.
> 
> Effectively preexisting: we go from Monitor * to MonitorQMP * without
> checking in several places.  I'll throw in assertions.

Since I don't think doing both in one patch makes review a lot harder
(and in fact think your patch 2.5 is harder to review for completeness
that the combined patch) and since both Dave and you already reviewed
the patch in its current form and I don't want to invalidate that
review, I'm going to keep it as a single patch and just squash in the
additional assertions where container_of() is used. The resulting code
is the same anyway.

Kevin


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

* Re: [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP Kevin Wolf
@ 2019-06-12 11:45   ` Markus Armbruster
  2019-06-12 13:55     ` Kevin Wolf
  0 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 11:45 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> Monitor.cmd_table contains the handlers for HMP commands, so there is no
> reason to keep it in the state shared with QMP. Move it to MonitorHMP.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  monitor.c | 23 +++++++++++++++--------
>  1 file changed, 15 insertions(+), 8 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index f8730e4462..56af8ed448 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -191,7 +191,6 @@ struct Monitor {
>      bool use_io_thread;
>  
>      gchar *mon_cpu_path;
> -    mon_cmd_t *cmd_table;
>      QTAILQ_ENTRY(Monitor) entry;
>  
>      /*
> @@ -219,6 +218,7 @@ struct MonitorHMP {
>       * These members can be safely accessed without locks.
>       */
>      ReadLineState *rs;
> +    mon_cmd_t *cmd_table;
>  };
>  
>  typedef struct {
> @@ -720,13 +720,19 @@ static void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
>      memset(mon, 0, sizeof(Monitor));
>      qemu_mutex_init(&mon->mon_lock);
>      mon->outbuf = qstring_new();
> -    /* Use *mon_cmds by default. */
> -    mon->cmd_table = mon_cmds;

As far as I can tell, this is the only assignment to Monitor member
cmd_table.  Why not delete it outright, and use mon_cmds directly?
Preferably renamed to something like hmp_cmds.

[...]


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

* Re: [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c Kevin Wolf
  2019-06-11 15:38   ` Dr. David Alan Gilbert
@ 2019-06-12 11:57   ` Markus Armbruster
  1 sibling, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 11:57 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.

I figure we'll want to move most of (all of?) monitor/misc.c out.  Not a
job this series must finish, of course.

> Signed-off-by: Kevin Wolf <kwolf@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:

Not this patch's fault, but this is wrong since commit da76ee76f78 (Sep
2015).

Funny, the one place that provides advice on writing HMP commands is
called writing-qmp-commands.txt %-}

>  
>      {
>          .name       = "alarmclock",

[...]

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


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

* Re: [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
  2019-06-11 16:09   ` Dr. David Alan Gilbert
@ 2019-06-12 12:01   ` Markus Armbruster
  1 sibling, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 12:01 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, berrange, qemu-devel, qemu-block, armbru

Kevin Wolf <kwolf@redhat.com> writes:

> 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>
> ---
>  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

Not this patch's fault: the "All" is wrong, and the entire sentence is
bad English.

> -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 fa1b3c1577..65520222ca 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 10c082314c..8789c82e5c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1925,7 +1925,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

Move hmp.h to include/monitor/ ?

>  F: hmp-commands*.hx
>  F: include/monitor/hmp-target.h
>  F: tests/test-hmp.c
> @@ -2045,7 +2046,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

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


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

* Re: [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions Kevin Wolf
@ 2019-06-12 12:18   ` Markus Armbruster
  2019-06-12 12:43   ` Markus Armbruster
  1 sibling, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 12:18 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, berrange, qemu-devel, qemu-block, armbru

Kevin Wolf <kwolf@redhat.com> writes:

> Before we can split monitor.c, we need to create a header file that
> contains the common definitions that will be used by multiple source
> files.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  monitor/monitor_int.h | 148 ++++++++++++++++++++++++++++++++++++++++++
>  monitor/misc.c        | 110 +------------------------------
>  MAINTAINERS           |   2 +
>  3 files changed, 151 insertions(+), 109 deletions(-)
>  create mode 100644 monitor/monitor_int.h
>
> diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> new file mode 100644
> index 0000000000..7122418955
> --- /dev/null
> +++ b/monitor/monitor_int.h

Please spell it with a '-', like the other files in this directory.

Suggest not to abbreviate "internal".  We use both spellings, but
-internal.h is clearer and more common.

> @@ -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 "qemu-common.h"

Use of qemu-common.h in headers is forbidden.  See its file comment, and
my "[PATCH 0/4] Cleanups around qemu-common.h".  Fortunately, its
inclusion is superfluous here.

> +#include "monitor/monitor.h"

Also superfluous.

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

Likewise.

> +#include "qapi/qmp/json-parser.h"
> +#include "qapi/qapi-commands.h"
> +
> +#include "qemu/readline.h"
> +#include "chardev/char-fe.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 mon_cmd_t {
> +    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 mon_cmd_t *sub_table;
> +    void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
> +} mon_cmd_t;
> +
> +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.
> +     * Else, it's the main thread.
> +     * These members can be safely accessed without locks.
> +     */
> +    ReadLineState *rs;
> +    mon_cmd_t *cmd_table;
> +};
> +
> +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

The new header mixes common stuff like struct Monitor with HMP-only and
QMP-only stuff.  Okay for now.

> diff --git a/monitor/misc.c b/monitor/misc.c
> index ea3de5cac1..aa3342c1e5 100644
> --- a/monitor/misc.c
> +++ b/monitor/misc.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "qemu/osdep.h"
> +#include "monitor_int.h"
>  #include "qemu/units.h"
>  #include <dirent.h>
>  #include "cpu.h"
> @@ -91,55 +92,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 mon_cmd_t {
> -    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 mon_cmd_t *sub_table;
> -    void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
> -} mon_cmd_t;
> -
>  /* file descriptors passed via SCM_RIGHTS */
>  typedef struct mon_fd_t mon_fd_t;
>  struct mon_fd_t {
> @@ -182,66 +134,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.
> -     * Else, it's the main thread.
> -     * These members can be safely accessed without locks.
> -     */
> -    ReadLineState *rs;
> -    mon_cmd_t *cmd_table;
> -};
> -
> -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 8789c82e5c..0c98719f4e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1924,6 +1924,7 @@ F: qapi/run-state.json
>  Human Monitor (HMP)
>  M: Dr. David Alan Gilbert <dgilbert@redhat.com>
>  S: Maintained
> +F: monitor/monitor_int.h
>  F: monitor/misc.c
>  F: monitor/hmp*
>  F: hmp.h
> @@ -2046,6 +2047,7 @@ F: tests/check-qom-proplist.c
>  QMP
>  M: Markus Armbruster <armbru@redhat.com>
>  S: Supported
> +F: monitor/monitor_int.h
>  F: monitor/qmp*
>  F: monitor/misc.c
>  F: docs/devel/*qmp-*


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

* Re: [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions Kevin Wolf
  2019-06-12 12:18   ` Markus Armbruster
@ 2019-06-12 12:43   ` Markus Armbruster
  1 sibling, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 12:43 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

One more nit...

Kevin Wolf <kwolf@redhat.com> writes:

> Before we can split monitor.c, we need to create a header file that

monitor/misc.c

> contains the common definitions that will be used by multiple source
> files.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>


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

* Re: [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c Kevin Wolf
@ 2019-06-12 13:11   ` Markus Armbruster
  2019-06-12 15:25     ` Kevin Wolf
  0 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 13:11 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block

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.

Less code compiled per target, yay!

> 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.

That's okay.

I have to admit I naively expected the previous patch moved everything
to the new header we need in a header for splitting up monitor/misc.c.
How did you decide what to move to the header in which patch?

> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  include/monitor/monitor.h |   1 +
>  monitor/monitor_int.h     |  30 ++-
>  monitor/misc.c            | 394 +------------------------------------
>  monitor/qmp.c             | 404 ++++++++++++++++++++++++++++++++++++++
>  Makefile.objs             |   1 +
>  monitor/Makefile.objs     |   1 +
>  monitor/trace-events      |   4 +-
>  7 files changed, 448 insertions(+), 387 deletions(-)
>  create mode 100644 monitor/qmp.c
>
> diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> index 1ba354f811..7bbab05320 100644
> --- a/include/monitor/monitor.h
> +++ b/include/monitor/monitor.h
> @@ -21,6 +21,7 @@ bool monitor_cur_is_qmp(void);
>  
>  void monitor_init_globals(void);
>  void monitor_init(Chardev *chr, int flags);
> +void monitor_init_qmp(Chardev *chr, int flags);

Why does this one go to the non-internal header?

>  void monitor_cleanup(void);
>  
>  int monitor_suspend(Monitor *mon);
> diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> index 7122418955..4aabee54e1 100644
> --- a/monitor/monitor_int.h
> +++ b/monitor/monitor_int.h
> @@ -30,10 +30,11 @@
>  
>  #include "qapi/qmp/qdict.h"
>  #include "qapi/qmp/json-parser.h"
> -#include "qapi/qapi-commands.h"
> +#include "qapi/qmp/dispatch.h"

This part should be squashed into the previous patch.  You'll
additionally need qapi/qapi-types-misc.h for QMP_CAPABILITY__MAX there,
or keep monitor/monitor.h, even though you need it only here for
MONITOR_USE_CONTROL.

>  
>  #include "qemu/readline.h"
>  #include "chardev/char-fe.h"
> +#include "sysemu/iothread.h"

Perhaps IOThread should be typedef'ed in qemu/typedefs.h.  I'm not
asking you to do that.

>  
>  /*
>   * Supported types:
> @@ -145,4 +146,31 @@ 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;
> +
> +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

I trust you these are indeed all needed.

> diff --git a/monitor/misc.c b/monitor/misc.c
> index aa3342c1e5..7e6f09106c 100644
> --- a/monitor/misc.c
> +++ b/monitor/misc.c
> @@ -140,51 +140,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 mon_cmd_t mon_cmds[];
>  static mon_cmd_t 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
> @@ -243,28 +221,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);
>  
> @@ -324,7 +280,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;
> @@ -374,21 +330,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 },
> @@ -603,8 +544,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();
> @@ -625,14 +566,6 @@ static void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush)
>      mon->cmd_table = mon_cmds;
>  }
>  
> -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);
> @@ -1069,18 +1002,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.
> @@ -2253,7 +2174,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;
> @@ -4031,209 +3952,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;
> @@ -4320,56 +4045,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;
> @@ -4505,7 +4180,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);
>      /*
> @@ -4525,57 +4200,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));
> -
> -    /* 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..d425b0f2ba
> --- /dev/null
> +++ b/monitor/qmp.c
> @@ -0,0 +1,404 @@
> +/*
> + * QEMU monitor
> + *
> + * Copyright (c) 2003-2004 Fabrice Bellard

I'm pretty confident nothing in this file is actually due to Fabrice.

> + *
> + * 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.
> + */

We inherit the non-standard license regardless.  Lesson learned: do not
add substantial code to source files with a non-standard license.

> +
> +#include "qemu/osdep.h"
> +#include "monitor_int.h"
> +
> +#include "chardev/char-io.h"
> +
> +#include "qapi/error.h"
> +#include "qapi/qmp/qjson.h"
> +#include "qapi/qmp/qstring.h"
> +#include "qapi/qmp/qlist.h"
> +#include "qapi/qapi-commands-misc.h"
> +
> +#include "trace.h"

Please sort the includes alphabetically (except qemu/osdep.h, of
course).

> +
> +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;

Please fuse these two.

> +
> +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.

> +
> +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));
> +
> +    /* 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);
> +    }
> +}

I trust you this is pure code motion.

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


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

* Re: [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c Kevin Wolf
@ 2019-06-12 13:17   ` Markus Armbruster
  2019-06-12 15:31     ` Kevin Wolf
  0 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 13:17 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, berrange, qemu-devel, qemu-block, armbru

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>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  include/monitor/monitor.h |    1 +
>  monitor/monitor_int.h     |   31 +
>  monitor/hmp.c             | 1387 +++++++++++++++++++++++++++++++++++++
>  monitor/misc.c            | 1338 +----------------------------------
>  monitor/Makefile.objs     |    2 +-
>  monitor/trace-events      |    4 +-
>  6 files changed, 1429 insertions(+), 1334 deletions(-)
>  create mode 100644 monitor/hmp.c
>
> diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> index 7bbab05320..8547529e49 100644
> --- a/include/monitor/monitor.h
> +++ b/include/monitor/monitor.h
> @@ -22,6 +22,7 @@ bool monitor_cur_is_qmp(void);
>  void monitor_init_globals(void);
>  void monitor_init(Chardev *chr, int flags);
>  void monitor_init_qmp(Chardev *chr, int flags);
> +void monitor_init_hmp(Chardev *chr, int flags);
>  void monitor_cleanup(void);
>  
>  int monitor_suspend(Monitor *mon);
> diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> index 4aabee54e1..88eaed9c5c 100644
> --- a/monitor/monitor_int.h
> +++ b/monitor/monitor_int.h
> @@ -27,6 +27,7 @@
>  
>  #include "qemu-common.h"
>  #include "monitor/monitor.h"
> +#include "qemu/cutils.h"
>  
>  #include "qapi/qmp/qdict.h"
>  #include "qapi/qmp/json-parser.h"
> @@ -154,6 +155,29 @@ static inline bool monitor_is_qmp(const Monitor *mon)
>      return (mon->flags & MONITOR_USE_CONTROL);
>  }
>  
> +/**
> + * Is @name in the '|' separated list of names @list?
> + */
> +static inline int compare_cmd(const char *name, const char *list)
> +{
> +    const char *p, *pstart;
> +    int len;
> +    len = strlen(name);
> +    p = list;
> +    for (;;) {
> +        pstart = p;
> +        p = qemu_strchrnul(p, '|');
> +        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
> +            return 1;
> +        }
> +        if (*p == '\0') {
> +            break;
> +        }
> +        p++;
> +    }
> +    return 0;
> +}
> +

What's the justification for inline?

>  typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
>  extern IOThread *mon_iothread;
>  extern QEMUBH *qmp_dispatcher_bh;
> @@ -162,6 +186,8 @@ extern QemuMutex monitor_lock;
>  extern MonitorList mon_list;
>  extern int mon_refcount;
>  
> +extern mon_cmd_t mon_cmds[];
> +

Any particular reason for not moving this one to hmp.c, along with
info_cmds?  Question, not demand :)

>  int monitor_puts(Monitor *mon, const char *str);
>  void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
>                         bool use_io_thread);
> @@ -173,4 +199,9 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp);
>  void monitor_data_destroy_qmp(MonitorQMP *mon);
>  void monitor_qmp_bh_dispatcher(void *data);
>  
> +void monitor_data_init_hmp(MonitorHMP *mon, int flags, bool skip_flush);
> +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);
> +
>  #endif
[...]


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

* Re: [Qemu-devel] [PATCH v2 11/11] monitor: Split out monitor/monitor.c
  2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 11/11] monitor: Split out monitor/monitor.c Kevin Wolf
@ 2019-06-12 13:49   ` Markus Armbruster
  2019-06-12 15:51     ` Kevin Wolf
  0 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 13:49 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 and code that requires a system emulator or is
> even target-dependent.

I think target-independent command handlers should move to qmp-cmds.c
and hmp-cmds.c.  Okay to leave for later.  Mentioning it the commit
message wouldn't hurt, though.

Also left in misc.c, and bulky enough for mention: completion callbacks.
They should perhaps move next to their command handlers.  Okay to leave
for later.

> 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>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> ---
>  include/monitor/monitor.h |   1 +
>  monitor/monitor_int.h     |   1 +
>  monitor/misc.c            | 568 +----------------------------------
>  monitor/monitor.c         | 605 ++++++++++++++++++++++++++++++++++++++
>  MAINTAINERS               |   2 +
>  monitor/Makefile.objs     |   2 +-
>  monitor/trace-events      |   2 +-
>  7 files changed, 612 insertions(+), 569 deletions(-)
>  create mode 100644 monitor/monitor.c
>
> diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> index 8547529e49..b9f8d175ed 100644
> --- a/include/monitor/monitor.h
> +++ b/include/monitor/monitor.h
> @@ -20,6 +20,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_init_qmp(Chardev *chr, int flags);
>  void monitor_init_hmp(Chardev *chr, int flags);
> diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> index 88eaed9c5c..d5fb5162f3 100644
> --- a/monitor/monitor_int.h
> +++ b/monitor/monitor_int.h
> @@ -191,6 +191,7 @@ extern mon_cmd_t mon_cmds[];
>  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 4f1168b7c3..a4ec850493 100644
> --- a/monitor/misc.c
> +++ b/monitor/misc.c
> @@ -62,7 +62,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
> @@ -117,43 +116,13 @@ 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 mon_cmd_t info_cmds[];
>  
>  __thread Monitor *cur_mon;
> @@ -161,32 +130,6 @@ __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
> - * 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);
   }

I can see why monitor_cur_is_qmp() stays here.  But why do the next two
stay?

   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;
       }
   }
> @@ -220,355 +163,6 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func,
>  }
>  
>  
> -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();
> -    }
> -    memset(mon, 0, sizeof(Monitor));
> -    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)
>  {
[...]

   static void monitor_init_qmp_commands(void)
   {
       /*
        * Two command lists:
        * - qmp_commands contains all QMP commands
        * - qmp_cap_negotiation_commands contains just
        *   "qmp_capabilities", to enforce capability negotiation
        */

       qmp_init_marshal(&qmp_commands);

       qmp_register_command(&qmp_commands, "query-qmp-schema",
                            qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
       qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
                            QCO_NO_OPTIONS);
       qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
                            QCO_NO_OPTIONS);

       QTAILQ_INIT(&qmp_cap_negotiation_commands);
       qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
                            qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
   }

Should have been moved to qmp.c in PATCH 09.

[...]

   static void monitor_printc(Monitor *mon, int c)
   {
       monitor_printf(mon, "'");
       switch(c) {
       case '\'':
           monitor_printf(mon, "\\'");
           break;
       case '\\':
           monitor_printf(mon, "\\\\");
           break;
       case '\n':
           monitor_printf(mon, "\\n");
           break;
       case '\r':
           monitor_printf(mon, "\\r");
           break;
       default:
           if (c >= 32 && c <= 126) {
               monitor_printf(mon, "%c", c);
           } else {
               monitor_printf(mon, "\\x%02x", c);
           }
           break;
       }
       monitor_printf(mon, "'");
   }

> @@ -2740,13 +2334,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);
> -}
> -
>  static void monitor_command_cb(void *opaque, const char *cmdline,
>                                 void *readline_opaque)
>  {
> @@ -2757,60 +2344,6 @@ static void monitor_command_cb(void *opaque, const char *cmdline,
>      monitor_resume(&mon->common);
>  }
>  
> -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)
>  {
> @@ -2830,27 +2363,12 @@ static void sortcmdlist(void)
>      qsort((void *)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);
>  }
>  
>  /*
> @@ -2875,90 +2393,6 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap)

Why do these two stay?

   /*
    * 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());
[...]


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

* Re: [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP
  2019-06-12 11:45   ` Markus Armbruster
@ 2019-06-12 13:55     ` Kevin Wolf
  0 siblings, 0 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-12 13:55 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 12.06.2019 um 13:45 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Monitor.cmd_table contains the handlers for HMP commands, so there is no
> > reason to keep it in the state shared with QMP. Move it to MonitorHMP.
> >
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > ---
> >  monitor.c | 23 +++++++++++++++--------
> >  1 file changed, 15 insertions(+), 8 deletions(-)
> >
> > diff --git a/monitor.c b/monitor.c
> > index f8730e4462..56af8ed448 100644
> > --- a/monitor.c
> > +++ b/monitor.c
> > @@ -191,7 +191,6 @@ struct Monitor {
> >      bool use_io_thread;
> >  
> >      gchar *mon_cpu_path;
> > -    mon_cmd_t *cmd_table;
> >      QTAILQ_ENTRY(Monitor) entry;
> >  
> >      /*
> > @@ -219,6 +218,7 @@ struct MonitorHMP {
> >       * These members can be safely accessed without locks.
> >       */
> >      ReadLineState *rs;
> > +    mon_cmd_t *cmd_table;
> >  };
> >  
> >  typedef struct {
> > @@ -720,13 +720,19 @@ static void monitor_data_init(Monitor *mon, int flags, bool skip_flush,
> >      memset(mon, 0, sizeof(Monitor));
> >      qemu_mutex_init(&mon->mon_lock);
> >      mon->outbuf = qstring_new();
> > -    /* Use *mon_cmds by default. */
> > -    mon->cmd_table = mon_cmds;
> 
> As far as I can tell, this is the only assignment to Monitor member
> cmd_table.  Why not delete it outright, and use mon_cmds directly?
> Preferably renamed to something like hmp_cmds.

Good idea, I'll do that.

Kevin


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

* Re: [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-12 10:03     ` Kevin Wolf
@ 2019-06-12 14:08       ` Markus Armbruster
  2019-06-12 14:10         ` Dr. David Alan Gilbert
  2019-06-12 15:03         ` Kevin Wolf
  0 siblings, 2 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 14:08 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-block, berrange, qemu-devel, Peter Xu, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> Am 12.06.2019 um 11:07 hat Markus Armbruster geschrieben:
>> Cc: Peter for a monitor I/O thread question.
>> 
>> 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>
>
>> > @@ -218,6 +210,17 @@ 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.
>> > +     * Else, it's the main thread.
>> > +     * These members can be safely accessed without locks.
>> > +     */
>> > +    ReadLineState *rs;
>> > +};
>> > +
>> 
>> Hmm.
>> 
>> The monitor I/O thread code makes an effort not to restrict I/O thread
>> use to QMP, even though we only use it there.  Whether the code would
>> actually work for HMP as well we don't know.
>> 
>> Readline was similar until your PATCH 02: the code made an effort not to
>> restrict it to HMP, even though we only use it there.  Whether the code
>> would actually work for QMP as well we don't know.
>> 
>> Should we stop pretending and hard-code "I/O thread only for QMP"?
>> 
>> If yes, the comment above gets simplified by the patch that hard-codes
>> "I/O thread only for QMP".
>> 
>> If no, we should perhaps point out that we currently don't use an I/O
>> thread with HMP.  The comment above seems like a good place for that.
>> 
>> Perhaps restricting readline to HMP should be a separate patch before
>> PATCH 02.
>
> Yes, possibly iothreads could be restricted to QMP. It doesn't help me
> in splitting the monitor in any way, though, so I don't see it within
> the scope of this series.

That's okay.

Would you mind pointing out we don't actually use an I/O thread with HMP
in the comment?

> Keeping readline around for QMP, on the other hand, would probably have
> been harder than making the restriction.
>
> As for splitting patch 2, I don't think that reorganising a patch that
> already does its job and already received review is the most productive
> thing we could do, but if you insist on a separate patch, I can do that.

No, I don't insist.

>> > @@ -748,12 +754,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 = {};
>> 
>> Any particular reason for adding the initializer?
>
> Yes:
>
>> >  
>> > -    monitor_data_init(&hmp, 0, true, false);
>> > +    monitor_data_init(&hmp.common, 0, true, false);
>
> monitor_data_init() does a memset(), but only on hmp.common, so the
> fields outside of hmp.common would remain uniniitialised. Specifically,
> hmp.rs wouldn't be initialised to NULL and attempting to free it in the
> end would crash.

I see.

Drop the superfluous memset() in monitor_data_init() then.

>> >      old_mon = cur_mon;
>> > -    cur_mon = &hmp;
>> > +    cur_mon = &hmp.common;
>> >  
>> >      if (has_cpu_index) {
>> >          int ret = monitor_set_cpu(cpu_index);
>
>> > @@ -1341,16 +1348,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);
>> 
>> Unchecked conversion.  Tolerable, I think, since HMP command handlers
>> generally don't get invoked manually, unlike QMP command handlers.
>
> I would like to see all HMP command handlers take MonitorHMP* instead of
> Monitor*, but that would be a big ugly patch touching everything that
> isn't really needed for the goal of this series, so I didn't include it.

I consider the MonitorHMP job incomplete without it.  But it's Dave's
turf.

> If you consider it valuable to get rid of this container_of(), that's
> probably the follow-up you could do.

My recent qemu-common.h pull request temporarily cooled my enthusiasm
for big, ugly patches touching everything...

>> > @@ -4460,6 +4474,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(cur_mon, MonitorHMP, common);
>> 
>> Any particular reason for changing from @opaque to @cur_mon?
>
> Probably a copy & paste error, thanks for catching it! I'll fix it.
>
>> > @@ -4662,11 +4679,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));
>> 
>> Any particular reason for changing to g_malloc0()?
>> 
>> You hid the same change for monitor_init_qmp() in PATCH 03, where I
>> missed it until now.
>
> As above, initialising the fields outside mon->common.
>
> Kevin


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

* Re: [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-12 14:08       ` Markus Armbruster
@ 2019-06-12 14:10         ` Dr. David Alan Gilbert
  2019-06-12 15:03         ` Kevin Wolf
  1 sibling, 0 replies; 46+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-12 14:10 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, qemu-block, berrange, qemu-devel, Peter Xu

* Markus Armbruster (armbru@redhat.com) wrote:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Am 12.06.2019 um 11:07 hat Markus Armbruster geschrieben:
> >> Cc: Peter for a monitor I/O thread question.
> >> 
> >> 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>
> >
> >> > @@ -218,6 +210,17 @@ 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.
> >> > +     * Else, it's the main thread.
> >> > +     * These members can be safely accessed without locks.
> >> > +     */
> >> > +    ReadLineState *rs;
> >> > +};
> >> > +
> >> 
> >> Hmm.
> >> 
> >> The monitor I/O thread code makes an effort not to restrict I/O thread
> >> use to QMP, even though we only use it there.  Whether the code would
> >> actually work for HMP as well we don't know.
> >> 
> >> Readline was similar until your PATCH 02: the code made an effort not to
> >> restrict it to HMP, even though we only use it there.  Whether the code
> >> would actually work for QMP as well we don't know.
> >> 
> >> Should we stop pretending and hard-code "I/O thread only for QMP"?
> >> 
> >> If yes, the comment above gets simplified by the patch that hard-codes
> >> "I/O thread only for QMP".
> >> 
> >> If no, we should perhaps point out that we currently don't use an I/O
> >> thread with HMP.  The comment above seems like a good place for that.
> >> 
> >> Perhaps restricting readline to HMP should be a separate patch before
> >> PATCH 02.
> >
> > Yes, possibly iothreads could be restricted to QMP. It doesn't help me
> > in splitting the monitor in any way, though, so I don't see it within
> > the scope of this series.
> 
> That's okay.
> 
> Would you mind pointing out we don't actually use an I/O thread with HMP
> in the comment?
> 
> > Keeping readline around for QMP, on the other hand, would probably have
> > been harder than making the restriction.
> >
> > As for splitting patch 2, I don't think that reorganising a patch that
> > already does its job and already received review is the most productive
> > thing we could do, but if you insist on a separate patch, I can do that.
> 
> No, I don't insist.
> 
> >> > @@ -748,12 +754,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 = {};
> >> 
> >> Any particular reason for adding the initializer?
> >
> > Yes:
> >
> >> >  
> >> > -    monitor_data_init(&hmp, 0, true, false);
> >> > +    monitor_data_init(&hmp.common, 0, true, false);
> >
> > monitor_data_init() does a memset(), but only on hmp.common, so the
> > fields outside of hmp.common would remain uniniitialised. Specifically,
> > hmp.rs wouldn't be initialised to NULL and attempting to free it in the
> > end would crash.
> 
> I see.
> 
> Drop the superfluous memset() in monitor_data_init() then.
> 
> >> >      old_mon = cur_mon;
> >> > -    cur_mon = &hmp;
> >> > +    cur_mon = &hmp.common;
> >> >  
> >> >      if (has_cpu_index) {
> >> >          int ret = monitor_set_cpu(cpu_index);
> >
> >> > @@ -1341,16 +1348,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);
> >> 
> >> Unchecked conversion.  Tolerable, I think, since HMP command handlers
> >> generally don't get invoked manually, unlike QMP command handlers.
> >
> > I would like to see all HMP command handlers take MonitorHMP* instead of
> > Monitor*, but that would be a big ugly patch touching everything that
> > isn't really needed for the goal of this series, so I didn't include it.
> 
> I consider the MonitorHMP job incomplete without it.  But it's Dave's
> turf.

I'd rather see stuff move forward and then fix that later when someone
has the time.

Dave

> > If you consider it valuable to get rid of this container_of(), that's
> > probably the follow-up you could do.
> 
> My recent qemu-common.h pull request temporarily cooled my enthusiasm
> for big, ugly patches touching everything...
> 
> >> > @@ -4460,6 +4474,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(cur_mon, MonitorHMP, common);
> >> 
> >> Any particular reason for changing from @opaque to @cur_mon?
> >
> > Probably a copy & paste error, thanks for catching it! I'll fix it.
> >
> >> > @@ -4662,11 +4679,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));
> >> 
> >> Any particular reason for changing to g_malloc0()?
> >> 
> >> You hid the same change for monitor_init_qmp() in PATCH 03, where I
> >> missed it until now.
> >
> > As above, initialising the fields outside mon->common.
> >
> > Kevin
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor
  2019-06-12 11:28     ` Kevin Wolf
@ 2019-06-12 14:18       ` Markus Armbruster
  0 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 14:18 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> Am 12.06.2019 um 09:59 hat Markus Armbruster geschrieben:
>> 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.
>> >
>> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> 
>> This is a bit harder to review than necessary, because it mixes the
>> largely mechanical "replace QMP member by child class" with the
>> necessary prerequisite "clean up to access QMP stuff only when the
>> monitor is actually a QMP monitor".  I'm going to post a split.
>> 
>> Effectively preexisting: we go from Monitor * to MonitorQMP * without
>> checking in several places.  I'll throw in assertions.
>
> Since I don't think doing both in one patch makes review a lot harder
> (and in fact think your patch 2.5 is harder to review for completeness
> that the combined patch)

I disagree with the parenthesis.  The completeness argument is really
simple: each occurence of member qmp is either guarded by a "is a QMP
monitor" conditional, or an "is a QMP monitor" assertion, or in a
callback that takes a QMP monitor converted to void * (I didn't bother
asserting anything there).

>                          and since both Dave and you already reviewed
> the patch in its current form

Actually, I didn't review the patch "in its current form", because I
found that more bothersome than splitting it up and reviewing the parts.

By effectively squashing together the parts, you have of course every
right to claim the resulting code passed my review.  That's not quite
the same as claiming my R-by for the *patch*.

>                                   I don't want to invalidate that
> review, I'm going to keep it as a single patch and just squash in the
> additional assertions where container_of() is used. The resulting code
> is the same anyway.

Having the commit message explain that the patch mixes mechanical change
for the "replace QMP member by child class" data reorganization with its
prerequisite cleanup "access QMP stuff only when the monitor is actually
a QMP monitor" might suffice to make me acquiesce to the squashed patch.


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

* Re: [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (12 preceding siblings ...)
  2019-06-11 15:24 ` no-reply
@ 2019-06-12 14:22 ` Markus Armbruster
  13 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-12 14:22 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.

Also: it's so fat it hasn't seen its feet in years.

> 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,

It's not :)

>                                          I think it's an improvement of
> the current state even for QEMU proper,

It very much is!

There are a few issues to address, but nothing structural.  Looking
forward to v3.

>                                         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.


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

* Re: [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state
  2019-06-12 14:08       ` Markus Armbruster
  2019-06-12 14:10         ` Dr. David Alan Gilbert
@ 2019-06-12 15:03         ` Kevin Wolf
  1 sibling, 0 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-12 15:03 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-block, berrange, qemu-devel, Peter Xu, dgilbert

Am 12.06.2019 um 16:08 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Am 12.06.2019 um 11:07 hat Markus Armbruster geschrieben:
> >> Cc: Peter for a monitor I/O thread question.
> >> 
> >> 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>
> >
> >> > @@ -218,6 +210,17 @@ 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.
> >> > +     * Else, it's the main thread.
> >> > +     * These members can be safely accessed without locks.
> >> > +     */
> >> > +    ReadLineState *rs;
> >> > +};
> >> > +
> >> 
> >> Hmm.
> >> 
> >> The monitor I/O thread code makes an effort not to restrict I/O thread
> >> use to QMP, even though we only use it there.  Whether the code would
> >> actually work for HMP as well we don't know.
> >> 
> >> Readline was similar until your PATCH 02: the code made an effort not to
> >> restrict it to HMP, even though we only use it there.  Whether the code
> >> would actually work for QMP as well we don't know.
> >> 
> >> Should we stop pretending and hard-code "I/O thread only for QMP"?
> >> 
> >> If yes, the comment above gets simplified by the patch that hard-codes
> >> "I/O thread only for QMP".
> >> 
> >> If no, we should perhaps point out that we currently don't use an I/O
> >> thread with HMP.  The comment above seems like a good place for that.
> >> 
> >> Perhaps restricting readline to HMP should be a separate patch before
> >> PATCH 02.
> >
> > Yes, possibly iothreads could be restricted to QMP. It doesn't help me
> > in splitting the monitor in any way, though, so I don't see it within
> > the scope of this series.
> 
> That's okay.
> 
> Would you mind pointing out we don't actually use an I/O thread with HMP
> in the comment?

I do mind in a way (git doesn't really cope well with changing things in
the first patches of this series while the later patches move them to
different files - renaming mon_cmds resulted in a big mess and now I'm
kind of fed up with this kind of merge conflicts), but I'll do it
anyway. As long as it's only one line, it shouldn't be that hard to make
sure that it still exists at the end of the series...

> >> > @@ -748,12 +754,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 = {};
> >> 
> >> Any particular reason for adding the initializer?
> >
> > Yes:
> >
> >> >  
> >> > -    monitor_data_init(&hmp, 0, true, false);
> >> > +    monitor_data_init(&hmp.common, 0, true, false);
> >
> > monitor_data_init() does a memset(), but only on hmp.common, so the
> > fields outside of hmp.common would remain uniniitialised. Specifically,
> > hmp.rs wouldn't be initialised to NULL and attempting to free it in the
> > end would crash.
> 
> I see.
> 
> Drop the superfluous memset() in monitor_data_init() then.

Hm, yes, all callers already initialise the memory now, so that can be
done.

Kevin


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

* Re: [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c
  2019-06-12 13:11   ` Markus Armbruster
@ 2019-06-12 15:25     ` Kevin Wolf
  2019-06-13  5:38       ` Markus Armbruster
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-12 15:25 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block

Am 12.06.2019 um 15:11 hat Markus Armbruster geschrieben:
> 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.
> 
> Less code compiled per target, yay!
> 
> > 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.
> 
> That's okay.
> 
> I have to admit I naively expected the previous patch moved everything
> to the new header we need in a header for splitting up monitor/misc.c.
> How did you decide what to move to the header in which patch?

The previous patch moved only the Monitor{HMP,QMP} data structures and
their dependencies as I was sure these would be shared. Everything else
was added to address linker complaints as I was going. I'll clarify this
in the commit message of the previous patch.

> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > ---
> >  include/monitor/monitor.h |   1 +
> >  monitor/monitor_int.h     |  30 ++-
> >  monitor/misc.c            | 394 +------------------------------------
> >  monitor/qmp.c             | 404 ++++++++++++++++++++++++++++++++++++++
> >  Makefile.objs             |   1 +
> >  monitor/Makefile.objs     |   1 +
> >  monitor/trace-events      |   4 +-
> >  7 files changed, 448 insertions(+), 387 deletions(-)
> >  create mode 100644 monitor/qmp.c
> >
> > diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> > index 1ba354f811..7bbab05320 100644
> > --- a/include/monitor/monitor.h
> > +++ b/include/monitor/monitor.h
> > @@ -21,6 +21,7 @@ bool monitor_cur_is_qmp(void);
> >  
> >  void monitor_init_globals(void);
> >  void monitor_init(Chardev *chr, int flags);
> > +void monitor_init_qmp(Chardev *chr, int flags);
> 
> Why does this one go to the non-internal header?

Most callers already know whether they want QMP or HMP, so they can just
directly create the right thing instead of going through the
monitor_init() wrapper.

If you prefer, I can move it to the internal header, though. It's not
called externally yet.

> >  void monitor_cleanup(void);
> >  
> >  int monitor_suspend(Monitor *mon);
> > diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> > index 7122418955..4aabee54e1 100644
> > --- a/monitor/monitor_int.h
> > +++ b/monitor/monitor_int.h
> > @@ -30,10 +30,11 @@
> >  
> >  #include "qapi/qmp/qdict.h"
> >  #include "qapi/qmp/json-parser.h"
> > -#include "qapi/qapi-commands.h"
> > +#include "qapi/qmp/dispatch.h"
> 
> This part should be squashed into the previous patch.  You'll
> additionally need qapi/qapi-types-misc.h for QMP_CAPABILITY__MAX there,
> or keep monitor/monitor.h, even though you need it only here for
> MONITOR_USE_CONTROL.

Yes, already happened while addressing the comments you had for the
header.

> >  
> >  #include "qemu/readline.h"
> >  #include "chardev/char-fe.h"
> > +#include "sysemu/iothread.h"
> 
> Perhaps IOThread should be typedef'ed in qemu/typedefs.h.  I'm not
> asking you to do that.
> 
> >  
> >  /*
> >   * Supported types:
> > @@ -145,4 +146,31 @@ 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;
> > +
> > +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
> 
> I trust you these are indeed all needed.

The linker said so. :-)

> > diff --git a/monitor/qmp.c b/monitor/qmp.c
> > new file mode 100644
> > index 0000000000..d425b0f2ba
> > --- /dev/null
> > +++ b/monitor/qmp.c
> > @@ -0,0 +1,404 @@
> > +/*
> > + * QEMU monitor
> > + *
> > + * Copyright (c) 2003-2004 Fabrice Bellard
> 
> I'm pretty confident nothing in this file is actually due to Fabrice.
> 
> > + *
> > + * 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.
> > + */
> 
> We inherit the non-standard license regardless.  Lesson learned: do not
> add substantial code to source files with a non-standard license.

Yes. Nothing I can change here now, though. The legally safe way for
splitting files is to copy the license header.

> > +
> > +#include "qemu/osdep.h"
> > +#include "monitor_int.h"
> > +
> > +#include "chardev/char-io.h"
> > +
> > +#include "qapi/error.h"
> > +#include "qapi/qmp/qjson.h"
> > +#include "qapi/qmp/qstring.h"
> > +#include "qapi/qmp/qlist.h"
> > +#include "qapi/qapi-commands-misc.h"
> > +
> > +#include "trace.h"
> 
> Please sort the includes alphabetically (except qemu/osdep.h, of
> course).

In other words, move monitor_int.h down and remove the empty lines?

I like separating header files by "category", but that's a matter of
taste. I'll follow yours if you tell me whether I understood it
correctly.

> > +
> > +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;
> 
> Please fuse these two.

This is a code motion patch. Are you sure? [y/n]

Kevin


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

* Re: [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c
  2019-06-12 13:17   ` Markus Armbruster
@ 2019-06-12 15:31     ` Kevin Wolf
  2019-06-13  5:44       ` Markus Armbruster
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Wolf @ 2019-06-12 15:31 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Am 12.06.2019 um 15:17 hat Markus Armbruster geschrieben:
> 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>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > ---
> >  include/monitor/monitor.h |    1 +
> >  monitor/monitor_int.h     |   31 +
> >  monitor/hmp.c             | 1387 +++++++++++++++++++++++++++++++++++++
> >  monitor/misc.c            | 1338 +----------------------------------
> >  monitor/Makefile.objs     |    2 +-
> >  monitor/trace-events      |    4 +-
> >  6 files changed, 1429 insertions(+), 1334 deletions(-)
> >  create mode 100644 monitor/hmp.c
> >
> > diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> > index 7bbab05320..8547529e49 100644
> > --- a/include/monitor/monitor.h
> > +++ b/include/monitor/monitor.h
> > @@ -22,6 +22,7 @@ bool monitor_cur_is_qmp(void);
> >  void monitor_init_globals(void);
> >  void monitor_init(Chardev *chr, int flags);
> >  void monitor_init_qmp(Chardev *chr, int flags);
> > +void monitor_init_hmp(Chardev *chr, int flags);
> >  void monitor_cleanup(void);
> >  
> >  int monitor_suspend(Monitor *mon);
> > diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> > index 4aabee54e1..88eaed9c5c 100644
> > --- a/monitor/monitor_int.h
> > +++ b/monitor/monitor_int.h
> > @@ -27,6 +27,7 @@
> >  
> >  #include "qemu-common.h"
> >  #include "monitor/monitor.h"
> > +#include "qemu/cutils.h"
> >  
> >  #include "qapi/qmp/qdict.h"
> >  #include "qapi/qmp/json-parser.h"
> > @@ -154,6 +155,29 @@ static inline bool monitor_is_qmp(const Monitor *mon)
> >      return (mon->flags & MONITOR_USE_CONTROL);
> >  }
> >  
> > +/**
> > + * Is @name in the '|' separated list of names @list?
> > + */
> > +static inline int compare_cmd(const char *name, const char *list)
> > +{
> > +    const char *p, *pstart;
> > +    int len;
> > +    len = strlen(name);
> > +    p = list;
> > +    for (;;) {
> > +        pstart = p;
> > +        p = qemu_strchrnul(p, '|');
> > +        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
> > +            return 1;
> > +        }
> > +        if (*p == '\0') {
> > +            break;
> > +        }
> > +        p++;
> > +    }
> > +    return 0;
> > +}
> > +
> 
> What's the justification for inline?

It seemed small enough, but maybe it isn't (it has also grown by two
lines after fixing the coding style). I can leave it in misc.c and just
make it public.

I'd just need a more specific name than compare_cmd() to make it public.

> >  typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
> >  extern IOThread *mon_iothread;
> >  extern QEMUBH *qmp_dispatcher_bh;
> > @@ -162,6 +186,8 @@ extern QemuMutex monitor_lock;
> >  extern MonitorList mon_list;
> >  extern int mon_refcount;
> >  
> > +extern mon_cmd_t mon_cmds[];
> > +
> 
> Any particular reason for not moving this one to hmp.c, along with
> info_cmds?  Question, not demand :)

Yes, it's not part of the core infrastructure, but contains commands
specific to the system emulator. If a tool were to use HMP, it would
have to provide its own command tables.

If we ever create a monitor/hmp-sysemu.c or something like it, this
would be a good place for the tables.

Kevin


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

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

Am 12.06.2019 um 15:49 hat Markus Armbruster geschrieben:
> 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 and code that requires a system emulator or is
> > even target-dependent.
> 
> I think target-independent command handlers should move to qmp-cmds.c
> and hmp-cmds.c.  Okay to leave for later.  Mentioning it the commit
> message wouldn't hurt, though.
> 
> Also left in misc.c, and bulky enough for mention: completion callbacks.
> They should perhaps move next to their command handlers.  Okay to leave
> for later.

Ok.

> > 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>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > ---
> >  include/monitor/monitor.h |   1 +
> >  monitor/monitor_int.h     |   1 +
> >  monitor/misc.c            | 568 +----------------------------------
> >  monitor/monitor.c         | 605 ++++++++++++++++++++++++++++++++++++++
> >  MAINTAINERS               |   2 +
> >  monitor/Makefile.objs     |   2 +-
> >  monitor/trace-events      |   2 +-
> >  7 files changed, 612 insertions(+), 569 deletions(-)
> >  create mode 100644 monitor/monitor.c
> >
> > diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
> > index 8547529e49..b9f8d175ed 100644
> > --- a/include/monitor/monitor.h
> > +++ b/include/monitor/monitor.h
> > @@ -20,6 +20,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_init_qmp(Chardev *chr, int flags);
> >  void monitor_init_hmp(Chardev *chr, int flags);
> > diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
> > index 88eaed9c5c..d5fb5162f3 100644
> > --- a/monitor/monitor_int.h
> > +++ b/monitor/monitor_int.h
> > @@ -191,6 +191,7 @@ extern mon_cmd_t mon_cmds[];
> >  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 4f1168b7c3..a4ec850493 100644
> > --- a/monitor/misc.c
> > +++ b/monitor/misc.c
> > @@ -62,7 +62,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
> > @@ -117,43 +116,13 @@ 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 mon_cmd_t info_cmds[];
> >  
> >  __thread Monitor *cur_mon;
> > @@ -161,32 +130,6 @@ __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
> > - * 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);
>    }
> 
> I can see why monitor_cur_is_qmp() stays here.  But why do the next two
> stay?
> 
>    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;
>        }
>    }

No real reason. These can move to hmp.c together with
monitor_command_cb().

> > @@ -220,355 +163,6 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func,
> >  }
> >  
> >  
> > -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();
> > -    }
> > -    memset(mon, 0, sizeof(Monitor));
> > -    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)
> >  {
> [...]
> 
>    static void monitor_init_qmp_commands(void)
>    {
>        /*
>         * Two command lists:
>         * - qmp_commands contains all QMP commands
>         * - qmp_cap_negotiation_commands contains just
>         *   "qmp_capabilities", to enforce capability negotiation
>         */
> 
>        qmp_init_marshal(&qmp_commands);
> 
>        qmp_register_command(&qmp_commands, "query-qmp-schema",
>                             qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
>        qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
>                             QCO_NO_OPTIONS);
>        qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
>                             QCO_NO_OPTIONS);
> 
>        QTAILQ_INIT(&qmp_cap_negotiation_commands);
>        qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
>                             qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
>    }
> 
> Should have been moved to qmp.c in PATCH 09.

No, like the mon_cmds definitions for HMP, this is system emulator code
that must not be moved to the monitor core.

> > @@ -2875,90 +2393,6 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap)
> 
> Why do these two stay?
> 
>    /*
>     * 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;
> >  }

I think these can move to monitor.c.

Kevin


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

* Re: [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c
  2019-06-12 15:25     ` Kevin Wolf
@ 2019-06-13  5:38       ` Markus Armbruster
  2019-06-13 14:11         ` Kevin Wolf
  0 siblings, 1 reply; 46+ messages in thread
From: Markus Armbruster @ 2019-06-13  5:38 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, Markus Armbruster, qemu-block, qemu-devel

Kevin Wolf <kwolf@redhat.com> writes:

> Am 12.06.2019 um 15:11 hat Markus Armbruster geschrieben:
>> 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.
>> 
>> Less code compiled per target, yay!
>> 
>> > 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.
>> 
>> That's okay.
>> 
>> I have to admit I naively expected the previous patch moved everything
>> to the new header we need in a header for splitting up monitor/misc.c.
>> How did you decide what to move to the header in which patch?
>
> The previous patch moved only the Monitor{HMP,QMP} data structures and
> their dependencies as I was sure these would be shared. Everything else
> was added to address linker complaints as I was going. I'll clarify this
> in the commit message of the previous patch.
>
>> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> > ---
>> >  include/monitor/monitor.h |   1 +
>> >  monitor/monitor_int.h     |  30 ++-
>> >  monitor/misc.c            | 394 +------------------------------------
>> >  monitor/qmp.c             | 404 ++++++++++++++++++++++++++++++++++++++
>> >  Makefile.objs             |   1 +
>> >  monitor/Makefile.objs     |   1 +
>> >  monitor/trace-events      |   4 +-
>> >  7 files changed, 448 insertions(+), 387 deletions(-)
>> >  create mode 100644 monitor/qmp.c
>> >
>> > diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
>> > index 1ba354f811..7bbab05320 100644
>> > --- a/include/monitor/monitor.h
>> > +++ b/include/monitor/monitor.h
>> > @@ -21,6 +21,7 @@ bool monitor_cur_is_qmp(void);
>> >  
>> >  void monitor_init_globals(void);
>> >  void monitor_init(Chardev *chr, int flags);
>> > +void monitor_init_qmp(Chardev *chr, int flags);
>> 
>> Why does this one go to the non-internal header?
>
> Most callers already know whether they want QMP or HMP, so they can just
> directly create the right thing instead of going through the
> monitor_init() wrapper.
>
> If you prefer, I can move it to the internal header, though. It's not
> called externally yet.

As is, monitor_init_qmp() and monitor_init_hmp() are awkward interfaces:
what if you pass MONITOR_USE_CONTROL to monitor_init_hmp()?

I can see just one call passing flags that aren't compile-time
constant.  I think a better interface would be

    monitor_init_hmp(Chardev *chr);
    monitor_init_qmp(Chardev *chr, bool pretty);

replacing monitor_init() entirely.  This is my first preference.

My (somewhat distant) second is hiding the awkward interfaces in the
internal header for now, and clean them up later.

Your choice.

>> >  void monitor_cleanup(void);
>> >  
>> >  int monitor_suspend(Monitor *mon);
>> > diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
>> > index 7122418955..4aabee54e1 100644
>> > --- a/monitor/monitor_int.h
>> > +++ b/monitor/monitor_int.h
>> > @@ -30,10 +30,11 @@
>> >  
>> >  #include "qapi/qmp/qdict.h"
>> >  #include "qapi/qmp/json-parser.h"
>> > -#include "qapi/qapi-commands.h"
>> > +#include "qapi/qmp/dispatch.h"
>> 
>> This part should be squashed into the previous patch.  You'll
>> additionally need qapi/qapi-types-misc.h for QMP_CAPABILITY__MAX there,
>> or keep monitor/monitor.h, even though you need it only here for
>> MONITOR_USE_CONTROL.
>
> Yes, already happened while addressing the comments you had for the
> header.
>
>> >  
>> >  #include "qemu/readline.h"
>> >  #include "chardev/char-fe.h"
>> > +#include "sysemu/iothread.h"
>> 
>> Perhaps IOThread should be typedef'ed in qemu/typedefs.h.  I'm not
>> asking you to do that.
>> 
>> >  
>> >  /*
>> >   * Supported types:
>> > @@ -145,4 +146,31 @@ 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;
>> > +
>> > +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
>> 
>> I trust you these are indeed all needed.
>
> The linker said so. :-)

I've seen people stuff random crap into headers just because, but I
trust you wouldn't do that :)

>> > diff --git a/monitor/qmp.c b/monitor/qmp.c
>> > new file mode 100644
>> > index 0000000000..d425b0f2ba
>> > --- /dev/null
>> > +++ b/monitor/qmp.c
>> > @@ -0,0 +1,404 @@
>> > +/*
>> > + * QEMU monitor
>> > + *
>> > + * Copyright (c) 2003-2004 Fabrice Bellard
>> 
>> I'm pretty confident nothing in this file is actually due to Fabrice.
>> 
>> > + *
>> > + * 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.
>> > + */
>> 
>> We inherit the non-standard license regardless.  Lesson learned: do not
>> add substantial code to source files with a non-standard license.
>
> Yes. Nothing I can change here now, though. The legally safe way for
> splitting files is to copy the license header.
>
>> > +
>> > +#include "qemu/osdep.h"
>> > +#include "monitor_int.h"
>> > +
>> > +#include "chardev/char-io.h"
>> > +
>> > +#include "qapi/error.h"
>> > +#include "qapi/qmp/qjson.h"
>> > +#include "qapi/qmp/qstring.h"
>> > +#include "qapi/qmp/qlist.h"
>> > +#include "qapi/qapi-commands-misc.h"
>> > +
>> > +#include "trace.h"
>> 
>> Please sort the includes alphabetically (except qemu/osdep.h, of
>> course).
>
> In other words, move monitor_int.h down and remove the empty lines?
>
> I like separating header files by "category", but that's a matter of
> taste. I'll follow yours if you tell me whether I understood it
> correctly.

Yes.

I hate the quasi-random order of #include we have in QEMU.  The ordering
method you describe would be okay with me, except for one thing: it
takes actual thought.  Alphabetical order can be enforced / fixed up by
a simple machine.

>> > +
>> > +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;
>> 
>> Please fuse these two.
>
> This is a code motion patch. Are you sure? [y/n]

Nevermind :)


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

* Re: [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c
  2019-06-12 15:31     ` Kevin Wolf
@ 2019-06-13  5:44       ` Markus Armbruster
  0 siblings, 0 replies; 46+ messages in thread
From: Markus Armbruster @ 2019-06-13  5:44 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: berrange, qemu-devel, qemu-block, dgilbert

Kevin Wolf <kwolf@redhat.com> writes:

> Am 12.06.2019 um 15:17 hat Markus Armbruster geschrieben:
>> 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>
>> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> > ---
>> >  include/monitor/monitor.h |    1 +
>> >  monitor/monitor_int.h     |   31 +
>> >  monitor/hmp.c             | 1387 +++++++++++++++++++++++++++++++++++++
>> >  monitor/misc.c            | 1338 +----------------------------------
>> >  monitor/Makefile.objs     |    2 +-
>> >  monitor/trace-events      |    4 +-
>> >  6 files changed, 1429 insertions(+), 1334 deletions(-)
>> >  create mode 100644 monitor/hmp.c
>> >
>> > diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
>> > index 7bbab05320..8547529e49 100644
>> > --- a/include/monitor/monitor.h
>> > +++ b/include/monitor/monitor.h
>> > @@ -22,6 +22,7 @@ bool monitor_cur_is_qmp(void);
>> >  void monitor_init_globals(void);
>> >  void monitor_init(Chardev *chr, int flags);
>> >  void monitor_init_qmp(Chardev *chr, int flags);
>> > +void monitor_init_hmp(Chardev *chr, int flags);
>> >  void monitor_cleanup(void);
>> >  
>> >  int monitor_suspend(Monitor *mon);
>> > diff --git a/monitor/monitor_int.h b/monitor/monitor_int.h
>> > index 4aabee54e1..88eaed9c5c 100644
>> > --- a/monitor/monitor_int.h
>> > +++ b/monitor/monitor_int.h
>> > @@ -27,6 +27,7 @@
>> >  
>> >  #include "qemu-common.h"
>> >  #include "monitor/monitor.h"
>> > +#include "qemu/cutils.h"
>> >  
>> >  #include "qapi/qmp/qdict.h"
>> >  #include "qapi/qmp/json-parser.h"
>> > @@ -154,6 +155,29 @@ static inline bool monitor_is_qmp(const Monitor *mon)
>> >      return (mon->flags & MONITOR_USE_CONTROL);
>> >  }
>> >  
>> > +/**
>> > + * Is @name in the '|' separated list of names @list?
>> > + */
>> > +static inline int compare_cmd(const char *name, const char *list)
>> > +{
>> > +    const char *p, *pstart;
>> > +    int len;
>> > +    len = strlen(name);
>> > +    p = list;
>> > +    for (;;) {
>> > +        pstart = p;
>> > +        p = qemu_strchrnul(p, '|');
>> > +        if ((p - pstart) == len && !memcmp(pstart, name, len)) {
>> > +            return 1;
>> > +        }
>> > +        if (*p == '\0') {
>> > +            break;
>> > +        }
>> > +        p++;
>> > +    }
>> > +    return 0;
>> > +}
>> > +
>> 
>> What's the justification for inline?
>
> It seemed small enough, but maybe it isn't (it has also grown by two
> lines after fixing the coding style). I can leave it in misc.c and just
> make it public.

Yes, please.

> I'd just need a more specific name than compare_cmd() to make it public.

Arguably a good idea even for static inlines in an internal header :)

>> >  typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList;
>> >  extern IOThread *mon_iothread;
>> >  extern QEMUBH *qmp_dispatcher_bh;
>> > @@ -162,6 +186,8 @@ extern QemuMutex monitor_lock;
>> >  extern MonitorList mon_list;
>> >  extern int mon_refcount;
>> >  
>> > +extern mon_cmd_t mon_cmds[];
>> > +
>> 
>> Any particular reason for not moving this one to hmp.c, along with
>> info_cmds?  Question, not demand :)
>
> Yes, it's not part of the core infrastructure, but contains commands
> specific to the system emulator. If a tool were to use HMP, it would
> have to provide its own command tables.
>
> If we ever create a monitor/hmp-sysemu.c or something like it, this
> would be a good place for the tables.

I'm very much in favor of splitting up monitor/misc.c further.  It's
okay to leave that for later, of course.


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

* Re: [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c
  2019-06-13  5:38       ` Markus Armbruster
@ 2019-06-13 14:11         ` Kevin Wolf
  0 siblings, 0 replies; 46+ messages in thread
From: Kevin Wolf @ 2019-06-13 14:11 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: berrange, qemu-devel, qemu-block

Am 13.06.2019 um 07:38 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Am 12.06.2019 um 15:11 hat Markus Armbruster geschrieben:
> >> Kevin Wolf <kwolf@redhat.com> writes:
> >> > --- a/include/monitor/monitor.h
> >> > +++ b/include/monitor/monitor.h
> >> > @@ -21,6 +21,7 @@ bool monitor_cur_is_qmp(void);
> >> >  
> >> >  void monitor_init_globals(void);
> >> >  void monitor_init(Chardev *chr, int flags);
> >> > +void monitor_init_qmp(Chardev *chr, int flags);
> >> 
> >> Why does this one go to the non-internal header?
> >
> > Most callers already know whether they want QMP or HMP, so they can just
> > directly create the right thing instead of going through the
> > monitor_init() wrapper.
> >
> > If you prefer, I can move it to the internal header, though. It's not
> > called externally yet.
> 
> As is, monitor_init_qmp() and monitor_init_hmp() are awkward interfaces:
> what if you pass MONITOR_USE_CONTROL to monitor_init_hmp()?
> 
> I can see just one call passing flags that aren't compile-time
> constant.  I think a better interface would be
> 
>     monitor_init_hmp(Chardev *chr);
>     monitor_init_qmp(Chardev *chr, bool pretty);
> 
> replacing monitor_init() entirely.  This is my first preference.
> 
> My (somewhat distant) second is hiding the awkward interfaces in the
> internal header for now, and clean them up later.
> 
> Your choice.

I'm doing both, as in move it to the internal header in the code motion
patches, but add some patches at the end of the series to clean it up.

Kevin


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

end of thread, other threads:[~2019-06-13 14:51 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-11 13:40 [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 01/11] monitor: Remove unused password prompting fields Kevin Wolf
2019-06-12  6:43   ` Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 02/11] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
2019-06-12  6:12   ` Markus Armbruster
2019-06-12  6:43     ` Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 03/11] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
2019-06-12  7:59   ` Markus Armbruster
2019-06-12 11:28     ` Kevin Wolf
2019-06-12 14:18       ` Markus Armbruster
2019-06-12  8:05   ` [Qemu-devel] [PATCH v2.1 02.5/11] monitor: Restrict use of Monitor member qmp to actual QMP monitors Markus Armbruster
2019-06-12  8:05   ` [Qemu-devel] [PATCH v2.1 03/11] monitor: Make MonitorQMP a child class of Monitor Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 04/11] monitor: Create MonitorHMP with readline state Kevin Wolf
2019-06-12  9:07   ` Markus Armbruster
2019-06-12  9:54     ` Peter Xu
2019-06-12 10:03     ` Kevin Wolf
2019-06-12 14:08       ` Markus Armbruster
2019-06-12 14:10         ` Dr. David Alan Gilbert
2019-06-12 15:03         ` Kevin Wolf
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 05/11] monitor: Move cmd_table to MonitorHMP Kevin Wolf
2019-06-12 11:45   ` Markus Armbruster
2019-06-12 13:55     ` Kevin Wolf
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 06/11] Move monitor.c to monitor/misc.c Kevin Wolf
2019-06-11 15:38   ` Dr. David Alan Gilbert
2019-06-12 11:57   ` Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 07/11] monitor: Move {hmp, qmp}.c to monitor/{hmp, qmp}-cmds.c Kevin Wolf
2019-06-11 16:09   ` Dr. David Alan Gilbert
2019-06-12 12:01   ` Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 08/11] monitor: Create monitor_int.h with common definitions Kevin Wolf
2019-06-12 12:18   ` Markus Armbruster
2019-06-12 12:43   ` Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 09/11] monitor: Split out monitor/qmp.c Kevin Wolf
2019-06-12 13:11   ` Markus Armbruster
2019-06-12 15:25     ` Kevin Wolf
2019-06-13  5:38       ` Markus Armbruster
2019-06-13 14:11         ` Kevin Wolf
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 10/11] monitor: Split out monitor/hmp.c Kevin Wolf
2019-06-12 13:17   ` Markus Armbruster
2019-06-12 15:31     ` Kevin Wolf
2019-06-13  5:44       ` Markus Armbruster
2019-06-11 13:40 ` [Qemu-devel] [PATCH v2 11/11] monitor: Split out monitor/monitor.c Kevin Wolf
2019-06-12 13:49   ` Markus Armbruster
2019-06-12 15:51     ` Kevin Wolf
2019-06-11 14:18 ` [Qemu-devel] [PATCH v2 00/11] monitor: Split monitor.c in core/HMP/QMP/misc no-reply
2019-06-11 15:24 ` no-reply
2019-06-12 14:22 ` Markus Armbruster

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.