qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
@ 2019-06-07 13:54 Kevin Wolf
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields Kevin Wolf
                   ` (12 more replies)
  0 siblings, 13 replies; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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.

Kevin Wolf (10):
  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: Create monitor_int.h with common definitions
  monitor: Split out monitor/qmp.c
  monitor: Split out monitor/hmp.c
  monitor: Split out monitor/core.c

 include/monitor/monitor.h |    8 +-
 monitor/monitor_int.h     |  207 ++
 hmp.c                     |    4 +-
 monitor.c                 | 4727 -------------------------------------
 monitor/core.c            |  604 +++++
 monitor/hmp.c             | 1351 +++++++++++
 monitor/misc.c            | 2406 +++++++++++++++++++
 monitor/qmp.c             |  404 ++++
 Makefile.objs             |    1 +
 Makefile.target           |    3 +-
 monitor/Makefile.objs     |    2 +
 11 files changed, 4986 insertions(+), 4731 deletions(-)
 create mode 100644 monitor/monitor_int.h
 delete mode 100644 monitor.c
 create mode 100644 monitor/core.c
 create mode 100644 monitor/hmp.c
 create mode 100644 monitor/misc.c
 create mode 100644 monitor/qmp.c
 create mode 100644 monitor/Makefile.objs

-- 
2.20.1



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

* [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 15:39   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 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] 31+ messages in thread

* [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 15:46   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 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] 31+ messages in thread

* [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields Kevin Wolf
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 16:17   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state Kevin Wolf
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 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] 31+ messages in thread

* [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (2 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 16:32   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP Kevin Wolf
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 include/monitor/monitor.h |   5 +-
 hmp.c                     |   4 +-
 monitor.c                 | 123 +++++++++++++++++++++-----------------
 3 files changed, 75 insertions(+), 57 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..810f3dcf9c 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,14 +1348,15 @@ 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);
+        str = readline_get_history(hmp_mon->rs, i);
         if (!str)
             break;
         monitor_printf(mon, "%d: '%s'\n", i, str);
@@ -3048,11 +3056,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 +3092,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 +3469,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 +3477,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 +3520,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 +4009,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 +4104,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 +4124,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 +4335,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 +4358,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 +4408,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 +4472,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 +4480,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 +4507,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 +4569,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 +4677,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 +4691,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] 31+ messages in thread

* [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (3 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 16:35   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c Kevin Wolf
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 monitor.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/monitor.c b/monitor.c
index 810f3dcf9c..d964dd1969 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);
 }
@@ -3477,7 +3484,7 @@ static void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
 
     trace_handle_hmp_command(mon, cmdline);
 
-    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_table);
+    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
     if (!cmd) {
         return;
     }
@@ -4124,7 +4131,7 @@ static void monitor_find_completion(void *opaque,
     }
 
     /* 2. auto complete according to args */
-    monitor_find_completion_by_table(mon, mon->common.cmd_table, args, nb_args);
+    monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
 
 cleanup:
     free_cmdline_args(args, nb_args);
@@ -4680,7 +4687,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] 31+ messages in thread

* [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (4 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 16:39   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions Kevin Wolf
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 monitor.c => monitor/misc.c | 0
 Makefile.target             | 3 ++-
 monitor/Makefile.objs       | 1 +
 3 files changed, 3 insertions(+), 1 deletion(-)
 rename monitor.c => monitor/misc.c (100%)
 create mode 100644 monitor/Makefile.objs

diff --git a/monitor.c b/monitor/misc.c
similarity index 100%
rename from monitor.c
rename to monitor/misc.c
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
-- 
2.20.1



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

* [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (5 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 16:52   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c Kevin Wolf
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 monitor/monitor_int.h | 147 ++++++++++++++++++++++++++++++++++++++++++
 monitor/misc.c        | 110 +------------------------------
 2 files changed, 148 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..ab87013b6f
--- /dev/null
+++ b/monitor/monitor_int.h
@@ -0,0 +1,147 @@
+/*
+ * 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 d964dd1969..6ae7561105 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;
 
-- 
2.20.1



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

* [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (6 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 16:59   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c Kevin Wolf
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 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 +
 6 files changed, 445 insertions(+), 386 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 ab87013b6f..487618392f 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:
@@ -144,4 +145,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 6ae7561105..6c67f0978c 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.
@@ -2251,7 +2172,7 @@ static void monitor_fdset_cleanup(MonFdset *mon_fdset)
     }
 }
 
-static void monitor_fdsets_cleanup(void)
+void monitor_fdsets_cleanup(void)
 {
     MonFdset *mon_fdset;
     MonFdset *mon_fdset_next;
@@ -4029,209 +3950,13 @@ cleanup:
     free_cmdline_args(args, nb_args);
 }
 
-static int monitor_can_read(void *opaque)
+int monitor_can_read(void *opaque)
 {
     Monitor *mon = opaque;
 
     return !atomic_mb_read(&mon->suspend_cnt);
 }
 
-/*
- * Emit QMP response @rsp with ID @id to @mon.
- * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP.
- * Nothing is emitted then.
- */
-static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp)
-{
-    if (rsp) {
-        qmp_send_response(mon, rsp);
-    }
-}
-
-static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req)
-{
-    Monitor *old_mon;
-    QDict *rsp;
-    QDict *error;
-
-    old_mon = cur_mon;
-    cur_mon = &mon->common;
-
-    rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon));
-
-    cur_mon = old_mon;
-
-    if (mon->commands == &qmp_cap_negotiation_commands) {
-        error = qdict_get_qdict(rsp, "error");
-        if (error
-            && !g_strcmp0(qdict_get_try_str(error, "class"),
-                    QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
-            /* Provide a more useful error message */
-            qdict_del(error, "desc");
-            qdict_put_str(error, "desc", "Expecting capabilities negotiation"
-                          " with 'qmp_capabilities'");
-        }
-    }
-
-    monitor_qmp_respond(mon, rsp);
-    qobject_unref(rsp);
-}
-
-/*
- * Pop a QMP request from a monitor request queue.
- * Return the request, or NULL all request queues are empty.
- * We are using round-robin fashion to pop the request, to avoid
- * processing commands only on a very busy monitor.  To achieve that,
- * when we process one request on a specific monitor, we put that
- * monitor to the end of mon_list queue.
- *
- * Note: if the function returned with non-NULL, then the caller will
- * be with qmp_mon->qmp_queue_lock held, and the caller is responsible
- * to release it.
- */
-static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
-{
-    QMPRequest *req_obj = NULL;
-    Monitor *mon;
-    MonitorQMP *qmp_mon;
-
-    qemu_mutex_lock(&monitor_lock);
-
-    QTAILQ_FOREACH(mon, &mon_list, entry) {
-        if (!monitor_is_qmp(mon)) {
-            continue;
-        }
-
-        qmp_mon = container_of(mon, MonitorQMP, common);
-        qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
-        req_obj = g_queue_pop_head(qmp_mon->qmp_requests);
-        if (req_obj) {
-            /* With the lock of corresponding queue held */
-            break;
-        }
-        qemu_mutex_unlock(&qmp_mon->qmp_queue_lock);
-    }
-
-    if (req_obj) {
-        /*
-         * We found one request on the monitor. Degrade this monitor's
-         * priority to lowest by re-inserting it to end of queue.
-         */
-        QTAILQ_REMOVE(&mon_list, mon, entry);
-        QTAILQ_INSERT_TAIL(&mon_list, mon, entry);
-    }
-
-    qemu_mutex_unlock(&monitor_lock);
-
-    return req_obj;
-}
-
-static void monitor_qmp_bh_dispatcher(void *data)
-{
-    QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
-    QDict *rsp;
-    bool need_resume;
-    MonitorQMP *mon;
-
-    if (!req_obj) {
-        return;
-    }
-
-    mon = req_obj->mon;
-    /*  qmp_oob_enabled() might change after "qmp_capabilities" */
-    need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
-    qemu_mutex_unlock(&mon->qmp_queue_lock);
-    if (req_obj->req) {
-        QDict *qdict = qobject_to(QDict, req_obj->req);
-        QObject *id = qdict ? qdict_get(qdict, "id") : NULL;
-        trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: "");
-        monitor_qmp_dispatch(mon, req_obj->req);
-    } else {
-        assert(req_obj->err);
-        rsp = qmp_error_response(req_obj->err);
-        req_obj->err = NULL;
-        monitor_qmp_respond(mon, rsp);
-        qobject_unref(rsp);
-    }
-
-    if (need_resume) {
-        /* Pairs with the monitor_suspend() in handle_qmp_command() */
-        monitor_resume(&mon->common);
-    }
-    qmp_request_free(req_obj);
-
-    /* Reschedule instead of looping so the main loop stays responsive */
-    qemu_bh_schedule(qmp_dispatcher_bh);
-}
-
-static void handle_qmp_command(void *opaque, QObject *req, Error *err)
-{
-    MonitorQMP *mon = opaque;
-    QObject *id = NULL;
-    QDict *qdict;
-    QMPRequest *req_obj;
-
-    assert(!req != !err);
-
-    qdict = qobject_to(QDict, req);
-    if (qdict) {
-        id = qdict_get(qdict, "id");
-    } /* else will fail qmp_dispatch() */
-
-    if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
-        QString *req_json = qobject_to_json(req);
-        trace_handle_qmp_command(mon, qstring_get_str(req_json));
-        qobject_unref(req_json);
-    }
-
-    if (qdict && qmp_is_oob(qdict)) {
-        /* OOB commands are executed immediately */
-        trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: "");
-        monitor_qmp_dispatch(mon, req);
-        qobject_unref(req);
-        return;
-    }
-
-    req_obj = g_new0(QMPRequest, 1);
-    req_obj->mon = mon;
-    req_obj->req = req;
-    req_obj->err = err;
-
-    /* Protect qmp_requests and fetching its length. */
-    qemu_mutex_lock(&mon->qmp_queue_lock);
-
-    /*
-     * Suspend the monitor when we can't queue more requests after
-     * this one.  Dequeuing in monitor_qmp_bh_dispatcher() will resume
-     * it.  Note that when OOB is disabled, we queue at most one
-     * command, for backward compatibility.
-     */
-    if (!qmp_oob_enabled(mon) ||
-        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
-        monitor_suspend(&mon->common);
-    }
-
-    /*
-     * Put the request to the end of queue so that requests will be
-     * handled in time order.  Ownership for req_obj, req,
-     * etc. will be delivered to the handler side.
-     */
-    assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
-    g_queue_push_tail(mon->qmp_requests, req_obj);
-    qemu_mutex_unlock(&mon->qmp_queue_lock);
-
-    /* Kick the dispatcher routine */
-    qemu_bh_schedule(qmp_dispatcher_bh);
-}
-
-static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
-{
-    MonitorQMP *mon = opaque;
-
-    json_message_parser_feed(&mon->parser, (const char *) buf, size);
-}
-
 static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
     MonitorHMP *mon;
@@ -4318,56 +4043,6 @@ void monitor_resume(Monitor *mon)
     trace_monitor_suspend(mon, -1);
 }
 
-static QDict *qmp_greeting(MonitorQMP *mon)
-{
-    QList *cap_list = qlist_new();
-    QObject *ver = NULL;
-    QMPCapability cap;
-
-    qmp_marshal_query_version(NULL, &ver, NULL);
-
-    for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) {
-        if (mon->capab_offered[cap]) {
-            qlist_append_str(cap_list, QMPCapability_str(cap));
-        }
-    }
-
-    return qdict_from_jsonf_nofail(
-        "{'QMP': {'version': %p, 'capabilities': %p}}",
-        ver, cap_list);
-}
-
-static void monitor_qmp_event(void *opaque, int event)
-{
-    QDict *data;
-    MonitorQMP *mon = opaque;
-
-    switch (event) {
-    case CHR_EVENT_OPENED:
-        mon->commands = &qmp_cap_negotiation_commands;
-        monitor_qmp_caps_reset(mon);
-        data = qmp_greeting(mon);
-        qmp_send_response(mon, data);
-        qobject_unref(data);
-        mon_refcount++;
-        break;
-    case CHR_EVENT_CLOSED:
-        /*
-         * Note: this is only useful when the output of the chardev
-         * backend is still open.  For example, when the backend is
-         * stdio, it's possible that stdout is still open when stdin
-         * is closed.
-         */
-        monitor_qmp_cleanup_queues(mon);
-        json_message_parser_destroy(&mon->parser);
-        json_message_parser_init(&mon->parser, handle_qmp_command,
-                                 mon, NULL);
-        mon_refcount--;
-        monitor_fdsets_cleanup();
-        break;
-    }
-}
-
 static void monitor_event(void *opaque, int event)
 {
     Monitor *mon = opaque;
@@ -4503,7 +4178,7 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap)
     return -1;
 }
 
-static void monitor_list_append(Monitor *mon)
+void monitor_list_append(Monitor *mon)
 {
     qemu_mutex_lock(&monitor_lock);
     /*
@@ -4523,57 +4198,6 @@ static void monitor_list_append(Monitor *mon)
     }
 }
 
-static void monitor_qmp_setup_handlers_bh(void *opaque)
-{
-    MonitorQMP *mon = opaque;
-    GMainContext *context;
-
-    assert(mon->common.use_io_thread);
-    context = iothread_get_g_main_context(mon_iothread);
-    assert(context);
-    qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read,
-                             monitor_qmp_read, monitor_qmp_event,
-                             NULL, &mon->common, context, true);
-    monitor_list_append(&mon->common);
-}
-
-static void monitor_init_qmp(Chardev *chr, int flags)
-{
-    MonitorQMP *mon = g_malloc0(sizeof(*mon));
-
-    /* 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..74e72cf5b8
--- /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-root.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 c8337fa34b..76c5b525f9 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 e783b0616b..d04d58b583 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -1 +1,2 @@
 obj-y += misc.o
+common-obj-y += qmp.o
-- 
2.20.1



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

* [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (7 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 17:21   ` Dr. David Alan Gilbert
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c Kevin Wolf
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, 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>
---
 include/monitor/monitor.h |    1 +
 monitor/monitor_int.h     |   31 +
 monitor/hmp.c             | 1351 +++++++++++++++++++++++++++++++++++++
 monitor/misc.c            | 1338 +-----------------------------------
 monitor/Makefile.objs     |    2 +-
 5 files changed, 1390 insertions(+), 1333 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 487618392f..8c5d95f942 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"
@@ -153,6 +154,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;
@@ -161,6 +185,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);
@@ -172,4 +198,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..2bc464a7fc
--- /dev/null
+++ b/monitor/hmp.c
@@ -0,0 +1,1351 @@
+/*
+ * 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-root.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 6c67f0978c..408d11e1fe 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"));
@@ -2510,30 +2256,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();
@@ -2576,829 +2308,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)
 {
@@ -3829,127 +2738,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;
@@ -3957,28 +2745,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)
 {
@@ -4043,58 +2809,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)
 {
@@ -4137,25 +2851,6 @@ void monitor_init_globals(void)
                                    NULL);
 }
 
-/* These functions just adapt the readline interface in a typesafe way.  We
- * could cast function pointers but that discards compiler checks.
- */
-static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
-                                                       const char *fmt, ...)
-{
-    MonitorHMP *mon = opaque;
-    va_list ap;
-    va_start(ap, fmt);
-    monitor_vprintf(&mon->common, fmt, ap);
-    va_end(ap);
-}
-
-static void monitor_readline_flush(void *opaque)
-{
-    MonitorHMP *mon = opaque;
-    monitor_flush(&mon->common);
-}
-
 /*
  * Print to current monitor if we have one, else to stderr.
  */
@@ -4198,27 +2893,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 d04d58b583..48c73eed51 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y += misc.o
-common-obj-y += qmp.o
+common-obj-y += qmp.o hmp.o
-- 
2.20.1



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

* [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (8 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c Kevin Wolf
@ 2019-06-07 13:54 ` Kevin Wolf
  2019-06-07 17:29   ` Dr. David Alan Gilbert
  2019-06-07 17:30   ` Dr. David Alan Gilbert
  2019-06-07 14:03 ` [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Daniel P. Berrangé
                   ` (2 subsequent siblings)
  12 siblings, 2 replies; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 13:54 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, armbru, qemu-block, dgilbert

Move the monitor core infrastructure from monitor/misc.c to
monitor/core.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>
---
 include/monitor/monitor.h |   1 +
 monitor/monitor_int.h     |   1 +
 monitor/core.c            | 604 ++++++++++++++++++++++++++++++++++++++
 monitor/misc.c            | 567 +----------------------------------
 monitor/Makefile.objs     |   2 +-
 5 files changed, 608 insertions(+), 567 deletions(-)
 create mode 100644 monitor/core.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 8c5d95f942..1a7af6a223 100644
--- a/monitor/monitor_int.h
+++ b/monitor/monitor_int.h
@@ -190,6 +190,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/core.c b/monitor/core.c
new file mode 100644
index 0000000000..1cea56054b
--- /dev/null
+++ b/monitor/core.c
@@ -0,0 +1,604 @@
+/*
+ * 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-root.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/monitor/misc.c b/monitor/misc.c
index 408d11e1fe..1f60f31c95 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -117,43 +117,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 +131,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 +164,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)
 {
@@ -2738,13 +2333,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)
 {
@@ -2755,60 +2343,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)
 {
@@ -2828,27 +2362,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);
 }
 
 /*
@@ -2873,90 +2392,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/Makefile.objs b/monitor/Makefile.objs
index 48c73eed51..c8dff5e4b5 100644
--- a/monitor/Makefile.objs
+++ b/monitor/Makefile.objs
@@ -1,2 +1,2 @@
 obj-y += misc.o
-common-obj-y += qmp.o hmp.o
+common-obj-y += core.o qmp.o hmp.o
-- 
2.20.1



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

* Re: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (9 preceding siblings ...)
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c Kevin Wolf
@ 2019-06-07 14:03 ` Daniel P. Berrangé
  2019-06-07 14:25   ` Kevin Wolf
  2019-06-07 16:48 ` [Qemu-devel] " no-reply
  2019-06-07 20:42 ` no-reply
  12 siblings, 1 reply; 31+ messages in thread
From: Daniel P. Berrangé @ 2019-06-07 14:03 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, qemu-devel, qemu-block, armbru

On Fri, Jun 07, 2019 at 03:54:20PM +0200, Kevin Wolf wrote:
> 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.
> 
> Kevin Wolf (10):
>   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: Create monitor_int.h with common definitions
>   monitor: Split out monitor/qmp.c
>   monitor: Split out monitor/hmp.c
>   monitor: Split out monitor/core.c
> 
>  include/monitor/monitor.h |    8 +-
>  monitor/monitor_int.h     |  207 ++
>  hmp.c                     |    4 +-
>  monitor.c                 | 4727 -------------------------------------
>  monitor/core.c            |  604 +++++
>  monitor/hmp.c             | 1351 +++++++++++
>  monitor/misc.c            | 2406 +++++++++++++++++++
>  monitor/qmp.c             |  404 ++++
>  Makefile.objs             |    1 +
>  Makefile.target           |    3 +-
>  monitor/Makefile.objs     |    2 +

It will be nice to have the monitor code split up a bit more.

I'm not a fan, however, of having both $ROOT/qmp.c and $ROOT/monitor/qmp.c
Likwise  $ROOT/hmp.c and $ROOT/monitor/hmp.c.  Can we move those other
existing files out of the root dir, into monitor/, so we don't have two
files with the same name in different dirs.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


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

* Re: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 14:03 ` [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Daniel P. Berrangé
@ 2019-06-07 14:25   ` Kevin Wolf
  2019-06-07 14:31     ` Daniel P. Berrangé
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-07 14:25 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: dgilbert, qemu-devel, qemu-block, armbru

Am 07.06.2019 um 16:03 hat Daniel P. Berrangé geschrieben:
> On Fri, Jun 07, 2019 at 03:54:20PM +0200, Kevin Wolf wrote:
> > 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.
> > 
> > Kevin Wolf (10):
> >   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: Create monitor_int.h with common definitions
> >   monitor: Split out monitor/qmp.c
> >   monitor: Split out monitor/hmp.c
> >   monitor: Split out monitor/core.c
> > 
> >  include/monitor/monitor.h |    8 +-
> >  monitor/monitor_int.h     |  207 ++
> >  hmp.c                     |    4 +-
> >  monitor.c                 | 4727 -------------------------------------
> >  monitor/core.c            |  604 +++++
> >  monitor/hmp.c             | 1351 +++++++++++
> >  monitor/misc.c            | 2406 +++++++++++++++++++
> >  monitor/qmp.c             |  404 ++++
> >  Makefile.objs             |    1 +
> >  Makefile.target           |    3 +-
> >  monitor/Makefile.objs     |    2 +
> 
> It will be nice to have the monitor code split up a bit more.
> 
> I'm not a fan, however, of having both $ROOT/qmp.c and $ROOT/monitor/qmp.c
> Likwise  $ROOT/hmp.c and $ROOT/monitor/hmp.c.  Can we move those other
> existing files out of the root dir, into monitor/, so we don't have two
> files with the same name in different dirs.

$ROOT/hmp.c and $ROOT/qmp.c contain various command implementations,
just as $ROOT/monitor/misc.c. This is still a bit of a mess. I'll have
to address this at least partially in the next step because I need to
separate commands that can be linked with tools from those that require
a system emulator.

My plan involves at least creating some monitor/qmp-cmds-*.c, which
might already make $ROOT/qmp.c empty. Even though I don't strictly need
it, there's no reason not to do the same for HMP, too. In any case, I'd
rather address this in a separate follow-up series.

But if people prefer, I can move the existing files in the root
directory to monitor/{qmp,hmp}-cmds.c temporarily in this series and
then work from there with follow-ups until they are empty (or maybe I
don't even have to make them completely empty then).

Kevin


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

* Re: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 14:25   ` Kevin Wolf
@ 2019-06-07 14:31     ` Daniel P. Berrangé
  2019-06-07 15:35       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 31+ messages in thread
From: Daniel P. Berrangé @ 2019-06-07 14:31 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: dgilbert, qemu-devel, qemu-block, armbru

On Fri, Jun 07, 2019 at 04:25:14PM +0200, Kevin Wolf wrote:
> Am 07.06.2019 um 16:03 hat Daniel P. Berrangé geschrieben:
> > On Fri, Jun 07, 2019 at 03:54:20PM +0200, Kevin Wolf wrote:
> > > 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.
> > > 
> > > Kevin Wolf (10):
> > >   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: Create monitor_int.h with common definitions
> > >   monitor: Split out monitor/qmp.c
> > >   monitor: Split out monitor/hmp.c
> > >   monitor: Split out monitor/core.c
> > > 
> > >  include/monitor/monitor.h |    8 +-
> > >  monitor/monitor_int.h     |  207 ++
> > >  hmp.c                     |    4 +-
> > >  monitor.c                 | 4727 -------------------------------------
> > >  monitor/core.c            |  604 +++++
> > >  monitor/hmp.c             | 1351 +++++++++++
> > >  monitor/misc.c            | 2406 +++++++++++++++++++
> > >  monitor/qmp.c             |  404 ++++
> > >  Makefile.objs             |    1 +
> > >  Makefile.target           |    3 +-
> > >  monitor/Makefile.objs     |    2 +
> > 
> > It will be nice to have the monitor code split up a bit more.
> > 
> > I'm not a fan, however, of having both $ROOT/qmp.c and $ROOT/monitor/qmp.c
> > Likwise  $ROOT/hmp.c and $ROOT/monitor/hmp.c.  Can we move those other
> > existing files out of the root dir, into monitor/, so we don't have two
> > files with the same name in different dirs.
> 
> $ROOT/hmp.c and $ROOT/qmp.c contain various command implementations,
> just as $ROOT/monitor/misc.c. This is still a bit of a mess. I'll have
> to address this at least partially in the next step because I need to
> separate commands that can be linked with tools from those that require
> a system emulator.
> 
> My plan involves at least creating some monitor/qmp-cmds-*.c, which
> might already make $ROOT/qmp.c empty. Even though I don't strictly need
> it, there's no reason not to do the same for HMP, too. In any case, I'd
> rather address this in a separate follow-up series.

Ok, if you have a plan for this, that's fine with me.

> But if people prefer, I can move the existing files in the root
> directory to monitor/{qmp,hmp}-cmds.c temporarily in this series and
> then work from there with follow-ups until they are empty (or maybe I
> don't even have to make them completely empty then).

A plain rename like this won't hurt in the meantime.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


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

* Re: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 14:31     ` Daniel P. Berrangé
@ 2019-06-07 15:35       ` Dr. David Alan Gilbert
  2019-06-07 18:11         ` [Qemu-devel] [Qemu-block] " Eric Blake
  0 siblings, 1 reply; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 15:35 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: Kevin Wolf, qemu-devel, qemu-block, armbru

* Daniel P. Berrangé (berrange@redhat.com) wrote:
> On Fri, Jun 07, 2019 at 04:25:14PM +0200, Kevin Wolf wrote:
> > Am 07.06.2019 um 16:03 hat Daniel P. Berrangé geschrieben:
> > > On Fri, Jun 07, 2019 at 03:54:20PM +0200, Kevin Wolf wrote:
> > > > 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.
> > > > 
> > > > Kevin Wolf (10):
> > > >   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: Create monitor_int.h with common definitions
> > > >   monitor: Split out monitor/qmp.c
> > > >   monitor: Split out monitor/hmp.c
> > > >   monitor: Split out monitor/core.c
> > > > 
> > > >  include/monitor/monitor.h |    8 +-
> > > >  monitor/monitor_int.h     |  207 ++
> > > >  hmp.c                     |    4 +-
> > > >  monitor.c                 | 4727 -------------------------------------
> > > >  monitor/core.c            |  604 +++++
> > > >  monitor/hmp.c             | 1351 +++++++++++
> > > >  monitor/misc.c            | 2406 +++++++++++++++++++
> > > >  monitor/qmp.c             |  404 ++++
> > > >  Makefile.objs             |    1 +
> > > >  Makefile.target           |    3 +-
> > > >  monitor/Makefile.objs     |    2 +
> > > 
> > > It will be nice to have the monitor code split up a bit more.
> > > 
> > > I'm not a fan, however, of having both $ROOT/qmp.c and $ROOT/monitor/qmp.c
> > > Likwise  $ROOT/hmp.c and $ROOT/monitor/hmp.c.  Can we move those other
> > > existing files out of the root dir, into monitor/, so we don't have two
> > > files with the same name in different dirs.
> > 
> > $ROOT/hmp.c and $ROOT/qmp.c contain various command implementations,
> > just as $ROOT/monitor/misc.c. This is still a bit of a mess. I'll have
> > to address this at least partially in the next step because I need to
> > separate commands that can be linked with tools from those that require
> > a system emulator.
> > 
> > My plan involves at least creating some monitor/qmp-cmds-*.c, which
> > might already make $ROOT/qmp.c empty. Even though I don't strictly need
> > it, there's no reason not to do the same for HMP, too. In any case, I'd
> > rather address this in a separate follow-up series.
> 
> Ok, if you have a plan for this, that's fine with me.
> 
> > But if people prefer, I can move the existing files in the root
> > directory to monitor/{qmp,hmp}-cmds.c temporarily in this series and
> > then work from there with follow-ups until they are empty (or maybe I
> > don't even have to make them completely empty then).
> 
> A plain rename like this won't hurt in the meantime.

Yeh agreed, my brain hurts too much with files of the same name.

Dave

> Regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields Kevin Wolf
@ 2019-06-07 15:39   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 15:39 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

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

A shame, I love the idea of password completion.  123<tab>

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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
@ 2019-06-07 15:46   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 15:46 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
@ 2019-06-07 16:17   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 16:17 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state Kevin Wolf
@ 2019-06-07 16:32   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 16:32 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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                 | 123 +++++++++++++++++++++-----------------
>  3 files changed, 75 insertions(+), 57 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..810f3dcf9c 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,14 +1348,15 @@ 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);
> +        str = readline_get_history(hmp_mon->rs, i);
>          if (!str)
>              break;
>          monitor_printf(mon, "%d: '%s'\n", i, str);
> @@ -3048,11 +3056,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 +3092,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 +3469,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 +3477,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 +3520,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 +4009,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 +4104,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 +4124,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 +4335,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 +4358,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 +4408,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 +4472,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 +4480,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 +4507,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 +4569,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 +4677,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 +4691,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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP Kevin Wolf
@ 2019-06-07 16:35   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 16:35 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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 810f3dcf9c..d964dd1969 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);
>  }
> @@ -3477,7 +3484,7 @@ static void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
>  
>      trace_handle_hmp_command(mon, cmdline);
>  
> -    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->common.cmd_table);
> +    cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
>      if (!cmd) {
>          return;
>      }
> @@ -4124,7 +4131,7 @@ static void monitor_find_completion(void *opaque,
>      }
>  
>      /* 2. auto complete according to args */
> -    monitor_find_completion_by_table(mon, mon->common.cmd_table, args, nb_args);
> +    monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
>  
>  cleanup:
>      free_cmdline_args(args, nb_args);
> @@ -4680,7 +4687,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
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c Kevin Wolf
@ 2019-06-07 16:39   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 16:39 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: 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>
> ---
>  monitor.c => monitor/misc.c | 0
>  Makefile.target             | 3 ++-
>  monitor/Makefile.objs       | 1 +

This patch should probably also create monitor/trace-events
and move those events with it.

Dave

>  3 files changed, 3 insertions(+), 1 deletion(-)
>  rename monitor.c => monitor/misc.c (100%)
>  create mode 100644 monitor/Makefile.objs
> 
> diff --git a/monitor.c b/monitor/misc.c
> similarity index 100%
> rename from monitor.c
> rename to monitor/misc.c
> 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
> -- 
> 2.20.1
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (10 preceding siblings ...)
  2019-06-07 14:03 ` [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Daniel P. Berrangé
@ 2019-06-07 16:48 ` no-reply
  2019-06-07 20:42 ` no-reply
  12 siblings, 0 replies; 31+ messages in thread
From: no-reply @ 2019-06-07 16:48 UTC (permalink / raw)
  To: kwolf; +Cc: kwolf, dgilbert, qemu-devel, qemu-block, armbru

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



Hi,

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

Subject: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
Message-id: 20190607135430.22149-1-kwolf@redhat.com
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 ===

Switched to a new branch 'test'
dbb0f22 monitor: Split out monitor/core.c
54736ce monitor: Split out monitor/hmp.c
9a88f45 monitor: Split out monitor/qmp.c
d3d699e monitor: Create monitor_int.h with common definitions
febc650 Move monitor.c to monitor/misc.c
8f3621b monitor: Move cmd_table to MonitorHMP
75ae78b monitor: Create MonitorHMP with readline state
6ab73c3 monitor: Make MonitorQMP a child class of Monitor
95f9e11 monitor: Split monitor_init in HMP and QMP function
d319053 monitor: Remove unused password prompting fields

=== OUTPUT BEGIN ===
1/10 Checking commit d3190532cbbb (monitor: Remove unused password prompting fields)
2/10 Checking commit 95f9e11f320f (monitor: Split monitor_init in HMP and QMP function)
3/10 Checking commit 6ab73c33845d (monitor: Make MonitorQMP a child class of Monitor)
4/10 Checking commit 75ae78baf77e (monitor: Create MonitorHMP with readline state)
ERROR: braces {} are necessary for all arms of this statement
#192: FILE: monitor.c:1355:
+    if (!hmp_mon->rs)
[...]

total: 1 errors, 0 warnings, 373 lines checked

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

5/10 Checking commit 8f3621b035e3 (monitor: Move cmd_table to MonitorHMP)
6/10 Checking commit febc6502f515 (Move monitor.c to monitor/misc.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#31: 
new file mode 100644

total: 0 errors, 1 warnings, 12 lines checked

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

WARNING: Block comments use a leading /* on a separate line
#233: FILE: monitor/monitor_int.h:79:
+    /* @sub_table is a list of 2nd level of commands. If it does not exist,

total: 0 errors, 2 warnings, 275 lines checked

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

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

total: 1 errors, 1 warnings, 956 lines checked

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

9/10 Checking commit 54736ce87811 (monitor: Split out monitor/hmp.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#39: 
new file mode 100644

ERROR: braces {} are necessary for all arms of this statement
#327: FILE: monitor/hmp.c:284:
+        while (qemu_isspace(*pch))
[...]

ERROR: space required before the open parenthesis '('
#340: FILE: monitor/hmp.c:297:
+    switch(*pch) {

ERROR: braces {} are necessary for all arms of this statement
#363: FILE: monitor/hmp.c:320:
+        if (*pch == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#367: FILE: monitor/hmp.c:324:
+        if (*pch != '\'')
[...]

ERROR: braces {} are necessary for all arms of this statement
#382: FILE: monitor/hmp.c:339:
+                if ((q - buf) < sizeof(buf) - 1)
[...]

ERROR: braces {} are necessary for all arms of this statement
#386: FILE: monitor/hmp.c:343:
+            while (qemu_isspace(*pch))
[...]

ERROR: braces {} are necessary for all arms of this statement
#390: FILE: monitor/hmp.c:347:
+            if (ret < 0)
[...]

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

ERROR: braces {} are necessary for all arms of this statement
#409: FILE: monitor/hmp.c:366:
+        while (qemu_isspace(*pch))
[...]

ERROR: space required before the open parenthesis '('
#422: FILE: monitor/hmp.c:379:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#424: FILE: monitor/hmp.c:381:
+        if (op != '*' && op != '/' && op != '%')
[...]

ERROR: space required before the open parenthesis '('
#428: FILE: monitor/hmp.c:385:
+        switch(op) {

ERROR: braces {} are necessary for all arms of this statement
#435: FILE: monitor/hmp.c:392:
+            if (val2 == 0)
[...]

ERROR: braces {} are necessary for all arms of this statement
#437: FILE: monitor/hmp.c:394:
+            if (op == '/')
[...]
+            else
[...]

ERROR: space required before the open parenthesis '('
#453: FILE: monitor/hmp.c:410:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#455: FILE: monitor/hmp.c:412:
+        if (op != '&' && op != '|' && op != '^')
[...]

ERROR: space required before the open parenthesis '('
#459: FILE: monitor/hmp.c:416:
+        switch(op) {

ERROR: space required before the open parenthesis '('
#481: FILE: monitor/hmp.c:438:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#483: FILE: monitor/hmp.c:440:
+        if (op != '+' && op != '-')
[...]

ERROR: braces {} are necessary for all arms of this statement
#487: FILE: monitor/hmp.c:444:
+        if (op == '+')
[...]
+        else
[...]

ERROR: braces {} are necessary for all arms of this statement
#502: FILE: monitor/hmp.c:459:
+    while (qemu_isspace(*pch))
[...]

ERROR: braces {} are necessary for all arms of this statement
#541: FILE: monitor/hmp.c:498:
+    while (qemu_isspace(*p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#543: FILE: monitor/hmp.c:500:
+    if (*p == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#546: FILE: monitor/hmp.c:503:
+    while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#549: FILE: monitor/hmp.c:506:
+    if (len > nlen - 1)
[...]

ERROR: braces {} are necessary for all arms of this statement
#565: FILE: monitor/hmp.c:522:
+    if (*type == ',')
[...]

ERROR: space required before the open parenthesis '('
#684: FILE: monitor/hmp.c:641:
+    for(;;) {

ERROR: space required before the open parenthesis '('
#691: FILE: monitor/hmp.c:648:
+        switch(c) {

ERROR: braces {} are necessary for all arms of this statement
#698: FILE: monitor/hmp.c:655:
+                while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#709: FILE: monitor/hmp.c:666:
+                    switch(c) {

ERROR: braces {} are necessary for all arms of this statement
#757: FILE: monitor/hmp.c:714:
+                while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#772: FILE: monitor/hmp.c:729:
+                    for(;;) {

ERROR: space required before the open parenthesis '('
#773: FILE: monitor/hmp.c:730:
+                        switch(*p) {

ERROR: braces {} are necessary for all arms of this statement
#840: FILE: monitor/hmp.c:797:
+                while (qemu_isspace(*p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#861: FILE: monitor/hmp.c:818:
+                if (get_expr(mon, &val, &p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#965: FILE: monitor/hmp.c:922:
+                if (c == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#967: FILE: monitor/hmp.c:924:
+                while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#971: FILE: monitor/hmp.c:928:
+                    if(c != *p) {

ERROR: space required before the open parenthesis '('
#972: FILE: monitor/hmp.c:929:
+                        if(!is_valid_option(p, typestr)) {

ERROR: space required before the open parenthesis '('
#980: FILE: monitor/hmp.c:937:
+                    if(skip_key) {

ERROR: braces {} are necessary for all arms of this statement
#1024: FILE: monitor/hmp.c:981:
+    while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#1074: FILE: monitor/hmp.c:1031:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#1078: FILE: monitor/hmp.c:1035:
+        if (len > sizeof(cmd) - 2)
[...]

ERROR: braces {} are necessary for all arms of this statement
#1085: FILE: monitor/hmp.c:1042:
+        if (*p == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#1108: FILE: monitor/hmp.c:1065:
+        if (input_path_len > sizeof(path) - 1)
[...]

ERROR: braces {} are necessary for all arms of this statement
#1115: FILE: monitor/hmp.c:1072:
+    if (!ffs)
[...]

ERROR: space required before the open parenthesis '('
#1117: FILE: monitor/hmp.c:1074:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#1120: FILE: monitor/hmp.c:1077:
+        if (!d)
[...]

WARNING: Block comments use a leading /* on a separate line
#1132: FILE: monitor/hmp.c:1089:
+            /* stat the file to find out if it's a directory.

ERROR: braces {} are necessary for all arms of this statement
#1163: FILE: monitor/hmp.c:1120:
+        if (nb_args == 0)
[...]
+        else
[...]

ERROR: space required before the open parenthesis '('
#1199: FILE: monitor/hmp.c:1156:
+        for(i = 0; i < nb_args - 2; i++) {

ERROR: braces {} are necessary for all arms of this statement
#1202: FILE: monitor/hmp.c:1159:
+                while (*ptype == '?')
[...]

ERROR: space required before the open parenthesis '('
#1212: FILE: monitor/hmp.c:1169:
+        switch(*ptype) {

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

WARNING: Block comments use * on subsequent lines
#1255: FILE: monitor/hmp.c:1212:
+    /* if the line ends with a space, it means we want to complete the
+       next arg */

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

WARNING: Block comments use a leading /* on a separate line
#1348: FILE: monitor/hmp.c:1305:
+/* These functions just adapt the readline interface in a typesafe way.  We

ERROR: space required before the open parenthesis '('
#2850: FILE: monitor/monitor_int.h:166:
+    for(;;) {

total: 53 errors, 6 warnings, 2828 lines checked

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

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

ERROR: braces {} are necessary for all arms of this statement
#214: FILE: monitor/core.c:166:
+    if (!mon)
[...]

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

total: 1 errors, 2 warnings, 1242 lines checked

Patch 10/10 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/20190607135430.22149-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] 31+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions Kevin Wolf
@ 2019-06-07 16:52   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 16:52 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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 | 147 ++++++++++++++++++++++++++++++++++++++++++
>  monitor/misc.c        | 110 +------------------------------
>  2 files changed, 148 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..ab87013b6f
> --- /dev/null
> +++ b/monitor/monitor_int.h
> @@ -0,0 +1,147 @@
> +/*
> + * 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 d964dd1969..6ae7561105 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;
>  
> -- 
> 2.20.1
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c Kevin Wolf
@ 2019-06-07 16:59   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 16:59 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> 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 +
>  6 files changed, 445 insertions(+), 386 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 ab87013b6f..487618392f 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:
> @@ -144,4 +145,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 6ae7561105..6c67f0978c 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.
> @@ -2251,7 +2172,7 @@ static void monitor_fdset_cleanup(MonFdset *mon_fdset)
>      }
>  }
>  
> -static void monitor_fdsets_cleanup(void)
> +void monitor_fdsets_cleanup(void)
>  {
>      MonFdset *mon_fdset;
>      MonFdset *mon_fdset_next;
> @@ -4029,209 +3950,13 @@ cleanup:
>      free_cmdline_args(args, nb_args);
>  }
>  
> -static int monitor_can_read(void *opaque)
> +int monitor_can_read(void *opaque)
>  {
>      Monitor *mon = opaque;
>  
>      return !atomic_mb_read(&mon->suspend_cnt);
>  }
>  
> -/*
> - * Emit QMP response @rsp with ID @id to @mon.
> - * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP.
> - * Nothing is emitted then.
> - */
> -static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp)
> -{
> -    if (rsp) {
> -        qmp_send_response(mon, rsp);
> -    }
> -}
> -
> -static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req)
> -{
> -    Monitor *old_mon;
> -    QDict *rsp;
> -    QDict *error;
> -
> -    old_mon = cur_mon;
> -    cur_mon = &mon->common;
> -
> -    rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon));
> -
> -    cur_mon = old_mon;
> -
> -    if (mon->commands == &qmp_cap_negotiation_commands) {
> -        error = qdict_get_qdict(rsp, "error");
> -        if (error
> -            && !g_strcmp0(qdict_get_try_str(error, "class"),
> -                    QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
> -            /* Provide a more useful error message */
> -            qdict_del(error, "desc");
> -            qdict_put_str(error, "desc", "Expecting capabilities negotiation"
> -                          " with 'qmp_capabilities'");
> -        }
> -    }
> -
> -    monitor_qmp_respond(mon, rsp);
> -    qobject_unref(rsp);
> -}
> -
> -/*
> - * Pop a QMP request from a monitor request queue.
> - * Return the request, or NULL all request queues are empty.
> - * We are using round-robin fashion to pop the request, to avoid
> - * processing commands only on a very busy monitor.  To achieve that,
> - * when we process one request on a specific monitor, we put that
> - * monitor to the end of mon_list queue.
> - *
> - * Note: if the function returned with non-NULL, then the caller will
> - * be with qmp_mon->qmp_queue_lock held, and the caller is responsible
> - * to release it.
> - */
> -static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
> -{
> -    QMPRequest *req_obj = NULL;
> -    Monitor *mon;
> -    MonitorQMP *qmp_mon;
> -
> -    qemu_mutex_lock(&monitor_lock);
> -
> -    QTAILQ_FOREACH(mon, &mon_list, entry) {
> -        if (!monitor_is_qmp(mon)) {
> -            continue;
> -        }
> -
> -        qmp_mon = container_of(mon, MonitorQMP, common);
> -        qemu_mutex_lock(&qmp_mon->qmp_queue_lock);
> -        req_obj = g_queue_pop_head(qmp_mon->qmp_requests);
> -        if (req_obj) {
> -            /* With the lock of corresponding queue held */
> -            break;
> -        }
> -        qemu_mutex_unlock(&qmp_mon->qmp_queue_lock);
> -    }
> -
> -    if (req_obj) {
> -        /*
> -         * We found one request on the monitor. Degrade this monitor's
> -         * priority to lowest by re-inserting it to end of queue.
> -         */
> -        QTAILQ_REMOVE(&mon_list, mon, entry);
> -        QTAILQ_INSERT_TAIL(&mon_list, mon, entry);
> -    }
> -
> -    qemu_mutex_unlock(&monitor_lock);
> -
> -    return req_obj;
> -}
> -
> -static void monitor_qmp_bh_dispatcher(void *data)
> -{
> -    QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
> -    QDict *rsp;
> -    bool need_resume;
> -    MonitorQMP *mon;
> -
> -    if (!req_obj) {
> -        return;
> -    }
> -
> -    mon = req_obj->mon;
> -    /*  qmp_oob_enabled() might change after "qmp_capabilities" */
> -    need_resume = !qmp_oob_enabled(mon) ||
> -        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
> -    qemu_mutex_unlock(&mon->qmp_queue_lock);
> -    if (req_obj->req) {
> -        QDict *qdict = qobject_to(QDict, req_obj->req);
> -        QObject *id = qdict ? qdict_get(qdict, "id") : NULL;
> -        trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: "");
> -        monitor_qmp_dispatch(mon, req_obj->req);
> -    } else {
> -        assert(req_obj->err);
> -        rsp = qmp_error_response(req_obj->err);
> -        req_obj->err = NULL;
> -        monitor_qmp_respond(mon, rsp);
> -        qobject_unref(rsp);
> -    }
> -
> -    if (need_resume) {
> -        /* Pairs with the monitor_suspend() in handle_qmp_command() */
> -        monitor_resume(&mon->common);
> -    }
> -    qmp_request_free(req_obj);
> -
> -    /* Reschedule instead of looping so the main loop stays responsive */
> -    qemu_bh_schedule(qmp_dispatcher_bh);
> -}
> -
> -static void handle_qmp_command(void *opaque, QObject *req, Error *err)
> -{
> -    MonitorQMP *mon = opaque;
> -    QObject *id = NULL;
> -    QDict *qdict;
> -    QMPRequest *req_obj;
> -
> -    assert(!req != !err);
> -
> -    qdict = qobject_to(QDict, req);
> -    if (qdict) {
> -        id = qdict_get(qdict, "id");
> -    } /* else will fail qmp_dispatch() */
> -
> -    if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
> -        QString *req_json = qobject_to_json(req);
> -        trace_handle_qmp_command(mon, qstring_get_str(req_json));
> -        qobject_unref(req_json);
> -    }
> -
> -    if (qdict && qmp_is_oob(qdict)) {
> -        /* OOB commands are executed immediately */
> -        trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: "");
> -        monitor_qmp_dispatch(mon, req);
> -        qobject_unref(req);
> -        return;
> -    }
> -
> -    req_obj = g_new0(QMPRequest, 1);
> -    req_obj->mon = mon;
> -    req_obj->req = req;
> -    req_obj->err = err;
> -
> -    /* Protect qmp_requests and fetching its length. */
> -    qemu_mutex_lock(&mon->qmp_queue_lock);
> -
> -    /*
> -     * Suspend the monitor when we can't queue more requests after
> -     * this one.  Dequeuing in monitor_qmp_bh_dispatcher() will resume
> -     * it.  Note that when OOB is disabled, we queue at most one
> -     * command, for backward compatibility.
> -     */
> -    if (!qmp_oob_enabled(mon) ||
> -        mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
> -        monitor_suspend(&mon->common);
> -    }
> -
> -    /*
> -     * Put the request to the end of queue so that requests will be
> -     * handled in time order.  Ownership for req_obj, req,
> -     * etc. will be delivered to the handler side.
> -     */
> -    assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
> -    g_queue_push_tail(mon->qmp_requests, req_obj);
> -    qemu_mutex_unlock(&mon->qmp_queue_lock);
> -
> -    /* Kick the dispatcher routine */
> -    qemu_bh_schedule(qmp_dispatcher_bh);
> -}
> -
> -static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
> -{
> -    MonitorQMP *mon = opaque;
> -
> -    json_message_parser_feed(&mon->parser, (const char *) buf, size);
> -}
> -
>  static void monitor_read(void *opaque, const uint8_t *buf, int size)
>  {
>      MonitorHMP *mon;
> @@ -4318,56 +4043,6 @@ void monitor_resume(Monitor *mon)
>      trace_monitor_suspend(mon, -1);
>  }
>  
> -static QDict *qmp_greeting(MonitorQMP *mon)
> -{
> -    QList *cap_list = qlist_new();
> -    QObject *ver = NULL;
> -    QMPCapability cap;
> -
> -    qmp_marshal_query_version(NULL, &ver, NULL);
> -
> -    for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) {
> -        if (mon->capab_offered[cap]) {
> -            qlist_append_str(cap_list, QMPCapability_str(cap));
> -        }
> -    }
> -
> -    return qdict_from_jsonf_nofail(
> -        "{'QMP': {'version': %p, 'capabilities': %p}}",
> -        ver, cap_list);
> -}
> -
> -static void monitor_qmp_event(void *opaque, int event)
> -{
> -    QDict *data;
> -    MonitorQMP *mon = opaque;
> -
> -    switch (event) {
> -    case CHR_EVENT_OPENED:
> -        mon->commands = &qmp_cap_negotiation_commands;
> -        monitor_qmp_caps_reset(mon);
> -        data = qmp_greeting(mon);
> -        qmp_send_response(mon, data);
> -        qobject_unref(data);
> -        mon_refcount++;
> -        break;
> -    case CHR_EVENT_CLOSED:
> -        /*
> -         * Note: this is only useful when the output of the chardev
> -         * backend is still open.  For example, when the backend is
> -         * stdio, it's possible that stdout is still open when stdin
> -         * is closed.
> -         */
> -        monitor_qmp_cleanup_queues(mon);
> -        json_message_parser_destroy(&mon->parser);
> -        json_message_parser_init(&mon->parser, handle_qmp_command,
> -                                 mon, NULL);
> -        mon_refcount--;
> -        monitor_fdsets_cleanup();
> -        break;
> -    }
> -}
> -
>  static void monitor_event(void *opaque, int event)
>  {
>      Monitor *mon = opaque;
> @@ -4503,7 +4178,7 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap)
>      return -1;
>  }
>  
> -static void monitor_list_append(Monitor *mon)
> +void monitor_list_append(Monitor *mon)
>  {
>      qemu_mutex_lock(&monitor_lock);
>      /*
> @@ -4523,57 +4198,6 @@ static void monitor_list_append(Monitor *mon)
>      }
>  }
>  
> -static void monitor_qmp_setup_handlers_bh(void *opaque)
> -{
> -    MonitorQMP *mon = opaque;
> -    GMainContext *context;
> -
> -    assert(mon->common.use_io_thread);
> -    context = iothread_get_g_main_context(mon_iothread);
> -    assert(context);
> -    qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read,
> -                             monitor_qmp_read, monitor_qmp_event,
> -                             NULL, &mon->common, context, true);
> -    monitor_list_append(&mon->common);
> -}
> -
> -static void monitor_init_qmp(Chardev *chr, int flags)
> -{
> -    MonitorQMP *mon = g_malloc0(sizeof(*mon));
> -
> -    /* 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..74e72cf5b8
> --- /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-root.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 c8337fa34b..76c5b525f9 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 e783b0616b..d04d58b583 100644
> --- a/monitor/Makefile.objs
> +++ b/monitor/Makefile.objs
> @@ -1 +1,2 @@
>  obj-y += misc.o
> +common-obj-y += qmp.o
> -- 
> 2.20.1
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c Kevin Wolf
@ 2019-06-07 17:21   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 17:21 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

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

(The target_long change was well hidden!)

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/monitor/monitor.h |    1 +
>  monitor/monitor_int.h     |   31 +
>  monitor/hmp.c             | 1351 +++++++++++++++++++++++++++++++++++++
>  monitor/misc.c            | 1338 +-----------------------------------
>  monitor/Makefile.objs     |    2 +-
>  5 files changed, 1390 insertions(+), 1333 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 487618392f..8c5d95f942 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"
> @@ -153,6 +154,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;
> @@ -161,6 +185,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);
> @@ -172,4 +198,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..2bc464a7fc
> --- /dev/null
> +++ b/monitor/hmp.c
> @@ -0,0 +1,1351 @@
> +/*
> + * 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-root.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 6c67f0978c..408d11e1fe 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"));
> @@ -2510,30 +2256,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();
> @@ -2576,829 +2308,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)
>  {
> @@ -3829,127 +2738,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;
> @@ -3957,28 +2745,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)
>  {
> @@ -4043,58 +2809,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)
>  {
> @@ -4137,25 +2851,6 @@ void monitor_init_globals(void)
>                                     NULL);
>  }
>  
> -/* These functions just adapt the readline interface in a typesafe way.  We
> - * could cast function pointers but that discards compiler checks.
> - */
> -static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
> -                                                       const char *fmt, ...)
> -{
> -    MonitorHMP *mon = opaque;
> -    va_list ap;
> -    va_start(ap, fmt);
> -    monitor_vprintf(&mon->common, fmt, ap);
> -    va_end(ap);
> -}
> -
> -static void monitor_readline_flush(void *opaque)
> -{
> -    MonitorHMP *mon = opaque;
> -    monitor_flush(&mon->common);
> -}
> -
>  /*
>   * Print to current monitor if we have one, else to stderr.
>   */
> @@ -4198,27 +2893,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 d04d58b583..48c73eed51 100644
> --- a/monitor/Makefile.objs
> +++ b/monitor/Makefile.objs
> @@ -1,2 +1,2 @@
>  obj-y += misc.o
> -common-obj-y += qmp.o
> +common-obj-y += qmp.o hmp.o
> -- 
> 2.20.1
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c Kevin Wolf
@ 2019-06-07 17:29   ` Dr. David Alan Gilbert
  2019-06-11  9:22     ` Kevin Wolf
  2019-06-07 17:30   ` Dr. David Alan Gilbert
  1 sibling, 1 reply; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 17:29 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> Move the monitor core infrastructure from monitor/misc.c to
> monitor/core.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>

OK, but can you call it anything other than core.* - I regularly end up
deleting things like that!

Other than that,


Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/monitor/monitor.h |   1 +
>  monitor/monitor_int.h     |   1 +
>  monitor/core.c            | 604 ++++++++++++++++++++++++++++++++++++++
>  monitor/misc.c            | 567 +----------------------------------
>  monitor/Makefile.objs     |   2 +-
>  5 files changed, 608 insertions(+), 567 deletions(-)
>  create mode 100644 monitor/core.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 8c5d95f942..1a7af6a223 100644
> --- a/monitor/monitor_int.h
> +++ b/monitor/monitor_int.h
> @@ -190,6 +190,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/core.c b/monitor/core.c
> new file mode 100644
> index 0000000000..1cea56054b
> --- /dev/null
> +++ b/monitor/core.c
> @@ -0,0 +1,604 @@
> +/*
> + * 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-root.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/monitor/misc.c b/monitor/misc.c
> index 408d11e1fe..1f60f31c95 100644
> --- a/monitor/misc.c
> +++ b/monitor/misc.c
> @@ -117,43 +117,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 +131,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 +164,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)
>  {
> @@ -2738,13 +2333,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)
>  {
> @@ -2755,60 +2343,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)
>  {
> @@ -2828,27 +2362,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);
>  }
>  
>  /*
> @@ -2873,90 +2392,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/Makefile.objs b/monitor/Makefile.objs
> index 48c73eed51..c8dff5e4b5 100644
> --- a/monitor/Makefile.objs
> +++ b/monitor/Makefile.objs
> @@ -1,2 +1,2 @@
>  obj-y += misc.o
> -common-obj-y += qmp.o hmp.o
> +common-obj-y += core.o qmp.o hmp.o
> -- 
> 2.20.1
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c
  2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c Kevin Wolf
  2019-06-07 17:29   ` Dr. David Alan Gilbert
@ 2019-06-07 17:30   ` Dr. David Alan Gilbert
  1 sibling, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-07 17:30 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

Oh, can you also fix up the paths in writing-qmp-commands.txt?

Thanks for this split!

Dave

--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

* Re: [Qemu-devel] [Qemu-block] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 15:35       ` Dr. David Alan Gilbert
@ 2019-06-07 18:11         ` Eric Blake
  0 siblings, 0 replies; 31+ messages in thread
From: Eric Blake @ 2019-06-07 18:11 UTC (permalink / raw)
  To: Dr. David Alan Gilbert, Daniel P. Berrangé
  Cc: Kevin Wolf, qemu-devel, qemu-block, armbru


[-- Attachment #1.1: Type: text/plain, Size: 718 bytes --]

On 6/7/19 10:35 AM, Dr. David Alan Gilbert wrote:

>>> But if people prefer, I can move the existing files in the root
>>> directory to monitor/{qmp,hmp}-cmds.c temporarily in this series and
>>> then work from there with follow-ups until they are empty (or maybe I
>>> don't even have to make them completely empty then).
>>
>> A plain rename like this won't hurt in the meantime.
> 
> Yeh agreed, my brain hurts too much with files of the same name.

Not just that, but in gdb, it's harder to set breakpoints of the form
file.c:line if file.c is not unique to the image.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
  2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
                   ` (11 preceding siblings ...)
  2019-06-07 16:48 ` [Qemu-devel] " no-reply
@ 2019-06-07 20:42 ` no-reply
  12 siblings, 0 replies; 31+ messages in thread
From: no-reply @ 2019-06-07 20:42 UTC (permalink / raw)
  To: kwolf; +Cc: kwolf, dgilbert, qemu-devel, qemu-block, armbru

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



Hi,

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

Type: series
Subject: [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc
Message-id: 20190607135430.22149-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 ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/20190607184802.100945-1-vsementsov@virtuozzo.com -> patchew/20190607184802.100945-1-vsementsov@virtuozzo.com
Switched to a new branch 'test'
393e03b monitor: Split out monitor/core.c
6938636 monitor: Split out monitor/hmp.c
b33f363 monitor: Split out monitor/qmp.c
4e784bf monitor: Create monitor_int.h with common definitions
ec11ead Move monitor.c to monitor/misc.c
00365cc monitor: Move cmd_table to MonitorHMP
05c3aa3 monitor: Create MonitorHMP with readline state
5435f06 monitor: Make MonitorQMP a child class of Monitor
a541d49 monitor: Split monitor_init in HMP and QMP function
d1dcf9d monitor: Remove unused password prompting fields

=== OUTPUT BEGIN ===
1/10 Checking commit d1dcf9d89219 (monitor: Remove unused password prompting fields)
2/10 Checking commit a541d49ece87 (monitor: Split monitor_init in HMP and QMP function)
3/10 Checking commit 5435f06ca5bf (monitor: Make MonitorQMP a child class of Monitor)
4/10 Checking commit 05c3aa3627dd (monitor: Create MonitorHMP with readline state)
ERROR: braces {} are necessary for all arms of this statement
#192: FILE: monitor.c:1355:
+    if (!hmp_mon->rs)
[...]

total: 1 errors, 0 warnings, 373 lines checked

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

5/10 Checking commit 00365cc53224 (monitor: Move cmd_table to MonitorHMP)
6/10 Checking commit ec11ead0d0aa (Move monitor.c to monitor/misc.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#31: 
new file mode 100644

total: 0 errors, 1 warnings, 12 lines checked

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

WARNING: Block comments use a leading /* on a separate line
#233: FILE: monitor/monitor_int.h:79:
+    /* @sub_table is a list of 2nd level of commands. If it does not exist,

total: 0 errors, 2 warnings, 275 lines checked

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

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

total: 1 errors, 1 warnings, 956 lines checked

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

9/10 Checking commit 693863658d05 (monitor: Split out monitor/hmp.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#39: 
new file mode 100644

ERROR: braces {} are necessary for all arms of this statement
#327: FILE: monitor/hmp.c:284:
+        while (qemu_isspace(*pch))
[...]

ERROR: space required before the open parenthesis '('
#340: FILE: monitor/hmp.c:297:
+    switch(*pch) {

ERROR: braces {} are necessary for all arms of this statement
#363: FILE: monitor/hmp.c:320:
+        if (*pch == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#367: FILE: monitor/hmp.c:324:
+        if (*pch != '\'')
[...]

ERROR: braces {} are necessary for all arms of this statement
#382: FILE: monitor/hmp.c:339:
+                if ((q - buf) < sizeof(buf) - 1)
[...]

ERROR: braces {} are necessary for all arms of this statement
#386: FILE: monitor/hmp.c:343:
+            while (qemu_isspace(*pch))
[...]

ERROR: braces {} are necessary for all arms of this statement
#390: FILE: monitor/hmp.c:347:
+            if (ret < 0)
[...]

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

ERROR: braces {} are necessary for all arms of this statement
#409: FILE: monitor/hmp.c:366:
+        while (qemu_isspace(*pch))
[...]

ERROR: space required before the open parenthesis '('
#422: FILE: monitor/hmp.c:379:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#424: FILE: monitor/hmp.c:381:
+        if (op != '*' && op != '/' && op != '%')
[...]

ERROR: space required before the open parenthesis '('
#428: FILE: monitor/hmp.c:385:
+        switch(op) {

ERROR: braces {} are necessary for all arms of this statement
#435: FILE: monitor/hmp.c:392:
+            if (val2 == 0)
[...]

ERROR: braces {} are necessary for all arms of this statement
#437: FILE: monitor/hmp.c:394:
+            if (op == '/')
[...]
+            else
[...]

ERROR: space required before the open parenthesis '('
#453: FILE: monitor/hmp.c:410:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#455: FILE: monitor/hmp.c:412:
+        if (op != '&' && op != '|' && op != '^')
[...]

ERROR: space required before the open parenthesis '('
#459: FILE: monitor/hmp.c:416:
+        switch(op) {

ERROR: space required before the open parenthesis '('
#481: FILE: monitor/hmp.c:438:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#483: FILE: monitor/hmp.c:440:
+        if (op != '+' && op != '-')
[...]

ERROR: braces {} are necessary for all arms of this statement
#487: FILE: monitor/hmp.c:444:
+        if (op == '+')
[...]
+        else
[...]

ERROR: braces {} are necessary for all arms of this statement
#502: FILE: monitor/hmp.c:459:
+    while (qemu_isspace(*pch))
[...]

ERROR: braces {} are necessary for all arms of this statement
#541: FILE: monitor/hmp.c:498:
+    while (qemu_isspace(*p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#543: FILE: monitor/hmp.c:500:
+    if (*p == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#546: FILE: monitor/hmp.c:503:
+    while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#549: FILE: monitor/hmp.c:506:
+    if (len > nlen - 1)
[...]

ERROR: braces {} are necessary for all arms of this statement
#565: FILE: monitor/hmp.c:522:
+    if (*type == ',')
[...]

ERROR: space required before the open parenthesis '('
#684: FILE: monitor/hmp.c:641:
+    for(;;) {

ERROR: space required before the open parenthesis '('
#691: FILE: monitor/hmp.c:648:
+        switch(c) {

ERROR: braces {} are necessary for all arms of this statement
#698: FILE: monitor/hmp.c:655:
+                while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#709: FILE: monitor/hmp.c:666:
+                    switch(c) {

ERROR: braces {} are necessary for all arms of this statement
#757: FILE: monitor/hmp.c:714:
+                while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#772: FILE: monitor/hmp.c:729:
+                    for(;;) {

ERROR: space required before the open parenthesis '('
#773: FILE: monitor/hmp.c:730:
+                        switch(*p) {

ERROR: braces {} are necessary for all arms of this statement
#840: FILE: monitor/hmp.c:797:
+                while (qemu_isspace(*p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#861: FILE: monitor/hmp.c:818:
+                if (get_expr(mon, &val, &p))
[...]

ERROR: braces {} are necessary for all arms of this statement
#965: FILE: monitor/hmp.c:922:
+                if (c == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#967: FILE: monitor/hmp.c:924:
+                while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#971: FILE: monitor/hmp.c:928:
+                    if(c != *p) {

ERROR: space required before the open parenthesis '('
#972: FILE: monitor/hmp.c:929:
+                        if(!is_valid_option(p, typestr)) {

ERROR: space required before the open parenthesis '('
#980: FILE: monitor/hmp.c:937:
+                    if(skip_key) {

ERROR: braces {} are necessary for all arms of this statement
#1024: FILE: monitor/hmp.c:981:
+    while (qemu_isspace(*p))
[...]

ERROR: space required before the open parenthesis '('
#1074: FILE: monitor/hmp.c:1031:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#1078: FILE: monitor/hmp.c:1035:
+        if (len > sizeof(cmd) - 2)
[...]

ERROR: braces {} are necessary for all arms of this statement
#1085: FILE: monitor/hmp.c:1042:
+        if (*p == '\0')
[...]

ERROR: braces {} are necessary for all arms of this statement
#1108: FILE: monitor/hmp.c:1065:
+        if (input_path_len > sizeof(path) - 1)
[...]

ERROR: braces {} are necessary for all arms of this statement
#1115: FILE: monitor/hmp.c:1072:
+    if (!ffs)
[...]

ERROR: space required before the open parenthesis '('
#1117: FILE: monitor/hmp.c:1074:
+    for(;;) {

ERROR: braces {} are necessary for all arms of this statement
#1120: FILE: monitor/hmp.c:1077:
+        if (!d)
[...]

WARNING: Block comments use a leading /* on a separate line
#1132: FILE: monitor/hmp.c:1089:
+            /* stat the file to find out if it's a directory.

ERROR: braces {} are necessary for all arms of this statement
#1163: FILE: monitor/hmp.c:1120:
+        if (nb_args == 0)
[...]
+        else
[...]

ERROR: space required before the open parenthesis '('
#1199: FILE: monitor/hmp.c:1156:
+        for(i = 0; i < nb_args - 2; i++) {

ERROR: braces {} are necessary for all arms of this statement
#1202: FILE: monitor/hmp.c:1159:
+                while (*ptype == '?')
[...]

ERROR: space required before the open parenthesis '('
#1212: FILE: monitor/hmp.c:1169:
+        switch(*ptype) {

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

WARNING: Block comments use * on subsequent lines
#1255: FILE: monitor/hmp.c:1212:
+    /* if the line ends with a space, it means we want to complete the
+       next arg */

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

WARNING: Block comments use a leading /* on a separate line
#1348: FILE: monitor/hmp.c:1305:
+/* These functions just adapt the readline interface in a typesafe way.  We

ERROR: space required before the open parenthesis '('
#2850: FILE: monitor/monitor_int.h:166:
+    for(;;) {

total: 53 errors, 6 warnings, 2828 lines checked

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

10/10 Checking commit 393e03bb4f4e (monitor: Split out monitor/core.c)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#44: 
new file mode 100644

ERROR: braces {} are necessary for all arms of this statement
#214: FILE: monitor/core.c:166:
+    if (!mon)
[...]

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

total: 1 errors, 2 warnings, 1242 lines checked

Patch 10/10 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/20190607135430.22149-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] 31+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c
  2019-06-07 17:29   ` Dr. David Alan Gilbert
@ 2019-06-11  9:22     ` Kevin Wolf
  2019-06-11  9:25       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Wolf @ 2019-06-11  9:22 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: qemu-devel, qemu-block, armbru

Am 07.06.2019 um 19:29 hat Dr. David Alan Gilbert geschrieben:
> * Kevin Wolf (kwolf@redhat.com) wrote:
> > Move the monitor core infrastructure from monitor/misc.c to
> > monitor/core.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>
> 
> OK, but can you call it anything other than core.* - I regularly end up
> deleting things like that!

Oh, I didn't even think of this kind of core.*!

I imagine in practice it wouldn't be so bad to have a monitor/core.c
because it's in a subdirectory, and it's under version control anyway.
We already seem to have quite a few of them in subdirectories:

    ./hw/acpi/core.c
    ./hw/bt/core.c
    ./hw/cpu/core.c
    ./hw/i2c/core.c
    ./hw/ide/core.c
    ./hw/sd/core.c
    ./hw/usb/core.c

But I'll gladly rename it if I can find a good name. Do you have any
suggestions? Maybe just monitor/monitor.c?

Kevin


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

* Re: [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c
  2019-06-11  9:22     ` Kevin Wolf
@ 2019-06-11  9:25       ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 31+ messages in thread
From: Dr. David Alan Gilbert @ 2019-06-11  9:25 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru

* Kevin Wolf (kwolf@redhat.com) wrote:
> Am 07.06.2019 um 19:29 hat Dr. David Alan Gilbert geschrieben:
> > * Kevin Wolf (kwolf@redhat.com) wrote:
> > > Move the monitor core infrastructure from monitor/misc.c to
> > > monitor/core.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>
> > 
> > OK, but can you call it anything other than core.* - I regularly end up
> > deleting things like that!
> 
> Oh, I didn't even think of this kind of core.*!
> 
> I imagine in practice it wouldn't be so bad to have a monitor/core.c
> because it's in a subdirectory, and it's under version control anyway.
> We already seem to have quite a few of them in subdirectories:
> 
>     ./hw/acpi/core.c
>     ./hw/bt/core.c
>     ./hw/cpu/core.c
>     ./hw/i2c/core.c
>     ./hw/ide/core.c
>     ./hw/sd/core.c
>     ./hw/usb/core.c

Yes, they all annoy me in the same way :-)

> But I'll gladly rename it if I can find a good name. Do you have any
> suggestions? Maybe just monitor/monitor.c?

Yes that's fine, thanks!

Dave

> Kevin
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK


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

end of thread, other threads:[~2019-06-11  9:27 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-07 13:54 [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Kevin Wolf
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 01/10] monitor: Remove unused password prompting fields Kevin Wolf
2019-06-07 15:39   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 02/10] monitor: Split monitor_init in HMP and QMP function Kevin Wolf
2019-06-07 15:46   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 03/10] monitor: Make MonitorQMP a child class of Monitor Kevin Wolf
2019-06-07 16:17   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 04/10] monitor: Create MonitorHMP with readline state Kevin Wolf
2019-06-07 16:32   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 05/10] monitor: Move cmd_table to MonitorHMP Kevin Wolf
2019-06-07 16:35   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 06/10] Move monitor.c to monitor/misc.c Kevin Wolf
2019-06-07 16:39   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 07/10] monitor: Create monitor_int.h with common definitions Kevin Wolf
2019-06-07 16:52   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 08/10] monitor: Split out monitor/qmp.c Kevin Wolf
2019-06-07 16:59   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 09/10] monitor: Split out monitor/hmp.c Kevin Wolf
2019-06-07 17:21   ` Dr. David Alan Gilbert
2019-06-07 13:54 ` [Qemu-devel] [RFC PATCH 10/10] monitor: Split out monitor/core.c Kevin Wolf
2019-06-07 17:29   ` Dr. David Alan Gilbert
2019-06-11  9:22     ` Kevin Wolf
2019-06-11  9:25       ` Dr. David Alan Gilbert
2019-06-07 17:30   ` Dr. David Alan Gilbert
2019-06-07 14:03 ` [Qemu-devel] [RFC PATCH 00/10] monitor: Split monitor.c in core/HMP/QMP/misc Daniel P. Berrangé
2019-06-07 14:25   ` Kevin Wolf
2019-06-07 14:31     ` Daniel P. Berrangé
2019-06-07 15:35       ` Dr. David Alan Gilbert
2019-06-07 18:11         ` [Qemu-devel] [Qemu-block] " Eric Blake
2019-06-07 16:48 ` [Qemu-devel] " no-reply
2019-06-07 20:42 ` no-reply

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).