All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
@ 2018-03-26 15:08 Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 01/38] HACK: add back OOB Marc-André Lureau
                   ` (43 more replies)
  0 siblings, 44 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Hi,

One of initial design goals of QMP was to have "asynchronous command
completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
goal was not fully achieved, and some broken bits left were removed
progressively until commit 65207c59d that removed async command
support.

Yet there are clear benefits allowing the command handler to re-enter
the main loop if the command cannot be handled synchronously, or if it
is long-lasting. This is currently not possible and make some bugs
such as rhbz#1230527 difficult to solve.  Furthermore, many QMP
commands do IO and could be considered 'slow' and blocking the main
loop today. The unwritten solution so far is to use a pair of
command+event. But this approach has a number of issues, in particular
to fix existing commands, and inadequacy since the event is
broadcasted and may thus have command 'id' conflict, beside being
rather inefficient and incorrect.

The following series implements an async command solution instead. By
introducing a session context and a command return handler, it can:
- defer the return, allowing the mainloop to reenter
- return only to the caller (no broadcasted event)
- optionnally allow cancellation when the client is gone
- track on-going qapi command(s) per client/session

Existing qemu commands can be gradually replaced by async:true
variants when needed, and by carefully reviewing the concurrency
aspects. The async:true commands marshaller helpers are splitted in
half, the calling and return functions. The command is called with a
QmpReturn context, that can return immediately or later, using the
generated return helper, which allows for step-by-step conversion.

The screendump command is converted to an async:true version to solve
rhbz#1230527. The command shows basic cancellation (this could be
extended if needed). It could be further improved to do asynchronous
IO write as well.

v3:
- complete rework, dropping the asynchronous commands visibility from
  the protocol side entirely (until there is a real need for it)
- rebased, with a few preliminary cleanup patches
- teach asynchronous commands to HMP

v2:
- documentation fixes and improvements
- fix calling async commands sync without id
- fix bad hmp monitor assert
- add a few extra asserts
- add async with no-id failure and screendump test

Marc-André Lureau (38):
  HACK: add back OOB
  qmp-shell: learn to send commands with quoted arguments
  Revert "qmp: isolate responses into io thread"
  monitor: no need to save need_resume
  monitor: further simplify previous patch
  monitor: no need to remove desc before replacing it
  json-parser: always set an error if return NULL
  json-lexer: make it safe to call multiple times
  json: remove useless return value from lexer/parser
  tests: add a few qemu-qmp tests
  tests: change /0.15/* tests to /qmp/*
  tests: add a qmp success-response test
  qga: process_event() simplification
  monitor: simplify monitor_qmp_respond()
  qmp: pass and return a QDict to qmp_dispatch()
  qmp: move 'id' copy to qmp_dispatch()
  qmp: constify qmp_is_oob()
  qmp: add QmpSession
  QmpSession: add a return_cb
  QmpSession: add json parser and use it in qga
  QmpSession: add a dispatch callback
  monitor: use QmpSession parsing and common dispatch code
  QmpSession: introduce QmpReturn
  qmp: remove qmp_build_error_object()
  qmp: remove need for qobject_from_jsonf()
  qmp: fold do_qmp_dispatch() in qmp_dispatch()
  QmpSession: keep a queue of pending commands
  QmpSession: return orderly
  qmp: introduce asynchronous command type
  scripts: learn 'async' qapi commands
  qmp: add qmp_return_is_cancelled()
  monitor: add qmp_return_get_monitor()
  console: graphic_hw_update return true if async
  console: add graphic_hw_update_done()
  console: make screendump asynchronous
  monitor: start making qmp_human_monitor_command() asynchronous
  monitor: teach HMP about asynchronous commands
  hmp: call the asynchronous QMP screendump to fix outdated/glitches

 qapi/misc.json                          |   3 +-
 qapi/ui.json                            |   3 +-
 scripts/qapi/commands.py                | 149 +++++++--
 scripts/qapi/common.py                  |  12 +-
 scripts/qapi/doc.py                     |   2 +-
 scripts/qapi/introspect.py              |   2 +-
 hmp.h                                   |   3 +-
 hw/display/qxl.h                        |   2 +-
 include/monitor/monitor.h               |   3 +
 include/qapi/qmp/dispatch.h             |  85 ++++-
 include/qapi/qmp/json-lexer.h           |   4 +-
 include/qapi/qmp/json-streamer.h        |   4 +-
 include/ui/console.h                    |   7 +-
 hmp.c                                   |   6 +-
 hw/display/qxl-render.c                 |  14 +-
 hw/display/qxl.c                        |   8 +-
 migration/postcopy-ram.c                |   1 +
 monitor.c                               | 393 +++++++++---------------
 qapi/qmp-dispatch.c                     | 234 +++++++++++---
 qapi/qmp-registry.c                     |  27 +-
 qga/main.c                              |  73 +----
 qobject/json-lexer.c                    |  28 +-
 qobject/json-parser.c                   |   7 +-
 qobject/json-streamer.c                 |   8 +-
 tests/qmp-test.c                        | 146 ++++++++-
 tests/test-qmp-cmds.c                   | 206 +++++++++++--
 ui/console.c                            | 106 ++++++-
 hmp-commands.hx                         |   3 +-
 scripts/qmp/qmp-shell                   |   3 +-
 tests/Makefile.include                  |   6 +-
 tests/qapi-schema/qapi-schema-test.json |   7 +
 tests/qapi-schema/qapi-schema-test.out  |  10 +
 tests/qapi-schema/test-qapi.py          |   7 +-
 33 files changed, 1078 insertions(+), 494 deletions(-)
 mode change 100644 => 100755 scripts/qapi/doc.py

-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 01/38] HACK: add back OOB
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments Marc-André Lureau
                   ` (42 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

This adds back temporarily OOB for the sake of automated testing and
for the rest of the patches that are based upon OOB, as well as a few
pending fixes squashed together.

Revert "qapi: Force UTF8 encoding when parsing qapi files"

This reverts commit 39615354fc07af34e04ab5efb5b6d478b0d24e32.

Revert "Revert "monitor: enable IO thread for (qmp & !mux) typed""

This reverts commit a4f90923b520f1dc0a768634877eb412e5052c26.

Revert "Revert "tests: qmp-test: verify command batching""

This reverts commit cc797607c03722871a030f8a64d800a8df93b5b2.

Revert "Revert "tests: qmp-test: add oob test""

This reverts commit 4fd78ad7934bbd002da8ea420ce16f73ad23f417.

monitor: fix expected qmp_capabilities error description regression

Fix regression introduced in commit cf869d53172920536a14180a83292b240e9d0545:

Before:
{"execute":"foo"}
{"error": {"class": "CommandNotFound", "desc": "Expecting capabilities negotiation with 'qmp_capabilities'"}}

After:
{"execute":"foo"}
{"error": {"class": "CommandNotFound", "desc": "The command foo has not been found"}}

Because qmp_cmd_oob_check() happens before
monitor_qmp_dispatch_one(). Move the error manipulation code to
monitor_qmp_respond() instead.

migration: fix pfd leak

Fix leak spotted by ASAN:

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fe1abb80a38 in __interceptor_calloc (/lib64/libasan.so.4+0xdea38)
    #1 0x7fe1aaf1bf75 in g_malloc0 ../glib/gmem.c:124
    #2 0x7fe1aaf1c249 in g_malloc0_n ../glib/gmem.c:355
    #3 0x55f4841cfaa9 in postcopy_ram_fault_thread /home/elmarco/src/qemu/migration/postcopy-ram.c:596
    #4 0x55f48479447b in qemu_thread_start /home/elmarco/src/qemu/util/qemu-thread-posix.c:504
    #5 0x7fe1a043550a in start_thread (/lib64/libpthread.so.0+0x750a)

Regression introduced with commit 00fa4fc85b00f1a8a810068d158a7a66e88658eb.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 migration/postcopy-ram.c |  1 +
 monitor.c                | 30 +++++++------
 tests/qmp-test.c         | 97 +++++++++++++++++++++++++++++++++++++++-
 tests/Makefile.include   |  6 +--
 4 files changed, 116 insertions(+), 18 deletions(-)

diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index efd77939af..4a0b33b373 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -754,6 +754,7 @@ static void *postcopy_ram_fault_thread(void *opaque)
         }
     }
     trace_postcopy_ram_fault_thread_exit();
+    g_free(pfd);
     return NULL;
 }
 
diff --git a/monitor.c b/monitor.c
index 77f4c41cfa..d57bbbb134 100644
--- a/monitor.c
+++ b/monitor.c
@@ -36,6 +36,7 @@
 #include "net/slirp.h"
 #include "chardev/char-fe.h"
 #include "chardev/char-io.h"
+#include "chardev/char-mux.h"
 #include "ui/qemu-spice.h"
 #include "sysemu/numa.h"
 #include "monitor/monitor.h"
@@ -3996,6 +3997,18 @@ static void monitor_qmp_respond(Monitor *mon, QObject *rsp,
             qdict_put_obj(qobject_to(QDict, rsp), "id", id);
         }
 
+        if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
+            qdict = qdict_get_qdict(qobject_to(QDict, rsp), "error");
+            if (qdict
+                && !g_strcmp0(qdict_get_try_str(qdict, "class"),
+                          QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
+                /* Provide a more useful error message */
+                qdict_del(qdict, "desc");
+                qdict_put_str(qdict, "desc", "Expecting capabilities"
+                              " negotiation with 'qmp_capabilities'");
+            }
+        }
+
         monitor_json_emitter(mon, rsp);
     }
 
@@ -4027,7 +4040,6 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 {
     Monitor *mon, *old_mon;
     QObject *req, *rsp = NULL, *id;
-    QDict *qdict = NULL;
     bool need_resume;
 
     req = req_obj->req;
@@ -4050,18 +4062,6 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 
     cur_mon = old_mon;
 
-    if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
-        qdict = qdict_get_qdict(qobject_to(QDict, rsp), "error");
-        if (qdict
-            && !g_strcmp0(qdict_get_try_str(qdict, "class"),
-                    QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
-            /* Provide a more useful error message */
-            qdict_del(qdict, "desc");
-            qdict_put_str(qdict, "desc", "Expecting capabilities negotiation"
-                          " with 'qmp_capabilities'");
-        }
-    }
-
     /* Respond if necessary */
     monitor_qmp_respond(mon, rsp, NULL, id);
 
@@ -4536,8 +4536,10 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
 void monitor_init(Chardev *chr, int flags)
 {
     Monitor *mon = g_malloc(sizeof(*mon));
+    /* Enable IOThread for QMPs that are not using MUX chardev backends. */
+    bool use_io_thr = (!CHARDEV_IS_MUX(chr)) && (flags & MONITOR_USE_CONTROL);
 
-    monitor_data_init(mon, false, false);
+    monitor_data_init(mon, false, use_io_thr);
 
     qemu_chr_fe_init(&mon->chr, chr, &error_abort);
     mon->flags = flags;
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 558e83540c..07c0b87e27 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -80,6 +80,9 @@ static void test_qmp_protocol(void)
     QDict *resp, *q, *ret;
     QList *capabilities;
     QTestState *qts;
+    const QListEntry *entry;
+    QString *qstr;
+    int i;
 
     qts = qtest_init_without_qmp_handshake(common_args);
 
@@ -89,7 +92,13 @@ static void test_qmp_protocol(void)
     g_assert(q);
     test_version(qdict_get(q, "version"));
     capabilities = qdict_get_qlist(q, "capabilities");
-    g_assert(capabilities && qlist_empty(capabilities));
+    g_assert(capabilities);
+    entry = qlist_first(capabilities);
+    g_assert(entry);
+    qstr = qobject_to(QString, entry->value);
+    g_assert(qstr);
+    g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
+    QDECREF(resp);
 
     /* Test valid command before handshake */
     resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
@@ -131,9 +140,94 @@ static void test_qmp_protocol(void)
     g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
     QDECREF(resp);
 
+    /*
+     * Test command batching.  In current test OOB is not enabled, we
+     * should be able to run as many commands in batch as we like.
+     * Using 16 (>8, which is OOB queue length) to make sure OOB won't
+     * break existing clients.  Note: this test does not control the
+     * scheduling of QEMU's QMP command processing threads so it may
+     * not really trigger batching inside QEMU.  This is just a
+     * best-effort test.
+     */
+    for (i = 0; i < 16; i++) {
+        qtest_async_qmp(qts, "{ 'execute': 'query-version' }");
+    }
+    /* Verify the replies to make sure no command is dropped. */
+    for (i = 0; i < 16; i++) {
+        resp = qtest_qmp_receive(qts);
+        /* It should never be dropped.  Each of them should be a reply. */
+        g_assert(qdict_haskey(resp, "return"));
+        g_assert(!qdict_haskey(resp, "event"));
+        QDECREF(resp);
+    }
+
     qtest_quit(qts);
 }
 
+/* Tests for Out-Of-Band support. */
+static void test_qmp_oob(void)
+{
+    QDict *resp;
+    int acks = 0;
+    const char *cmd_id;
+
+    global_qtest = qtest_init_without_qmp_handshake(common_args);
+
+    /* Ignore the greeting message. */
+    resp = qmp_receive();
+    g_assert(qdict_get_qdict(resp, "QMP"));
+    QDECREF(resp);
+
+    /* Try a fake capability, it should fail. */
+    resp = qmp("{ 'execute': 'qmp_capabilities', "
+               "  'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
+    g_assert(qdict_haskey(resp, "error"));
+    QDECREF(resp);
+
+    /* Now, enable OOB in current QMP session, it should succeed. */
+    resp = qmp("{ 'execute': 'qmp_capabilities', "
+               "  'arguments': { 'enable': [ 'oob' ] } }");
+    g_assert(qdict_haskey(resp, "return"));
+    QDECREF(resp);
+
+    /*
+     * Try any command that does not support OOB but with OOB flag. We
+     * should get failure.
+     */
+    resp = qmp("{ 'execute': 'query-cpus',"
+               "  'control': { 'run-oob': true } }");
+    g_assert(qdict_haskey(resp, "error"));
+    QDECREF(resp);
+
+    /*
+     * First send the "x-oob-test" command with lock=true and
+     * oob=false, it should hang the dispatcher and main thread;
+     * later, we send another lock=false with oob=true to continue
+     * that thread processing.  Finally we should receive replies from
+     * both commands.
+     */
+    qmp_async("{ 'execute': 'x-oob-test',"
+              "  'arguments': { 'lock': true }, "
+              "  'id': 'lock-cmd'}");
+    qmp_async("{ 'execute': 'x-oob-test', "
+              "  'arguments': { 'lock': false }, "
+              "  'control': { 'run-oob': true }, "
+              "  'id': 'unlock-cmd' }");
+
+    /* Ignore all events.  Wait for 2 acks */
+    while (acks < 2) {
+        resp = qmp_receive();
+        cmd_id = qdict_get_str(resp, "id");
+        if (!g_strcmp0(cmd_id, "lock-cmd") ||
+            !g_strcmp0(cmd_id, "unlock-cmd")) {
+            acks++;
+        }
+        QDECREF(resp);
+    }
+
+    qtest_end();
+}
+
 static int query_error_class(const char *cmd)
 {
     static struct {
@@ -318,6 +412,7 @@ int main(int argc, char *argv[])
     g_test_init(&argc, &argv, NULL);
 
     qtest_add_func("qmp/protocol", test_qmp_protocol);
+    qtest_add_func("qmp/oob", test_qmp_oob);
     qmp_schema_init(&schema);
     add_query_tests(&schema);
 
diff --git a/tests/Makefile.include b/tests/Makefile.include
index eb218a9539..0b277036df 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -669,13 +669,13 @@ tests/test-qapi-events.c tests/test-qapi-events.h \
 tests/test-qapi-introspect.c tests/test-qapi-introspect.h: \
 tests/test-qapi-gen-timestamp ;
 tests/test-qapi-gen-timestamp: $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(qapi-py)
-	$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
 		-o tests -p "test-" $<, \
 		"GEN","$(@:%-timestamp=%)")
 	@>$@
 
 tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(qapi-py)
-	$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
 		-o tests/qapi-schema -p "doc-good-" $<, \
 		"GEN","$@")
 	@mv tests/qapi-schema/doc-good-qapi-doc.texi $@
@@ -927,7 +927,7 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
 .PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
 $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
 	$(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \
-		$(PYTHON_UTF8) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
+		$(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
 		$^ >$*.test.out 2>$*.test.err; \
 		echo $$? >$*.test.exit, \
 		"TEST","$*.out")
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 01/38] HACK: add back OOB Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 18:26   ` Eduardo Habkost
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 03/38] Revert "qmp: isolate responses into io thread" Marc-André Lureau
                   ` (41 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Use shlex to split the CLI command, respecting quoted arguments, and
also comments. This allows to call for ex:

(QEMU) human-monitor-command command-line="screendump /dev/null"
{"execute": "human-monitor-command", "arguments": {"command-line": "screendump /dev/null"}}

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qmp/qmp-shell | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index be449de621..af7033c765 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -73,6 +73,7 @@ import sys
 import os
 import errno
 import atexit
+import shlex
 
 class QMPCompleter(list):
     def complete(self, text, state):
@@ -218,7 +219,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
 
             < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
         """
-        cmdargs = cmdline.split()
+        cmdargs = shlex.split(cmdline)
 
         # Transactional CLI entry/exit:
         if cmdargs[0] == 'transaction(':
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 03/38] Revert "qmp: isolate responses into io thread"
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 01/38] HACK: add back OOB Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 04/38] monitor: no need to save need_resume Marc-André Lureau
                   ` (40 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

This reverts commit abe3cd0ff7f774966da6842620806ab7576fe4f3.

There is no need to add an additional queue to send the reply to the
IOThread, because QMP response is thread safe, and chardev write path
is thread safe. It will schedule watcher in the associated IOThread.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 96 +------------------------------------------------------
 1 file changed, 1 insertion(+), 95 deletions(-)

diff --git a/monitor.c b/monitor.c
index d57bbbb134..59920ea872 100644
--- a/monitor.c
+++ b/monitor.c
@@ -180,8 +180,6 @@ typedef struct {
     QemuMutex qmp_queue_lock;
     /* Input queue that holds all the parsed QMP requests */
     GQueue *qmp_requests;
-    /* Output queue contains all the QMP responses in order */
-    GQueue *qmp_responses;
 } MonitorQMP;
 
 /*
@@ -208,7 +206,6 @@ struct Monitor {
     bool skip_flush;
     bool use_io_thr;
 
-    /* We can't access guest memory when holding the lock */
     QemuMutex out_lock;
     QString *outbuf;
     guint out_watch;
@@ -231,8 +228,6 @@ static struct {
     IOThread *mon_iothread;
     /* Bottom half to dispatch the requests received from IO thread */
     QEMUBH *qmp_dispatcher_bh;
-    /* Bottom half to deliver the responses back to clients */
-    QEMUBH *qmp_respond_bh;
 } mon_global;
 
 /* QMP checker flags */
@@ -422,8 +417,7 @@ int monitor_fprintf(FILE *stream, const char *fmt, ...)
     return 0;
 }
 
-static void monitor_json_emitter_raw(Monitor *mon,
-                                     QObject *data)
+static void monitor_json_emitter(Monitor *mon, const QObject *data)
 {
     QString *json;
 
@@ -437,71 +431,6 @@ static void monitor_json_emitter_raw(Monitor *mon,
     QDECREF(json);
 }
 
-static void monitor_json_emitter(Monitor *mon, QObject *data)
-{
-    if (mon->use_io_thr) {
-        /*
-         * If using IO thread, we need to queue the item so that IO
-         * thread will do the rest for us.  Take refcount so that
-         * caller won't free the data (which will be finally freed in
-         * responder thread).
-         */
-        qobject_incref(data);
-        qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
-        g_queue_push_tail(mon->qmp.qmp_responses, (void *)data);
-        qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
-        qemu_bh_schedule(mon_global.qmp_respond_bh);
-    } else {
-        /*
-         * If not using monitor IO thread, then we are in main thread.
-         * Do the emission right away.
-         */
-        monitor_json_emitter_raw(mon, data);
-    }
-}
-
-struct QMPResponse {
-    Monitor *mon;
-    QObject *data;
-};
-typedef struct QMPResponse QMPResponse;
-
-/*
- * Return one QMPResponse.  The response is only valid if
- * response.data is not NULL.
- */
-static QMPResponse monitor_qmp_response_pop_one(void)
-{
-    Monitor *mon;
-    QObject *data = NULL;
-
-    qemu_mutex_lock(&monitor_lock);
-    QTAILQ_FOREACH(mon, &mon_list, entry) {
-        qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
-        data = g_queue_pop_head(mon->qmp.qmp_responses);
-        qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
-        if (data) {
-            break;
-        }
-    }
-    qemu_mutex_unlock(&monitor_lock);
-    return (QMPResponse) { .mon = mon, .data = data };
-}
-
-static void monitor_qmp_bh_responder(void *opaque)
-{
-    QMPResponse response;
-
-    while (true) {
-        response = monitor_qmp_response_pop_one();
-        if (!response.data) {
-            break;
-        }
-        monitor_json_emitter_raw(response.mon, response.data);
-        qobject_decref(response.data);
-    }
-}
-
 static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
     /* Limit guest-triggerable events to 1 per second */
     [QAPI_EVENT_RTC_CHANGE]        = { 1000 * SCALE_MS },
@@ -688,7 +617,6 @@ static void monitor_data_init(Monitor *mon, bool skip_flush,
     mon->skip_flush = skip_flush;
     mon->use_io_thr = use_io_thr;
     mon->qmp.qmp_requests = g_queue_new();
-    mon->qmp.qmp_responses = g_queue_new();
 }
 
 static void monitor_data_destroy(Monitor *mon)
@@ -703,7 +631,6 @@ static void monitor_data_destroy(Monitor *mon)
     qemu_mutex_destroy(&mon->out_lock);
     qemu_mutex_destroy(&mon->qmp.qmp_queue_lock);
     g_queue_free(mon->qmp.qmp_requests);
-    g_queue_free(mon->qmp.qmp_responses);
 }
 
 char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
@@ -4443,15 +4370,6 @@ static void monitor_iothread_init(void)
     mon_global.qmp_dispatcher_bh = aio_bh_new(qemu_get_aio_context(),
                                               monitor_qmp_bh_dispatcher,
                                               NULL);
-
-    /*
-     * Unlike the dispatcher BH, this must be run on the monitor IO
-     * thread, so that monitors that are using IO thread will make
-     * sure read/write operations are all done on the IO thread.
-     */
-    mon_global.qmp_respond_bh = aio_bh_new(monitor_get_aio_context(),
-                                           monitor_qmp_bh_responder,
-                                           NULL);
 }
 
 void monitor_init_globals(void)
@@ -4597,19 +4515,9 @@ void monitor_cleanup(void)
      */
     iothread_stop(mon_global.mon_iothread);
 
-    /*
-     * After we have IOThread to send responses, it's possible that
-     * when we stop the IOThread there are still replies queued in the
-     * responder queue.  Flush all of them.  Note that even after this
-     * flush it's still possible that out buffer is not flushed.
-     * It'll be done in below monitor_flush() as the last resort.
-     */
-    monitor_qmp_bh_responder(NULL);
-
     qemu_mutex_lock(&monitor_lock);
     QTAILQ_FOREACH_SAFE(mon, &mon_list, entry, next) {
         QTAILQ_REMOVE(&mon_list, mon, entry);
-        monitor_flush(mon);
         monitor_data_destroy(mon);
         g_free(mon);
     }
@@ -4618,8 +4526,6 @@ void monitor_cleanup(void)
     /* QEMUBHs needs to be deleted before destroying the IOThread. */
     qemu_bh_delete(mon_global.qmp_dispatcher_bh);
     mon_global.qmp_dispatcher_bh = NULL;
-    qemu_bh_delete(mon_global.qmp_respond_bh);
-    mon_global.qmp_respond_bh = NULL;
 
     iothread_destroy(mon_global.mon_iothread);
     mon_global.mon_iothread = NULL;
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 04/38] monitor: no need to save need_resume
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (2 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 03/38] Revert "qmp: isolate responses into io thread" Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 05/38] monitor: further simplify previous patch Marc-André Lureau
                   ` (39 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

There is no need for per-command need_resume granularity, it should
resume after running an non-oob command on oob-disabled monitor.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/monitor.c b/monitor.c
index 59920ea872..2428c7fcd4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3950,12 +3950,6 @@ struct QMPRequest {
     QObject *id;
     /* Request object to be handled */
     QObject *req;
-    /*
-     * Whether we need to resume the monitor afterward.  This flag is
-     * used to emulate the old QMP server behavior that the current
-     * command must be completed before execution of the next one.
-     */
-    bool need_resume;
 };
 typedef struct QMPRequest QMPRequest;
 
@@ -3963,7 +3957,7 @@ typedef struct QMPRequest QMPRequest;
  * Dispatch one single QMP request. The function will free the req_obj
  * and objects inside it before return.
  */
-static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
+static void monitor_qmp_dispatch_one(QMPRequest *req_obj, bool oob_cmd)
 {
     Monitor *mon, *old_mon;
     QObject *req, *rsp = NULL, *id;
@@ -3972,7 +3966,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     req = req_obj->req;
     mon = req_obj->mon;
     id = req_obj->id;
-    need_resume = req_obj->need_resume;
+    need_resume = !oob_cmd && !qmp_oob_enabled(mon);
 
     g_free(req_obj);
 
@@ -4043,7 +4037,7 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
     if (req_obj) {
         trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
-        monitor_qmp_dispatch_one(req_obj);
+        monitor_qmp_dispatch_one(req_obj, false);
         /* Reschedule instead of looping so the main loop stays responsive */
         qemu_bh_schedule(mon_global.qmp_dispatcher_bh);
     }
@@ -4096,13 +4090,12 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     req_obj->mon = mon;
     req_obj->id = id;
     req_obj->req = req;
-    req_obj->need_resume = false;
 
     if (qmp_is_oob(qdict)) {
         /* Out-Of-Band (OOB) requests are executed directly in parser. */
         trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(req_obj->id)
                                           ?: "");
-        monitor_qmp_dispatch_one(req_obj);
+        monitor_qmp_dispatch_one(req_obj, true);
         return;
     }
 
@@ -4117,7 +4110,6 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
      */
     if (!qmp_oob_enabled(mon)) {
         monitor_suspend(mon);
-        req_obj->need_resume = true;
     } else {
         /* Drop the request if queue is full. */
         if (mon->qmp.qmp_requests->length >= QMP_REQ_QUEUE_LEN_MAX) {
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 05/38] monitor: further simplify previous patch
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (3 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 04/38] monitor: no need to save need_resume Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it Marc-André Lureau
                   ` (38 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Move the resume code to the non-oob path. This patch could eventually
be squashed with the previous patch.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/monitor.c b/monitor.c
index 2428c7fcd4..a8dcfa283e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3957,16 +3957,14 @@ typedef struct QMPRequest QMPRequest;
  * Dispatch one single QMP request. The function will free the req_obj
  * and objects inside it before return.
  */
-static void monitor_qmp_dispatch_one(QMPRequest *req_obj, bool oob_cmd)
+static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 {
     Monitor *mon, *old_mon;
     QObject *req, *rsp = NULL, *id;
-    bool need_resume;
 
     req = req_obj->req;
     mon = req_obj->mon;
     id = req_obj->id;
-    need_resume = !oob_cmd && !qmp_oob_enabled(mon);
 
     g_free(req_obj);
 
@@ -3986,11 +3984,6 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj, bool oob_cmd)
     /* Respond if necessary */
     monitor_qmp_respond(mon, rsp, NULL, id);
 
-    /* This pairs with the monitor_suspend() in handle_qmp_command(). */
-    if (need_resume) {
-        monitor_resume(mon);
-    }
-
     qobject_decref(req);
 }
 
@@ -4036,8 +4029,14 @@ static void monitor_qmp_bh_dispatcher(void *data)
     QMPRequest *req_obj = monitor_qmp_requests_pop_one();
 
     if (req_obj) {
+        Monitor *mon = req_obj->mon;
+        bool need_resume = !qmp_oob_enabled(mon);
         trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
-        monitor_qmp_dispatch_one(req_obj, false);
+        monitor_qmp_dispatch_one(req_obj);
+        /* This pairs with the monitor_suspend() in handle_qmp_command(). */
+        if (need_resume) {
+            monitor_resume(mon);
+        }
         /* Reschedule instead of looping so the main loop stays responsive */
         qemu_bh_schedule(mon_global.qmp_dispatcher_bh);
     }
@@ -4095,7 +4094,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
         /* Out-Of-Band (OOB) requests are executed directly in parser. */
         trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(req_obj->id)
                                           ?: "");
-        monitor_qmp_dispatch_one(req_obj, true);
+        monitor_qmp_dispatch_one(req_obj);
         return;
     }
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (4 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 05/38] monitor: further simplify previous patch Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 19:31   ` Eric Blake
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL Marc-André Lureau
                   ` (37 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

The following qdict_put() line does replace the value, as the
documentation says.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/monitor.c b/monitor.c
index a8dcfa283e..5889a32231 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3930,7 +3930,6 @@ static void monitor_qmp_respond(Monitor *mon, QObject *rsp,
                 && !g_strcmp0(qdict_get_try_str(qdict, "class"),
                           QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
                 /* Provide a more useful error message */
-                qdict_del(qdict, "desc");
                 qdict_put_str(qdict, "desc", "Expecting capabilities"
                               " negotiation with 'qmp_capabilities'");
             }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (5 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-07-05 11:35   ` Markus Armbruster
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times Marc-André Lureau
                   ` (36 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Let's make json_parser_parse_err() suck less, and simplify caller
error handling.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c             | 4 ----
 qobject/json-parser.c | 7 ++++++-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/monitor.c b/monitor.c
index 5889a32231..e9d0c4d172 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4053,10 +4053,6 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     QMPRequest *req_obj;
 
     req = json_parser_parse_err(tokens, NULL, &err);
-    if (!req && !err) {
-        /* json_parser_parse_err() sucks: can fail without setting @err */
-        error_setg(&err, QERR_JSON_PARSING);
-    }
     if (err) {
         goto err;
     }
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index 769b960c9f..c39cd8e4d7 100644
--- a/qobject/json-parser.c
+++ b/qobject/json-parser.c
@@ -591,7 +591,12 @@ QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp)
 
     result = parse_value(ctxt, ap);
 
-    error_propagate(errp, ctxt->err);
+    if (!result && !ctxt->err) {
+        /* TODO: improve error reporting */
+        error_setg(errp, "Failed to parse JSON");
+    } else {
+        error_propagate(errp, ctxt->err);
+    }
 
     parser_context_free(ctxt);
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (6 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-07-05 11:42   ` Markus Armbruster
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser Marc-André Lureau
                   ` (35 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

We can easily avoid the burden of checking if the lexer was
initialized prior to calling destroy by the caller, let's do it.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qobject/json-lexer.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index 980ba159d6..0eaba43a2c 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -386,5 +386,8 @@ int json_lexer_flush(JSONLexer *lexer)
 
 void json_lexer_destroy(JSONLexer *lexer)
 {
-    g_string_free(lexer->token, true);
+    if (lexer->token) {
+        g_string_free(lexer->token, true);
+        lexer->token = NULL;
+    }
 }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (7 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-07-05 11:49   ` Markus Armbruster
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests Marc-André Lureau
                   ` (34 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

The lexer always returns 0 when char feeding. Furthermore, none of the
caller care about the return value.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/json-lexer.h    |  4 ++--
 include/qapi/qmp/json-streamer.h |  4 ++--
 qobject/json-lexer.c             | 23 ++++++++---------------
 qobject/json-streamer.c          |  8 ++++----
 4 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/include/qapi/qmp/json-lexer.h b/include/qapi/qmp/json-lexer.h
index afee7828cd..66ccf0357c 100644
--- a/include/qapi/qmp/json-lexer.h
+++ b/include/qapi/qmp/json-lexer.h
@@ -47,9 +47,9 @@ struct JSONLexer
 
 void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func);
 
-int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size);
+void json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size);
 
-int json_lexer_flush(JSONLexer *lexer);
+void json_lexer_flush(JSONLexer *lexer);
 
 void json_lexer_destroy(JSONLexer *lexer);
 
diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h
index 00d8a23af8..cb808cf27d 100644
--- a/include/qapi/qmp/json-streamer.h
+++ b/include/qapi/qmp/json-streamer.h
@@ -36,10 +36,10 @@ typedef struct JSONMessageParser
 void json_message_parser_init(JSONMessageParser *parser,
                               void (*func)(JSONMessageParser *, GQueue *));
 
-int json_message_parser_feed(JSONMessageParser *parser,
+void json_message_parser_feed(JSONMessageParser *parser,
                              const char *buffer, size_t size);
 
-int json_message_parser_flush(JSONMessageParser *parser);
+void json_message_parser_flush(JSONMessageParser *parser);
 
 void json_message_parser_destroy(JSONMessageParser *parser);
 
diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index 0eaba43a2c..89ccb180cc 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -290,7 +290,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
     lexer->x = lexer->y = 0;
 }
 
-static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
+static void json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
 {
     int char_consumed, new_state;
 
@@ -344,7 +344,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
             g_string_truncate(lexer->token, 0);
             new_state = IN_START;
             lexer->state = new_state;
-            return 0;
+            return;
         default:
             break;
         }
@@ -359,29 +359,22 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
         g_string_truncate(lexer->token, 0);
         lexer->state = IN_START;
     }
-
-    return 0;
 }
 
-int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
+void json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
 {
     size_t i;
 
     for (i = 0; i < size; i++) {
-        int err;
-
-        err = json_lexer_feed_char(lexer, buffer[i], false);
-        if (err < 0) {
-            return err;
-        }
+        json_lexer_feed_char(lexer, buffer[i], false);
     }
-
-    return 0;
 }
 
-int json_lexer_flush(JSONLexer *lexer)
+void json_lexer_flush(JSONLexer *lexer)
 {
-    return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0, true);
+    if (lexer->state != IN_START) {
+        json_lexer_feed_char(lexer, 0, true);
+    }
 }
 
 void json_lexer_destroy(JSONLexer *lexer)
diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c
index c51c2021f9..78dfff2aa0 100644
--- a/qobject/json-streamer.c
+++ b/qobject/json-streamer.c
@@ -118,15 +118,15 @@ void json_message_parser_init(JSONMessageParser *parser,
     json_lexer_init(&parser->lexer, json_message_process_token);
 }
 
-int json_message_parser_feed(JSONMessageParser *parser,
+void json_message_parser_feed(JSONMessageParser *parser,
                              const char *buffer, size_t size)
 {
-    return json_lexer_feed(&parser->lexer, buffer, size);
+    json_lexer_feed(&parser->lexer, buffer, size);
 }
 
-int json_message_parser_flush(JSONMessageParser *parser)
+void json_message_parser_flush(JSONMessageParser *parser)
 {
-    return json_lexer_flush(&parser->lexer);
+    json_lexer_flush(&parser->lexer);
 }
 
 void json_message_parser_destroy(JSONMessageParser *parser)
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (8 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-07-05 11:55   ` Markus Armbruster
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
                   ` (33 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

These 2 tests exhibited two qmp bugs that were fixed in 2.7
(series from commit e64c75a9752c5d0fd64eb2e684c656a5ea7d03c6 to
commit 1382d4abdf9619985e4078e37e49e487cea9935e)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/qmp-test.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 07c0b87e27..642f46a332 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -224,7 +224,50 @@ static void test_qmp_oob(void)
         }
         QDECREF(resp);
     }
+    qtest_end();
+}
+
+static void test_object_add_without_props(void)
+{
+    QDict *ret, *error;
+    const gchar *klass, *desc;
+
+    qtest_start("-machine none");
 
+    ret = qmp("{'execute': 'object-add',"
+              " 'arguments': { 'qom-type': 'memory-backend-ram', 'id': 'ram1' } }");
+    g_assert_nonnull(ret);
+
+    error = qdict_get_qdict(ret, "error");
+    klass = qdict_get_try_str(error, "class");
+    desc = qdict_get_try_str(error, "desc");
+
+    g_assert_cmpstr(klass, ==, "GenericError");
+    g_assert_cmpstr(desc, ==, "can't create backend with size 0");
+
+    QDECREF(ret);
+    qtest_end();
+}
+
+static void test_qom_set_without_value(void)
+{
+    QDict *ret, *error;
+    const gchar *klass, *desc;
+
+    qtest_start("-machine none");
+
+    ret = qmp("{'execute': 'qom-set',"
+              " 'arguments': { 'path': '/machine', 'property': 'rtc-time' } }");
+    g_assert_nonnull(ret);
+
+    error = qdict_get_qdict(ret, "error");
+    klass = qdict_get_try_str(error, "class");
+    desc = qdict_get_try_str(error, "desc");
+
+    g_assert_cmpstr(klass, ==, "GenericError");
+    g_assert_cmpstr(desc, ==, "Parameter 'value' is missing");
+
+    QDECREF(ret);
     qtest_end();
 }
 
@@ -411,13 +454,19 @@ int main(int argc, char *argv[])
 
     g_test_init(&argc, &argv, NULL);
 
+    qtest_add_func("qmp/object-add-without-props",
+                   test_object_add_without_props);
+    qtest_add_func("qmp/qom-set-without-value",
+                   test_qom_set_without_value);
     qtest_add_func("qmp/protocol", test_qmp_protocol);
     qtest_add_func("qmp/oob", test_qmp_oob);
+
     qmp_schema_init(&schema);
     add_query_tests(&schema);
 
     ret = g_test_run();
 
     qmp_schema_cleanup(&schema);
+
     return ret;
 }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/*
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (9 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-07-05 11:56   ` Markus Armbruster
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test Marc-André Lureau
                   ` (32 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Presumably 0.15 was the version it was first introduced, but
qmp keeps evolving. There is no point in having that version
as test prefix, 'qmp' makes more sense here.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/test-qmp-cmds.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 93fbbb1b73..b49e9dd029 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -273,11 +273,11 @@ int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
 
-    g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
-    g_test_add_func("/0.15/dispatch_cmd_failure", test_dispatch_cmd_failure);
-    g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
-    g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
-    g_test_add_func("/0.15/dealloc_partial", test_dealloc_partial);
+    g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd);
+    g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure);
+    g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
+    g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
+    g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 
     test_qmp_init_marshal(&qmp_commands);
     g_test_run();
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (10 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-07-05 11:59   ` Markus Armbruster
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 13/38] qga: process_event() simplification Marc-André Lureau
                   ` (31 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Verify the usage of this schema feature and the API behaviour.  This
should be the only case where qmp_dispatch() returns NULL without
error.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/test-qmp-cmds.c                   | 17 +++++++++++++++++
 tests/qapi-schema/qapi-schema-test.json |  2 ++
 tests/qapi-schema/qapi-schema-test.out  |  2 ++
 3 files changed, 21 insertions(+)

diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index b49e9dd029..02cbaf41a2 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -16,6 +16,10 @@ void qmp_user_def_cmd(Error **errp)
 {
 }
 
+void qmp_cmd_success_response(Error **errp)
+{
+}
+
 Empty2 *qmp_user_def_cmd0(Error **errp)
 {
     return g_new0(Empty2, 1);
@@ -137,6 +141,17 @@ static void test_dispatch_cmd_failure(void)
     QDECREF(req);
 }
 
+static void test_dispatch_cmd_success_response(void)
+{
+    QDict *req = qdict_new();
+    QObject *resp;
+
+    qdict_put_str(req, "execute", "cmd-success-response");
+    resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+    assert(resp == NULL);
+    QDECREF(req);
+}
+
 static QObject *test_qmp_dispatch(QDict *req)
 {
     QObject *resp_obj;
@@ -276,6 +291,8 @@ int main(int argc, char **argv)
     g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd);
     g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure);
     g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
+    g_test_add_func("/qmp/dispatch_cmd_success_response",
+                    test_dispatch_cmd_success_response);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
     g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index c72dbd8050..96ff3a8e47 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -132,6 +132,8 @@
   'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
   'returns': 'UserDefTwo' }
 
+{ 'command': 'cmd-success-response', 'data': {}, 'success-response': false }
+
 # Returning a non-dictionary requires a name from the whitelist
 { 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
   'returns': 'int' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 012e7fc06a..cd3642be34 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -153,6 +153,8 @@ object q_obj_user_def_cmd2-arg
     member ud1b: UserDefOne optional=True
 command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
    gen=True success_response=True boxed=False
+command cmd-success-response None -> None
+   gen=True success_response=False boxed=False
 object q_obj_guest-get-time-arg
     member a: int optional=False
     member b: int optional=True
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 13/38] qga: process_event() simplification
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (11 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 14/38] monitor: simplify monitor_qmp_respond() Marc-André Lureau
                   ` (30 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Simplify the code around qmp_dispatch().

Make qmp_dispatch_check_obj() a pre-requirement, same as qemu monitor.

Have a single send_response() point.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qga/main.c | 67 +++++++++++++++++++-----------------------------------
 1 file changed, 23 insertions(+), 44 deletions(-)

diff --git a/qga/main.c b/qga/main.c
index df1888edc1..71468e68c2 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -579,67 +579,46 @@ static int send_response(GAState *s, QObject *payload)
     return 0;
 }
 
-static void process_command(GAState *s, QDict *req)
-{
-    QObject *rsp = NULL;
-    int ret;
-
-    g_assert(req);
-    g_debug("processing command");
-    rsp = qmp_dispatch(&ga_commands, QOBJECT(req));
-    if (rsp) {
-        ret = send_response(s, rsp);
-        if (ret < 0) {
-            g_warning("error sending response: %s", strerror(-ret));
-        }
-        qobject_decref(rsp);
-    }
-}
-
 /* handle requests/control events coming in over the channel */
 static void process_event(JSONMessageParser *parser, GQueue *tokens)
 {
     GAState *s = container_of(parser, GAState, parser);
-    QDict *qdict;
+    QObject *req, *rsp = NULL;
     Error *err = NULL;
     int ret;
 
     g_assert(s && parser);
 
     g_debug("process_event: called");
-    qdict = qobject_to(QDict, json_parser_parse_err(tokens, NULL, &err));
-    if (err || !qdict) {
-        QDECREF(qdict);
-        qdict = qdict_new();
-        if (!err) {
-            g_warning("failed to parse event: unknown error");
-            error_setg(&err, QERR_JSON_PARSING);
-        } else {
-            g_warning("failed to parse event: %s", error_get_pretty(err));
-        }
+
+    req = json_parser_parse_err(tokens, NULL, &err);
+    if (err) {
+        goto end;
+    }
+
+    qmp_dispatch_check_obj(req, &err);
+    if (err) {
+        goto end;
+    }
+
+    g_debug("processing command");
+    rsp = qmp_dispatch(&ga_commands, req);
+
+end:
+    if (err) {
+        QDict *qdict = qdict_new();
         qdict_put_obj(qdict, "error", qmp_build_error_object(err));
         error_free(err);
+        rsp = QOBJECT(qdict);
     }
-
-    /* handle host->guest commands */
-    if (qdict_haskey(qdict, "execute")) {
-        process_command(s, qdict);
-    } else {
-        if (!qdict_haskey(qdict, "error")) {
-            QDECREF(qdict);
-            qdict = qdict_new();
-            g_warning("unrecognized payload format");
-            error_setg(&err, QERR_UNSUPPORTED);
-            qdict_put_obj(qdict, "error", qmp_build_error_object(err));
-            error_free(err);
-        }
-        ret = send_response(s, QOBJECT(qdict));
+    if (rsp) {
+        ret = send_response(s, rsp);
         if (ret < 0) {
             g_warning("error sending error response: %s", strerror(-ret));
         }
+        qobject_decref(rsp);
     }
-
-    QDECREF(qdict);
+    qobject_decref(req);
 }
 
 /* false return signals GAChannel to close the current client connection */
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 14/38] monitor: simplify monitor_qmp_respond()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (12 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 13/38] qga: process_event() simplification Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 15/38] qmp: pass and return a QDict to qmp_dispatch() Marc-André Lureau
                   ` (29 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Since the error path is at a single location, we can create the
response object there, simplifying argument handling. While at it,
also simplify id ownership: no need for the extra reference count.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 58 ++++++++++++++++++++-----------------------------------
 1 file changed, 21 insertions(+), 37 deletions(-)

diff --git a/monitor.c b/monitor.c
index e9d0c4d172..0d01e17398 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3899,46 +3899,27 @@ static int monitor_can_read(void *opaque)
     return !atomic_mb_read(&mon->suspend_cnt);
 }
 
-/*
- * 1. This function takes ownership of rsp, err, and id.
- * 2. rsp, err, and id may be NULL.
- * 3. If err != NULL then rsp must be NULL.
- */
-static void monitor_qmp_respond(Monitor *mon, QObject *rsp,
-                                Error *err, QObject *id)
+/* take the ownership of rsp & id */
+static void monitor_qmp_respond(Monitor *mon, QObject *rsp, QObject *id)
 {
-    QDict *qdict = NULL;
-
-    if (err) {
-        assert(!rsp);
-        qdict = qdict_new();
-        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
-        error_free(err);
-        rsp = QOBJECT(qdict);
-    }
-
-    if (rsp) {
-        if (id) {
-            /* This is for the qdict below. */
-            qobject_incref(id);
-            qdict_put_obj(qobject_to(QDict, rsp), "id", id);
-        }
+    if (!rsp) {
+        return;
+    }
 
-        if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
-            qdict = qdict_get_qdict(qobject_to(QDict, rsp), "error");
-            if (qdict
-                && !g_strcmp0(qdict_get_try_str(qdict, "class"),
+    if (id) {
+        qdict_put_obj(qobject_to(QDict, rsp), "id", id);
+    }
+    if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
+        QDict *qdict = qdict_get_qdict(qobject_to(QDict, rsp), "error");
+        if (qdict
+            && !g_strcmp0(qdict_get_try_str(qdict, "class"),
                           QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
-                /* Provide a more useful error message */
-                qdict_put_str(qdict, "desc", "Expecting capabilities"
-                              " negotiation with 'qmp_capabilities'");
-            }
+            /* Provide a more useful error message */
+            qdict_put_str(qdict, "desc", "Expecting capabilities"
+                          " negotiation with 'qmp_capabilities'");
         }
-
-        monitor_json_emitter(mon, rsp);
     }
-
-    qobject_decref(id);
+    monitor_json_emitter(mon, rsp);
     qobject_decref(rsp);
 }
 
@@ -3981,7 +3962,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     cur_mon = old_mon;
 
     /* Respond if necessary */
-    monitor_qmp_respond(mon, rsp, NULL, id);
+    monitor_qmp_respond(mon, rsp, id);
 
     qobject_decref(req);
 }
@@ -4131,7 +4112,10 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     return;
 
 err:
-    monitor_qmp_respond(mon, NULL, err, NULL);
+    qdict = qdict_new();
+    qdict_put_obj(qdict, "error", qmp_build_error_object(err));
+    error_free(err);
+    monitor_qmp_respond(mon, QOBJECT(qdict), id);
     qobject_decref(req);
 }
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 15/38] qmp: pass and return a QDict to qmp_dispatch()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (13 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 14/38] monitor: simplify monitor_qmp_respond() Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 16/38] qmp: move 'id' copy " Marc-André Lureau
                   ` (28 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

qmp_dispatch_check_obj() now must be called before calling
qmp_dispatch() and returns a dict.

Change qmp_dispatch() arguments, clarifying the expected qobject
types, and simplifying a bit the rest of the code.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  2 +-
 monitor.c                   | 24 +++++++++++++-----------
 qapi/qmp-dispatch.c         | 15 +++++----------
 qga/main.c                  | 18 +++++++++---------
 tests/test-qmp-cmds.c       | 36 +++++++++++++++---------------------
 5 files changed, 43 insertions(+), 52 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index ffb4652f71..8e0ac29300 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -40,7 +40,7 @@ void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
-QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request);
+QDict *qmp_dispatch(QmpCommandList *cmds, QDict *request);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
 
diff --git a/monitor.c b/monitor.c
index 0d01e17398..471c57e88c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3900,17 +3900,17 @@ static int monitor_can_read(void *opaque)
 }
 
 /* take the ownership of rsp & id */
-static void monitor_qmp_respond(Monitor *mon, QObject *rsp, QObject *id)
+static void monitor_qmp_respond(Monitor *mon, QDict *rsp, QObject *id)
 {
     if (!rsp) {
         return;
     }
 
     if (id) {
-        qdict_put_obj(qobject_to(QDict, rsp), "id", id);
+        qdict_put_obj(rsp, "id", id);
     }
     if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
-        QDict *qdict = qdict_get_qdict(qobject_to(QDict, rsp), "error");
+        QDict *qdict = qdict_get_qdict(rsp, "error");
         if (qdict
             && !g_strcmp0(qdict_get_try_str(qdict, "class"),
                           QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
@@ -3919,8 +3919,8 @@ static void monitor_qmp_respond(Monitor *mon, QObject *rsp, QObject *id)
                           " negotiation with 'qmp_capabilities'");
         }
     }
-    monitor_json_emitter(mon, rsp);
-    qobject_decref(rsp);
+    monitor_json_emitter(mon, QOBJECT(rsp));
+    QDECREF(rsp);
 }
 
 struct QMPRequest {
@@ -3929,7 +3929,7 @@ struct QMPRequest {
     /* "id" field of the request */
     QObject *id;
     /* Request object to be handled */
-    QObject *req;
+    QDict *req;
 };
 typedef struct QMPRequest QMPRequest;
 
@@ -3940,7 +3940,8 @@ typedef struct QMPRequest QMPRequest;
 static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 {
     Monitor *mon, *old_mon;
-    QObject *req, *rsp = NULL, *id;
+    QDict *req, *rsp = NULL;
+    QObject *id;
 
     req = req_obj->req;
     mon = req_obj->mon;
@@ -3949,7 +3950,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     g_free(req_obj);
 
     if (trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
-        QString *req_json = qobject_to_json(req);
+        QString *req_json = qobject_to_json(QOBJECT(req));
         trace_handle_qmp_command(mon, qstring_get_str(req_json));
         QDECREF(req_json);
     }
@@ -3964,7 +3965,8 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     /* Respond if necessary */
     monitor_qmp_respond(mon, rsp, id);
 
-    qobject_decref(req);
+
+    QDECREF(req);
 }
 
 /*
@@ -4064,7 +4066,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     req_obj = g_new0(QMPRequest, 1);
     req_obj->mon = mon;
     req_obj->id = id;
-    req_obj->req = req;
+    req_obj->req = qdict;
 
     if (qmp_is_oob(qdict)) {
         /* Out-Of-Band (OOB) requests are executed directly in parser. */
@@ -4115,7 +4117,7 @@ err:
     qdict = qdict_new();
     qdict_put_obj(qdict, "error", qmp_build_error_object(err));
     error_free(err);
-    monitor_qmp_respond(mon, QOBJECT(qdict), id);
+    monitor_qmp_respond(mon, qdict, id);
     qobject_decref(req);
 }
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index dd05907265..66596b66a0 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -74,20 +74,15 @@ QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
     return dict;
 }
 
-static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
+static QObject *do_qmp_dispatch(QmpCommandList *cmds, QDict *dict,
                                 Error **errp)
 {
     Error *local_err = NULL;
     const char *command;
-    QDict *args, *dict;
+    QDict *args;
     QmpCommand *cmd;
     QObject *ret = NULL;
 
-    dict = qmp_dispatch_check_obj(request, errp);
-    if (!dict) {
-        return NULL;
-    }
-
     command = qdict_get_str(dict, "execute");
     cmd = qmp_find_command(cmds, command);
     if (cmd == NULL) {
@@ -151,13 +146,13 @@ bool qmp_is_oob(QDict *dict)
     return qbool_get_bool(bool_obj);
 }
 
-QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request)
+QDict *qmp_dispatch(QmpCommandList *cmds, QDict *req)
 {
     Error *err = NULL;
     QObject *ret;
     QDict *rsp;
 
-    ret = do_qmp_dispatch(cmds, request, &err);
+    ret = do_qmp_dispatch(cmds, req, &err);
 
     rsp = qdict_new();
     if (err) {
@@ -170,5 +165,5 @@ QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request)
         return NULL;
     }
 
-    return QOBJECT(rsp);
+    return rsp;
 }
diff --git a/qga/main.c b/qga/main.c
index 71468e68c2..04f7dad0b3 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -583,7 +583,8 @@ static int send_response(GAState *s, QObject *payload)
 static void process_event(JSONMessageParser *parser, GQueue *tokens)
 {
     GAState *s = container_of(parser, GAState, parser);
-    QObject *req, *rsp = NULL;
+    QObject *obj;
+    QDict *req, *rsp = NULL;
     Error *err = NULL;
     int ret;
 
@@ -591,12 +592,12 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens)
 
     g_debug("process_event: called");
 
-    req = json_parser_parse_err(tokens, NULL, &err);
+    obj = json_parser_parse_err(tokens, NULL, &err);
     if (err) {
         goto end;
     }
 
-    qmp_dispatch_check_obj(req, &err);
+    req = qmp_dispatch_check_obj(obj, &err);
     if (err) {
         goto end;
     }
@@ -606,19 +607,18 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens)
 
 end:
     if (err) {
-        QDict *qdict = qdict_new();
-        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
+        rsp = qdict_new();
+        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
         error_free(err);
-        rsp = QOBJECT(qdict);
     }
     if (rsp) {
-        ret = send_response(s, rsp);
+        ret = send_response(s, QOBJECT(rsp));
         if (ret < 0) {
             g_warning("error sending error response: %s", strerror(-ret));
         }
-        qobject_decref(rsp);
+        QDECREF(rsp);
     }
-    qobject_decref(req);
+    qobject_decref(obj);
 }
 
 /* false return signals GAChannel to close the current client connection */
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 02cbaf41a2..52e2738a93 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -97,16 +97,15 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
 /* test commands with no input and no return value */
 static void test_dispatch_cmd(void)
 {
-    QDict *req = qdict_new();
-    QObject *resp;
+    QDict *resp, *req = qdict_new();
 
     qdict_put_str(req, "execute", "user_def_cmd");
 
-    resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+    resp = qmp_dispatch(&qmp_commands, req);
     assert(resp != NULL);
-    assert(!qdict_haskey(qobject_to(QDict, resp), "error"));
+    assert(!qdict_haskey(resp, "error"));
 
-    qobject_decref(resp);
+    QDECREF(resp);
     QDECREF(req);
 }
 
@@ -114,16 +113,15 @@ static void test_dispatch_cmd(void)
 static void test_dispatch_cmd_failure(void)
 {
     QDict *req = qdict_new();
-    QDict *args = qdict_new();
-    QObject *resp;
+    QDict *resp, *args = qdict_new();
 
     qdict_put_str(req, "execute", "user_def_cmd2");
 
-    resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+    resp = qmp_dispatch(&qmp_commands, req);
     assert(resp != NULL);
-    assert(qdict_haskey(qobject_to(QDict, resp), "error"));
+    assert(qdict_haskey(resp, "error"));
 
-    qobject_decref(resp);
+    QDECREF(resp);
     QDECREF(req);
 
     /* check that with extra arguments it throws an error */
@@ -133,39 +131,35 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_str(req, "execute", "user_def_cmd");
 
-    resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+    resp = qmp_dispatch(&qmp_commands, req);
     assert(resp != NULL);
-    assert(qdict_haskey(qobject_to(QDict, resp), "error"));
+    assert(qdict_haskey(resp, "error"));
 
-    qobject_decref(resp);
+    QDECREF(resp);
     QDECREF(req);
 }
 
 static void test_dispatch_cmd_success_response(void)
 {
-    QDict *req = qdict_new();
-    QObject *resp;
+    QDict *resp, *req = qdict_new();
 
     qdict_put_str(req, "execute", "cmd-success-response");
-    resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
+    resp = qmp_dispatch(&qmp_commands, req);
     assert(resp == NULL);
     QDECREF(req);
 }
 
 static QObject *test_qmp_dispatch(QDict *req)
 {
-    QObject *resp_obj;
     QDict *resp;
     QObject *ret;
 
-    resp_obj = qmp_dispatch(&qmp_commands, QOBJECT(req));
-    assert(resp_obj);
-    resp = qobject_to(QDict, resp_obj);
+    resp = qmp_dispatch(&qmp_commands, req);
     assert(resp && !qdict_haskey(resp, "error"));
     ret = qdict_get(resp, "return");
     assert(ret);
     qobject_incref(ret);
-    qobject_decref(resp_obj);
+    QDECREF(resp);
     return ret;
 }
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 16/38] qmp: move 'id' copy to qmp_dispatch()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (14 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 15/38] qmp: pass and return a QDict to qmp_dispatch() Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 17/38] qmp: constify qmp_is_oob() Marc-André Lureau
                   ` (27 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

This is convenient for other QMP users such as QGA and tests and
simplifies a bit the qemu monitor code, and avoids modifying the
request.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c             | 23 ++++++-----------------
 qapi/qmp-dispatch.c   |  5 +++++
 tests/test-qmp-cmds.c | 17 +++++++++++++++++
 3 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/monitor.c b/monitor.c
index 471c57e88c..ddcc3a5748 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3899,16 +3899,9 @@ static int monitor_can_read(void *opaque)
     return !atomic_mb_read(&mon->suspend_cnt);
 }
 
-/* take the ownership of rsp & id */
-static void monitor_qmp_respond(Monitor *mon, QDict *rsp, QObject *id)
+/* take the ownership of rsp */
+static void monitor_qmp_respond(Monitor *mon, QDict *rsp)
 {
-    if (!rsp) {
-        return;
-    }
-
-    if (id) {
-        qdict_put_obj(rsp, "id", id);
-    }
     if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
         QDict *qdict = qdict_get_qdict(rsp, "error");
         if (qdict
@@ -3941,11 +3934,9 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 {
     Monitor *mon, *old_mon;
     QDict *req, *rsp = NULL;
-    QObject *id;
 
     req = req_obj->req;
     mon = req_obj->mon;
-    id = req_obj->id;
 
     g_free(req_obj);
 
@@ -3963,7 +3954,9 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     cur_mon = old_mon;
 
     /* Respond if necessary */
-    monitor_qmp_respond(mon, rsp, id);
+    if (rsp) {
+        monitor_qmp_respond(mon, rsp);
+    }
 
 
     QDECREF(req);
@@ -4060,9 +4053,6 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
         goto err;
     }
 
-    qobject_incref(id);
-    qdict_del(qdict, "id");
-
     req_obj = g_new0(QMPRequest, 1);
     req_obj->mon = mon;
     req_obj->id = id;
@@ -4094,7 +4084,6 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
             qapi_event_send_command_dropped(id,
                                             COMMAND_DROP_REASON_QUEUE_FULL,
                                             &error_abort);
-            qobject_decref(id);
             qobject_decref(req);
             g_free(req_obj);
             return;
@@ -4117,7 +4106,7 @@ err:
     qdict = qdict_new();
     qdict_put_obj(qdict, "error", qmp_build_error_object(err));
     error_free(err);
-    monitor_qmp_respond(mon, qdict, id);
+    monitor_qmp_respond(mon, qdict);
     qobject_decref(req);
 }
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 66596b66a0..4be0648809 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -151,10 +151,15 @@ QDict *qmp_dispatch(QmpCommandList *cmds, QDict *req)
     Error *err = NULL;
     QObject *ret;
     QDict *rsp;
+    QObject *id = qdict_get(req, "id");
 
     ret = do_qmp_dispatch(cmds, req, &err);
 
     rsp = qdict_new();
+    if (id) {
+        qobject_incref(id);
+        qdict_put_obj(rsp, "id", id);
+    }
     if (err) {
         qdict_put_obj(rsp, "error", qmp_build_error_object(err));
         error_free(err);
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 52e2738a93..58d948b01f 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -277,6 +277,22 @@ static void test_dealloc_partial(void)
     qapi_free_UserDefTwo(ud2);
 }
 
+static void test_dispatch_cmd_id(void)
+{
+    QDict *resp, *req = qdict_new();
+
+    qdict_put_str(req, "execute", "user_def_cmd");
+    qdict_put_str(req, "id", "ID42");
+
+    resp = qmp_dispatch(&qmp_commands, req);
+    assert(resp != NULL);
+    assert(!qdict_haskey(resp, "error"));
+    assert(!strcmp(qdict_get_str(resp, "id"), "ID42"));
+
+    QDECREF(resp);
+    QDECREF(req);
+}
+
 
 int main(int argc, char **argv)
 {
@@ -287,6 +303,7 @@ int main(int argc, char **argv)
     g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
     g_test_add_func("/qmp/dispatch_cmd_success_response",
                     test_dispatch_cmd_success_response);
+    g_test_add_func("/qmp/dispatch_cmd_id", test_dispatch_cmd_id);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
     g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 17/38] qmp: constify qmp_is_oob()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (15 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 16/38] qmp: move 'id' copy " Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 18/38] qmp: add QmpSession Marc-André Lureau
                   ` (26 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h | 2 +-
 qapi/qmp-dispatch.c         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 8e0ac29300..79fe7f18e0 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -49,7 +49,7 @@ const char *qmp_command_name(const QmpCommand *cmd);
 bool qmp_has_success_response(const QmpCommand *cmd);
 QObject *qmp_build_error_object(Error *err);
 QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp);
-bool qmp_is_oob(QDict *dict);
+bool qmp_is_oob(const QDict *dict);
 
 typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 4be0648809..e8a14eb845 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -129,7 +129,7 @@ QObject *qmp_build_error_object(Error *err)
  * peeking at whether we have: { "control": { "run-oob": true } }. By
  * default commands are run in-band.
  */
-bool qmp_is_oob(QDict *dict)
+bool qmp_is_oob(const QDict *dict)
 {
     QBool *bool_obj;
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 18/38] qmp: add QmpSession
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (16 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 17/38] qmp: constify qmp_is_oob() Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 19/38] QmpSession: add a return_cb Marc-André Lureau
                   ` (25 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

This structure will hold various data related to a QMP session: the
list of commands, the parser, the callbacks, the pending operations
etc...

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h | 10 +++++++++-
 monitor.c                   | 20 +++++++++++---------
 qapi/qmp-dispatch.c         | 14 ++++++++++++--
 qga/main.c                  |  6 ++++--
 tests/test-qmp-cmds.c       | 28 ++++++++++++++++++++++------
 5 files changed, 58 insertions(+), 20 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 79fe7f18e0..10ba0745c7 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -36,11 +36,19 @@ typedef struct QmpCommand
 
 typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
+typedef struct QmpSession QmpSession;
+
+struct QmpSession {
+    QmpCommandList *cmds;
+};
+
 void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
-QDict *qmp_dispatch(QmpCommandList *cmds, QDict *request);
+void qmp_session_init(QmpSession *session, QmpCommandList *cmds);
+void qmp_session_destroy(QmpSession *session);
+QDict *qmp_dispatch(QmpSession *session, QDict *request);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
 
diff --git a/monitor.c b/monitor.c
index ddcc3a5748..b90f8566c8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -171,7 +171,7 @@ typedef struct {
      * When command qmp_capabilities succeeds, we go into command
      * mode.
      */
-    QmpCommandList *commands;
+    QmpSession session;
     bool qmp_caps[QMP_CAPABILITY__MAX];
     /*
      * Protects qmp request/response queue.  Please take monitor_lock
@@ -454,7 +454,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict)
     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) {
+            && mon->qmp.session.cmds != &qmp_cap_negotiation_commands) {
             monitor_json_emitter(mon, QOBJECT(qdict));
         }
     }
@@ -624,6 +624,7 @@ static void monitor_data_destroy(Monitor *mon)
     g_free(mon->mon_cpu_path);
     qemu_chr_fe_deinit(&mon->chr, false);
     if (monitor_is_qmp(mon)) {
+        qmp_session_destroy(&mon->qmp.session);
         json_message_parser_destroy(&mon->qmp.parser);
     }
     readline_free(mon->rs);
@@ -961,7 +962,7 @@ CommandInfoList *qmp_query_commands(Error **errp)
 {
     CommandInfoList *list = NULL;
 
-    qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
+    qmp_for_each_command(cur_mon->qmp.session.cmds, query_commands_cb, &list);
 
     return list;
 }
@@ -1129,7 +1130,7 @@ static bool qmp_cmd_oob_check(Monitor *mon, QDict *req, Error **errp)
         return false;
     }
 
-    cmd = qmp_find_command(mon->qmp.commands, command);
+    cmd = qmp_find_command(mon->qmp.session.cmds, command);
     if (!cmd) {
         error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
                   "The command %s has not been found", command);
@@ -1157,7 +1158,7 @@ void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
 {
     Error *local_err = NULL;
 
-    if (cur_mon->qmp.commands == &qmp_commands) {
+    if (cur_mon->qmp.session.cmds == &qmp_commands) {
         error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
                   "Capabilities negotiation is already complete, command "
                   "ignored");
@@ -1179,7 +1180,7 @@ void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
         qmp_caps_apply(cur_mon, enable);
     }
 
-    cur_mon->qmp.commands = &qmp_commands;
+    cur_mon->qmp.session.cmds = &qmp_commands;
 }
 
 /* set the current CPU defined by the user */
@@ -3902,7 +3903,7 @@ static int monitor_can_read(void *opaque)
 /* take the ownership of rsp */
 static void monitor_qmp_respond(Monitor *mon, QDict *rsp)
 {
-    if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
+    if (mon->qmp.session.cmds == &qmp_cap_negotiation_commands) {
         QDict *qdict = qdict_get_qdict(rsp, "error");
         if (qdict
             && !g_strcmp0(qdict_get_try_str(qdict, "class"),
@@ -3949,7 +3950,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     old_mon = cur_mon;
     cur_mon = mon;
 
-    rsp = qmp_dispatch(mon->qmp.commands, req);
+    rsp = qmp_dispatch(&mon->qmp.session, req);
 
     cur_mon = old_mon;
 
@@ -4222,7 +4223,7 @@ static void monitor_qmp_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_OPENED:
-        mon->qmp.commands = &qmp_cap_negotiation_commands;
+        qmp_session_init(&mon->qmp.session, &qmp_cap_negotiation_commands);
         monitor_qmp_caps_reset(mon);
         data = get_qmp_greeting(mon);
         monitor_json_emitter(mon, data);
@@ -4230,6 +4231,7 @@ static void monitor_qmp_event(void *opaque, int event)
         mon_refcount++;
         break;
     case CHR_EVENT_CLOSED:
+        qmp_session_destroy(&mon->qmp.session);
         json_message_parser_destroy(&mon->qmp.parser);
         json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
         mon_refcount--;
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index e8a14eb845..7fd4e41b26 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -146,14 +146,24 @@ bool qmp_is_oob(const QDict *dict)
     return qbool_get_bool(bool_obj);
 }
 
-QDict *qmp_dispatch(QmpCommandList *cmds, QDict *req)
+void qmp_session_init(QmpSession *session, QmpCommandList *cmds)
+{
+    session->cmds = cmds;
+}
+
+void qmp_session_destroy(QmpSession *session)
+{
+    session->cmds = NULL;
+}
+
+QDict *qmp_dispatch(QmpSession *session, QDict *req)
 {
     Error *err = NULL;
     QObject *ret;
     QDict *rsp;
     QObject *id = qdict_get(req, "id");
 
-    ret = do_qmp_dispatch(cmds, req, &err);
+    ret = do_qmp_dispatch(session->cmds, req, &err);
 
     rsp = qdict_new();
     if (id) {
diff --git a/qga/main.c b/qga/main.c
index 04f7dad0b3..b5d7cc9e8f 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -71,6 +71,7 @@ typedef struct GAPersistentState {
 } GAPersistentState;
 
 struct GAState {
+    QmpSession session;
     JSONMessageParser parser;
     GMainLoop *main_loop;
     GAChannel *channel;
@@ -603,7 +604,7 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens)
     }
 
     g_debug("processing command");
-    rsp = qmp_dispatch(&ga_commands, req);
+    rsp = qmp_dispatch(&s->session, req);
 
 end:
     if (err) {
@@ -1304,7 +1305,7 @@ static int run_agent(GAState *s, GAConfig *config, int socket_activation)
     ga_command_state_init(s, s->command_state);
     ga_command_state_init_all(s->command_state);
     json_message_parser_init(&s->parser, process_event);
-
+    qmp_session_init(&s->session, &ga_commands);
 #ifndef _WIN32
     if (!register_signal_handlers()) {
         g_critical("failed to register signal handlers");
@@ -1424,6 +1425,7 @@ int main(int argc, char **argv)
 
 end:
     if (s->command_state) {
+        qmp_session_destroy(&s->session);
         ga_command_state_cleanup_all(s->command_state);
         ga_command_state_free(s->command_state);
         json_message_parser_destroy(&s->parser);
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 58d948b01f..0c1fecb281 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -97,27 +97,32 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
 /* test commands with no input and no return value */
 static void test_dispatch_cmd(void)
 {
+    QmpSession session = { 0, };
     QDict *resp, *req = qdict_new();
 
+    qmp_session_init(&session, &qmp_commands);
     qdict_put_str(req, "execute", "user_def_cmd");
 
-    resp = qmp_dispatch(&qmp_commands, req);
+    resp = qmp_dispatch(&session, req);
     assert(resp != NULL);
     assert(!qdict_haskey(resp, "error"));
 
     QDECREF(resp);
     QDECREF(req);
+    qmp_session_destroy(&session);
 }
 
 /* test commands that return an error due to invalid parameters */
 static void test_dispatch_cmd_failure(void)
 {
+    QmpSession session = { 0, };
     QDict *req = qdict_new();
     QDict *resp, *args = qdict_new();
 
+    qmp_session_init(&session, &qmp_commands);
     qdict_put_str(req, "execute", "user_def_cmd2");
 
-    resp = qmp_dispatch(&qmp_commands, req);
+    resp = qmp_dispatch(&session, req);
     assert(resp != NULL);
     assert(qdict_haskey(resp, "error"));
 
@@ -131,35 +136,43 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_str(req, "execute", "user_def_cmd");
 
-    resp = qmp_dispatch(&qmp_commands, req);
+    resp = qmp_dispatch(&session, req);
     assert(resp != NULL);
     assert(qdict_haskey(resp, "error"));
 
     QDECREF(resp);
     QDECREF(req);
+    qmp_session_destroy(&session);
 }
 
 static void test_dispatch_cmd_success_response(void)
 {
+    QmpSession session = { 0, };
     QDict *resp, *req = qdict_new();
 
+    qmp_session_init(&session, &qmp_commands);
     qdict_put_str(req, "execute", "cmd-success-response");
-    resp = qmp_dispatch(&qmp_commands, req);
+    resp = qmp_dispatch(&session, req);
     assert(resp == NULL);
     QDECREF(req);
+    qmp_session_destroy(&session);
 }
 
+
 static QObject *test_qmp_dispatch(QDict *req)
 {
+    QmpSession session = { 0, };
     QDict *resp;
     QObject *ret;
 
-    resp = qmp_dispatch(&qmp_commands, req);
+    qmp_session_init(&session, &qmp_commands);
+    resp = qmp_dispatch(&session, req);
     assert(resp && !qdict_haskey(resp, "error"));
     ret = qdict_get(resp, "return");
     assert(ret);
     qobject_incref(ret);
     QDECREF(resp);
+    qmp_session_destroy(&session);
     return ret;
 }
 
@@ -279,18 +292,21 @@ static void test_dealloc_partial(void)
 
 static void test_dispatch_cmd_id(void)
 {
+    QmpSession session = { 0, };
     QDict *resp, *req = qdict_new();
 
+    qmp_session_init(&session, &qmp_commands);
     qdict_put_str(req, "execute", "user_def_cmd");
     qdict_put_str(req, "id", "ID42");
 
-    resp = qmp_dispatch(&qmp_commands, req);
+    resp = qmp_dispatch(&session, req);
     assert(resp != NULL);
     assert(!qdict_haskey(resp, "error"));
     assert(!strcmp(qdict_get_str(resp, "id"), "ID42"));
 
     QDECREF(resp);
     QDECREF(req);
+    qmp_session_destroy(&session);
 }
 
 
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 19/38] QmpSession: add a return_cb
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (17 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 18/38] qmp: add QmpSession Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 20/38] QmpSession: add json parser and use it in qga Marc-André Lureau
                   ` (24 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

The introduced return_cb will allow to delay finishing the dispatch
and sending the response asynchronously. For now, this is just
modifying qmp_dispatch() to call the callback synchronously, and
return void.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  8 +++-
 monitor.c                   | 52 +++++++++++-----------
 qapi/qmp-dispatch.c         | 19 ++++++--
 qga/main.c                  | 25 ++++++-----
 tests/test-qmp-cmds.c       | 86 ++++++++++++++++++-------------------
 5 files changed, 101 insertions(+), 89 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 10ba0745c7..7bf0b6a437 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -37,8 +37,10 @@ typedef struct QmpCommand
 typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
 typedef struct QmpSession QmpSession;
+typedef void (QmpDispatchReturn) (QmpSession *session, QDict *rsp);
 
 struct QmpSession {
+    QmpDispatchReturn *return_cb;
     QmpCommandList *cmds;
 };
 
@@ -46,9 +48,11 @@ void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
-void qmp_session_init(QmpSession *session, QmpCommandList *cmds);
+void qmp_session_init(QmpSession *session,
+                      QmpCommandList *cmds, QmpDispatchReturn *return_cb);
+
 void qmp_session_destroy(QmpSession *session);
-QDict *qmp_dispatch(QmpSession *session, QDict *request);
+void qmp_dispatch(QmpSession *session, QDict *request);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
 void qmp_enable_command(QmpCommandList *cmds, const char *name);
 
diff --git a/monitor.c b/monitor.c
index b90f8566c8..93ecb03d04 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3900,23 +3900,6 @@ static int monitor_can_read(void *opaque)
     return !atomic_mb_read(&mon->suspend_cnt);
 }
 
-/* take the ownership of rsp */
-static void monitor_qmp_respond(Monitor *mon, QDict *rsp)
-{
-    if (mon->qmp.session.cmds == &qmp_cap_negotiation_commands) {
-        QDict *qdict = qdict_get_qdict(rsp, "error");
-        if (qdict
-            && !g_strcmp0(qdict_get_try_str(qdict, "class"),
-                          QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
-            /* Provide a more useful error message */
-            qdict_put_str(qdict, "desc", "Expecting capabilities"
-                          " negotiation with 'qmp_capabilities'");
-        }
-    }
-    monitor_json_emitter(mon, QOBJECT(rsp));
-    QDECREF(rsp);
-}
-
 struct QMPRequest {
     /* Owner of the request */
     Monitor *mon;
@@ -3927,6 +3910,24 @@ struct QMPRequest {
 };
 typedef struct QMPRequest QMPRequest;
 
+static void dispatch_return_cb(QmpSession *session, QDict *rsp)
+{
+    Monitor *mon = container_of(session, Monitor, qmp.session);
+
+    if (mon->qmp.session.cmds == &qmp_cap_negotiation_commands) {
+        QDict *qdict = qdict = qdict_get_qdict(rsp, "error");
+        if (qdict
+            && !g_strcmp0(qdict_get_try_str(qdict, "class"),
+                    QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
+            /* Provide a more useful error message */
+            qdict_put_str(qdict, "desc", "Expecting capabilities negotiation"
+                          " with 'qmp_capabilities'");
+        }
+    }
+
+    monitor_json_emitter(mon, QOBJECT(rsp));
+}
+
 /*
  * Dispatch one single QMP request. The function will free the req_obj
  * and objects inside it before return.
@@ -3934,7 +3935,7 @@ typedef struct QMPRequest QMPRequest;
 static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 {
     Monitor *mon, *old_mon;
-    QDict *req, *rsp = NULL;
+    QDict *req;
 
     req = req_obj->req;
     mon = req_obj->mon;
@@ -3950,16 +3951,9 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
     old_mon = cur_mon;
     cur_mon = mon;
 
-    rsp = qmp_dispatch(&mon->qmp.session, req);
+    qmp_dispatch(&mon->qmp.session, req);
 
     cur_mon = old_mon;
-
-    /* Respond if necessary */
-    if (rsp) {
-        monitor_qmp_respond(mon, rsp);
-    }
-
-
     QDECREF(req);
 }
 
@@ -4107,7 +4101,8 @@ err:
     qdict = qdict_new();
     qdict_put_obj(qdict, "error", qmp_build_error_object(err));
     error_free(err);
-    monitor_qmp_respond(mon, qdict);
+    monitor_json_emitter(mon, QOBJECT(qdict));
+    QDECREF(qdict);
     qobject_decref(req);
 }
 
@@ -4223,7 +4218,8 @@ static void monitor_qmp_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_OPENED:
-        qmp_session_init(&mon->qmp.session, &qmp_cap_negotiation_commands);
+        qmp_session_init(&mon->qmp.session,
+                         &qmp_cap_negotiation_commands, dispatch_return_cb);
         monitor_qmp_caps_reset(mon);
         data = get_qmp_greeting(mon);
         monitor_json_emitter(mon, data);
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 7fd4e41b26..5274aa59cc 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -146,17 +146,27 @@ bool qmp_is_oob(const QDict *dict)
     return qbool_get_bool(bool_obj);
 }
 
-void qmp_session_init(QmpSession *session, QmpCommandList *cmds)
+void qmp_session_init(QmpSession *session,
+                      QmpCommandList *cmds, QmpDispatchReturn *return_cb)
 {
+    assert(return_cb);
+    assert(!session->return_cb);
+
     session->cmds = cmds;
+    session->return_cb = return_cb;
 }
 
 void qmp_session_destroy(QmpSession *session)
 {
+    if (!session->return_cb) {
+        return;
+    }
+
     session->cmds = NULL;
+    session->return_cb = NULL;
 }
 
-QDict *qmp_dispatch(QmpSession *session, QDict *req)
+void qmp_dispatch(QmpSession *session, QDict *req)
 {
     Error *err = NULL;
     QObject *ret;
@@ -177,8 +187,9 @@ QDict *qmp_dispatch(QmpSession *session, QDict *req)
         qdict_put_obj(rsp, "return", ret);
     } else {
         QDECREF(rsp);
-        return NULL;
+        return;
     }
 
-    return rsp;
+    session->return_cb(session, rsp);
+    QDECREF(rsp);
 }
diff --git a/qga/main.c b/qga/main.c
index b5d7cc9e8f..46349395ba 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -580,14 +580,22 @@ static int send_response(GAState *s, QObject *payload)
     return 0;
 }
 
+static void dispatch_return_cb(QmpSession *session, QDict *rsp)
+{
+    GAState *s = container_of(session, GAState, session);
+    int ret = send_response(s, QOBJECT(rsp));
+    if (ret < 0) {
+        g_warning("error sending response: %s", strerror(-ret));
+    }
+}
+
 /* handle requests/control events coming in over the channel */
 static void process_event(JSONMessageParser *parser, GQueue *tokens)
 {
     GAState *s = container_of(parser, GAState, parser);
     QObject *obj;
-    QDict *req, *rsp = NULL;
+    QDict *req;
     Error *err = NULL;
-    int ret;
 
     g_assert(s && parser);
 
@@ -604,19 +612,14 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens)
     }
 
     g_debug("processing command");
-    rsp = qmp_dispatch(&s->session, req);
+    qmp_dispatch(&s->session, req);
 
 end:
     if (err) {
-        rsp = qdict_new();
+        QDict *rsp = qdict_new();
         qdict_put_obj(rsp, "error", qmp_build_error_object(err));
         error_free(err);
-    }
-    if (rsp) {
-        ret = send_response(s, QOBJECT(rsp));
-        if (ret < 0) {
-            g_warning("error sending error response: %s", strerror(-ret));
-        }
+        dispatch_return_cb(&s->session, rsp);
         QDECREF(rsp);
     }
     qobject_decref(obj);
@@ -1305,7 +1308,7 @@ static int run_agent(GAState *s, GAConfig *config, int socket_activation)
     ga_command_state_init(s, s->command_state);
     ga_command_state_init_all(s->command_state);
     json_message_parser_init(&s->parser, process_event);
-    qmp_session_init(&s->session, &ga_commands);
+    qmp_session_init(&s->session, &ga_commands, dispatch_return_cb);
 #ifndef _WIN32
     if (!register_signal_handlers()) {
         g_critical("failed to register signal handlers");
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 0c1fecb281..5e6e75b133 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -93,85 +93,83 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
     return ret;
 }
 
+static void dispatch_cmd_return(QmpSession *session, QDict *resp)
+{
+    assert(resp != NULL);
+    assert(!qdict_haskey(resp, "error"));
+}
 
 /* test commands with no input and no return value */
 static void test_dispatch_cmd(void)
 {
     QmpSession session = { 0, };
-    QDict *resp, *req = qdict_new();
+    QDict *req = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands);
+    qmp_session_init(&session, &qmp_commands, dispatch_cmd_return);
     qdict_put_str(req, "execute", "user_def_cmd");
-
-    resp = qmp_dispatch(&session, req);
-    assert(resp != NULL);
-    assert(!qdict_haskey(resp, "error"));
-
-    QDECREF(resp);
+    qmp_dispatch(&session, req);
     QDECREF(req);
     qmp_session_destroy(&session);
 }
 
+static void dispatch_cmd_failure_return(QmpSession *session, QDict *resp)
+{
+    assert(resp != NULL);
+    assert(qdict_haskey(resp, "error"));
+}
+
 /* test commands that return an error due to invalid parameters */
 static void test_dispatch_cmd_failure(void)
 {
     QmpSession session = { 0, };
     QDict *req = qdict_new();
-    QDict *resp, *args = qdict_new();
+    QDict *args = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands);
+    qmp_session_init(&session, &qmp_commands, dispatch_cmd_failure_return);
     qdict_put_str(req, "execute", "user_def_cmd2");
-
-    resp = qmp_dispatch(&session, req);
-    assert(resp != NULL);
-    assert(qdict_haskey(resp, "error"));
-
-    QDECREF(resp);
+    qmp_dispatch(&session, req);
     QDECREF(req);
 
     /* check that with extra arguments it throws an error */
     req = qdict_new();
     qdict_put_int(args, "a", 66);
     qdict_put(req, "arguments", args);
-
     qdict_put_str(req, "execute", "user_def_cmd");
-
-    resp = qmp_dispatch(&session, req);
-    assert(resp != NULL);
-    assert(qdict_haskey(resp, "error"));
-
-    QDECREF(resp);
+    qmp_dispatch(&session, req);
     QDECREF(req);
     qmp_session_destroy(&session);
 }
 
+static QObject *dispatch_ret;
+
 static void test_dispatch_cmd_success_response(void)
 {
     QmpSession session = { 0, };
-    QDict *resp, *req = qdict_new();
+    QDict *req = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands);
+    qmp_session_init(&session, &qmp_commands, (QmpDispatchReturn *)abort);
     qdict_put_str(req, "execute", "cmd-success-response");
-    resp = qmp_dispatch(&session, req);
-    assert(resp == NULL);
+    qmp_dispatch(&session, req);
     QDECREF(req);
     qmp_session_destroy(&session);
 }
 
+static void dispatch_return(QmpSession *session, QDict *resp)
+{
+    assert(resp && !qdict_haskey(resp, "error"));
+    dispatch_ret = qdict_get(resp, "return");
+    qobject_incref(dispatch_ret);
+}
 
 static QObject *test_qmp_dispatch(QDict *req)
 {
     QmpSession session = { 0, };
-    QDict *resp;
     QObject *ret;
 
-    qmp_session_init(&session, &qmp_commands);
-    resp = qmp_dispatch(&session, req);
-    assert(resp && !qdict_haskey(resp, "error"));
-    ret = qdict_get(resp, "return");
-    assert(ret);
-    qobject_incref(ret);
-    QDECREF(resp);
+    qmp_session_init(&session, &qmp_commands, dispatch_return);
+    qmp_dispatch(&session, req);
+    ret = dispatch_ret;
+    dispatch_ret = NULL;
     qmp_session_destroy(&session);
     return ret;
 }
@@ -290,21 +288,21 @@ static void test_dealloc_partial(void)
     qapi_free_UserDefTwo(ud2);
 }
 
+static void dispatch_return_id42(QmpSession *session, QDict *resp)
+{
+    assert(!qdict_haskey(resp, "error"));
+    assert(!strcmp(qdict_get_str(resp, "id"), "ID42"));
+}
+
 static void test_dispatch_cmd_id(void)
 {
     QmpSession session = { 0, };
-    QDict *resp, *req = qdict_new();
+    QDict *req = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands);
+    qmp_session_init(&session, &qmp_commands, dispatch_return_id42);
     qdict_put_str(req, "execute", "user_def_cmd");
     qdict_put_str(req, "id", "ID42");
-
-    resp = qmp_dispatch(&session, req);
-    assert(resp != NULL);
-    assert(!qdict_haskey(resp, "error"));
-    assert(!strcmp(qdict_get_str(resp, "id"), "ID42"));
-
-    QDECREF(resp);
+    qmp_dispatch(&session, req);
     QDECREF(req);
     qmp_session_destroy(&session);
 }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 20/38] QmpSession: add json parser and use it in qga
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (18 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 19/38] QmpSession: add a return_cb Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 21/38] QmpSession: add a dispatch callback Marc-André Lureau
                   ` (23 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Move JSON parser to QmpSession, and implement a simple handler to check
the parsed tokens and call qmp_dispatch(). This is enough for a simple
QMP client, like QGA.

The QEMU monitor has more complicated handling of dispatching which
will be adressed in following patch to benefit more common code.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  9 ++++++++
 monitor.c                   |  7 ++-----
 qapi/qmp-dispatch.c         | 32 +++++++++++++++++++++++++++++
 qga/main.c                  | 41 +------------------------------------
 4 files changed, 44 insertions(+), 45 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 7bf0b6a437..cd425b8574 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -15,6 +15,7 @@
 #define QAPI_QMP_DISPATCH_H
 
 #include "qemu/queue.h"
+#include "qapi/qmp/json-streamer.h"
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
@@ -40,6 +41,7 @@ typedef struct QmpSession QmpSession;
 typedef void (QmpDispatchReturn) (QmpSession *session, QDict *rsp);
 
 struct QmpSession {
+    JSONMessageParser parser;
     QmpDispatchReturn *return_cb;
     QmpCommandList *cmds;
 };
@@ -48,9 +50,16 @@ void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
+
 void qmp_session_init(QmpSession *session,
                       QmpCommandList *cmds, QmpDispatchReturn *return_cb);
 
+static inline void
+qmp_session_feed(QmpSession *session, const char *buf, size_t count)
+{
+    json_message_parser_feed(&session->parser, buf, count);
+}
+
 void qmp_session_destroy(QmpSession *session);
 void qmp_dispatch(QmpSession *session, QDict *request);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
diff --git a/monitor.c b/monitor.c
index 93ecb03d04..66046d4854 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3934,11 +3934,8 @@ static void dispatch_return_cb(QmpSession *session, QDict *rsp)
  */
 static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
 {
-    Monitor *mon, *old_mon;
-    QDict *req;
-
-    req = req_obj->req;
-    mon = req_obj->mon;
+    Monitor *old_mon, *mon = req_obj->mon;
+    QDict *req = req_obj->req;
 
     g_free(req_obj);
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 5274aa59cc..5352b25e90 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -146,12 +146,43 @@ bool qmp_is_oob(const QDict *dict)
     return qbool_get_bool(bool_obj);
 }
 
+static void qmp_json_parser_emit(JSONMessageParser *parser, GQueue *tokens)
+{
+    QmpSession *session = container_of(parser, QmpSession, parser);
+    QObject *obj;
+    QDict *req;
+    Error *err = NULL;
+
+    obj = json_parser_parse_err(tokens, NULL, &err);
+    if (err) {
+        goto end;
+    }
+
+    req = qmp_dispatch_check_obj(obj, &err);
+    if (err) {
+        goto end;
+    }
+
+    qmp_dispatch(session, req);
+
+end:
+    if (err) {
+        QDict *rsp = qdict_new();
+        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
+        error_free(err);
+        session->return_cb(session, rsp);
+        QDECREF(rsp);
+    }
+    qobject_decref(obj);
+}
+
 void qmp_session_init(QmpSession *session,
                       QmpCommandList *cmds, QmpDispatchReturn *return_cb)
 {
     assert(return_cb);
     assert(!session->return_cb);
 
+    json_message_parser_init(&session->parser, qmp_json_parser_emit);
     session->cmds = cmds;
     session->return_cb = return_cb;
 }
@@ -164,6 +195,7 @@ void qmp_session_destroy(QmpSession *session)
 
     session->cmds = NULL;
     session->return_cb = NULL;
+    json_message_parser_destroy(&session->parser);
 }
 
 void qmp_dispatch(QmpSession *session, QDict *req)
diff --git a/qga/main.c b/qga/main.c
index 46349395ba..ce7efff3b4 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -72,7 +72,6 @@ typedef struct GAPersistentState {
 
 struct GAState {
     QmpSession session;
-    JSONMessageParser parser;
     GMainLoop *main_loop;
     GAChannel *channel;
     bool virtio; /* fastpath to check for virtio to deal with poll() quirks */
@@ -589,42 +588,6 @@ static void dispatch_return_cb(QmpSession *session, QDict *rsp)
     }
 }
 
-/* handle requests/control events coming in over the channel */
-static void process_event(JSONMessageParser *parser, GQueue *tokens)
-{
-    GAState *s = container_of(parser, GAState, parser);
-    QObject *obj;
-    QDict *req;
-    Error *err = NULL;
-
-    g_assert(s && parser);
-
-    g_debug("process_event: called");
-
-    obj = json_parser_parse_err(tokens, NULL, &err);
-    if (err) {
-        goto end;
-    }
-
-    req = qmp_dispatch_check_obj(obj, &err);
-    if (err) {
-        goto end;
-    }
-
-    g_debug("processing command");
-    qmp_dispatch(&s->session, req);
-
-end:
-    if (err) {
-        QDict *rsp = qdict_new();
-        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
-        error_free(err);
-        dispatch_return_cb(&s->session, rsp);
-        QDECREF(rsp);
-    }
-    qobject_decref(obj);
-}
-
 /* false return signals GAChannel to close the current client connection */
 static gboolean channel_event_cb(GIOCondition condition, gpointer data)
 {
@@ -639,7 +602,7 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data)
     case G_IO_STATUS_NORMAL:
         buf[count] = 0;
         g_debug("read data, count: %d, data: %s", (int)count, buf);
-        json_message_parser_feed(&s->parser, (char *)buf, (int)count);
+        qmp_session_feed(&s->session, buf, count);
         break;
     case G_IO_STATUS_EOF:
         g_debug("received EOF");
@@ -1307,7 +1270,6 @@ static int run_agent(GAState *s, GAConfig *config, int socket_activation)
     s->command_state = ga_command_state_new();
     ga_command_state_init(s, s->command_state);
     ga_command_state_init_all(s->command_state);
-    json_message_parser_init(&s->parser, process_event);
     qmp_session_init(&s->session, &ga_commands, dispatch_return_cb);
 #ifndef _WIN32
     if (!register_signal_handlers()) {
@@ -1431,7 +1393,6 @@ end:
         qmp_session_destroy(&s->session);
         ga_command_state_cleanup_all(s->command_state);
         ga_command_state_free(s->command_state);
-        json_message_parser_destroy(&s->parser);
     }
     if (s->channel) {
         ga_channel_free(s->channel);
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 21/38] QmpSession: add a dispatch callback
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (19 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 20/38] QmpSession: add json parser and use it in qga Marc-André Lureau
@ 2018-03-26 15:08 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 22/38] monitor: use QmpSession parsing and common dispatch code Marc-André Lureau
                   ` (22 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

In order to accomodate for QEMU monitor needs, allow to customize
dispatching after JSON parsing. The default (for QGA and tests) can be
simply qmp_dispatch().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  6 +++++-
 monitor.c                   |  4 +++-
 qapi/qmp-dispatch.c         |  8 ++++++--
 qga/main.c                  |  2 +-
 tests/test-qmp-cmds.c       | 12 +++++++-----
 5 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index cd425b8574..5329d0052a 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -38,10 +38,12 @@ typedef struct QmpCommand
 typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
 typedef struct QmpSession QmpSession;
+typedef void (QmpDispatch) (QmpSession *session, QDict *request);
 typedef void (QmpDispatchReturn) (QmpSession *session, QDict *rsp);
 
 struct QmpSession {
     JSONMessageParser parser;
+    QmpDispatch *dispatch_cb;
     QmpDispatchReturn *return_cb;
     QmpCommandList *cmds;
 };
@@ -52,7 +54,9 @@ void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
 
 void qmp_session_init(QmpSession *session,
-                      QmpCommandList *cmds, QmpDispatchReturn *return_cb);
+                     QmpCommandList *cmds,
+                     QmpDispatch *dispatch_cb,
+                     QmpDispatchReturn *return_cb);
 
 static inline void
 qmp_session_feed(QmpSession *session, const char *buf, size_t count)
diff --git a/monitor.c b/monitor.c
index 66046d4854..ae8c055df0 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4216,7 +4216,9 @@ static void monitor_qmp_event(void *opaque, int event)
     switch (event) {
     case CHR_EVENT_OPENED:
         qmp_session_init(&mon->qmp.session,
-                         &qmp_cap_negotiation_commands, dispatch_return_cb);
+                         &qmp_cap_negotiation_commands,
+                         NULL, /* XXX: not in use yet, but in following patch */
+                         dispatch_return_cb);
         monitor_qmp_caps_reset(mon);
         data = get_qmp_greeting(mon);
         monitor_json_emitter(mon, data);
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 5352b25e90..53d099d303 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -163,7 +163,7 @@ static void qmp_json_parser_emit(JSONMessageParser *parser, GQueue *tokens)
         goto end;
     }
 
-    qmp_dispatch(session, req);
+    session->dispatch_cb(session, req);
 
 end:
     if (err) {
@@ -177,13 +177,16 @@ end:
 }
 
 void qmp_session_init(QmpSession *session,
-                      QmpCommandList *cmds, QmpDispatchReturn *return_cb)
+                      QmpCommandList *cmds,
+                      QmpDispatch *dispatch_cb,
+                      QmpDispatchReturn *return_cb)
 {
     assert(return_cb);
     assert(!session->return_cb);
 
     json_message_parser_init(&session->parser, qmp_json_parser_emit);
     session->cmds = cmds;
+    session->dispatch_cb = dispatch_cb;
     session->return_cb = return_cb;
 }
 
@@ -194,6 +197,7 @@ void qmp_session_destroy(QmpSession *session)
     }
 
     session->cmds = NULL;
+    session->dispatch_cb = NULL;
     session->return_cb = NULL;
     json_message_parser_destroy(&session->parser);
 }
diff --git a/qga/main.c b/qga/main.c
index ce7efff3b4..dbb8f2cbbe 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1270,7 +1270,7 @@ static int run_agent(GAState *s, GAConfig *config, int socket_activation)
     s->command_state = ga_command_state_new();
     ga_command_state_init(s, s->command_state);
     ga_command_state_init_all(s->command_state);
-    qmp_session_init(&s->session, &ga_commands, dispatch_return_cb);
+    qmp_session_init(&s->session, &ga_commands, qmp_dispatch, dispatch_return_cb);
 #ifndef _WIN32
     if (!register_signal_handlers()) {
         g_critical("failed to register signal handlers");
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 5e6e75b133..5246650f71 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -105,7 +105,7 @@ static void test_dispatch_cmd(void)
     QmpSession session = { 0, };
     QDict *req = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands, dispatch_cmd_return);
+    qmp_session_init(&session, &qmp_commands, qmp_dispatch, dispatch_cmd_return);
     qdict_put_str(req, "execute", "user_def_cmd");
     qmp_dispatch(&session, req);
     QDECREF(req);
@@ -125,7 +125,8 @@ static void test_dispatch_cmd_failure(void)
     QDict *req = qdict_new();
     QDict *args = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands, dispatch_cmd_failure_return);
+    qmp_session_init(&session, &qmp_commands, qmp_dispatch,
+                     dispatch_cmd_failure_return);
     qdict_put_str(req, "execute", "user_def_cmd2");
     qmp_dispatch(&session, req);
     QDECREF(req);
@@ -147,7 +148,8 @@ static void test_dispatch_cmd_success_response(void)
     QmpSession session = { 0, };
     QDict *req = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands, (QmpDispatchReturn *)abort);
+    qmp_session_init(&session, &qmp_commands, qmp_dispatch,
+                     (QmpDispatchReturn *)abort);
     qdict_put_str(req, "execute", "cmd-success-response");
     qmp_dispatch(&session, req);
     QDECREF(req);
@@ -166,7 +168,7 @@ static QObject *test_qmp_dispatch(QDict *req)
     QmpSession session = { 0, };
     QObject *ret;
 
-    qmp_session_init(&session, &qmp_commands, dispatch_return);
+    qmp_session_init(&session, &qmp_commands, qmp_dispatch, dispatch_return);
     qmp_dispatch(&session, req);
     ret = dispatch_ret;
     dispatch_ret = NULL;
@@ -299,7 +301,7 @@ static void test_dispatch_cmd_id(void)
     QmpSession session = { 0, };
     QDict *req = qdict_new();
 
-    qmp_session_init(&session, &qmp_commands, dispatch_return_id42);
+    qmp_session_init(&session, &qmp_commands, qmp_dispatch, dispatch_return_id42);
     qdict_put_str(req, "execute", "user_def_cmd");
     qdict_put_str(req, "id", "ID42");
     qmp_dispatch(&session, req);
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 22/38] monitor: use QmpSession parsing and common dispatch code
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (20 preceding siblings ...)
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 21/38] QmpSession: add a dispatch callback Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 23/38] QmpSession: introduce QmpReturn Marc-André Lureau
                   ` (21 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

The previous patch allow to factorize some code out of monitor, and
reuse the JSON parsing in QmpSession.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 50 ++++++++++++++++----------------------------------
 1 file changed, 16 insertions(+), 34 deletions(-)

diff --git a/monitor.c b/monitor.c
index ae8c055df0..94ad366c2d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -58,8 +58,6 @@
 #include "qapi/qmp/qnum.h"
 #include "qapi/qmp/qstring.h"
 #include "qapi/qmp/qjson.h"
-#include "qapi/qmp/json-streamer.h"
-#include "qapi/qmp/json-parser.h"
 #include "qapi/qmp/qlist.h"
 #include "qom/object_interfaces.h"
 #include "trace-root.h"
@@ -625,7 +623,6 @@ static void monitor_data_destroy(Monitor *mon)
     qemu_chr_fe_deinit(&mon->chr, false);
     if (monitor_is_qmp(mon)) {
         qmp_session_destroy(&mon->qmp.session);
-        json_message_parser_destroy(&mon->qmp.parser);
     }
     readline_free(mon->rs);
     QDECREF(mon->outbuf);
@@ -4011,32 +4008,20 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
 #define  QMP_REQ_QUEUE_LEN_MAX  (8)
 
-static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
+static void qmp_dispatch_cb(QmpSession *session, QDict *req)
 {
-    QObject *req, *id = NULL;
-    QDict *qdict = NULL;
-    MonitorQMP *mon_qmp = container_of(parser, MonitorQMP, parser);
-    Monitor *mon = container_of(mon_qmp, Monitor, qmp);
+    QDict *rsp;
+    QObject *id;
+    Monitor *mon = container_of(session, Monitor, qmp.session);
     Error *err = NULL;
     QMPRequest *req_obj;
 
-    req = json_parser_parse_err(tokens, NULL, &err);
-    if (err) {
-        goto err;
-    }
-
-    /* Check against the request in general layout */
-    qdict = qmp_dispatch_check_obj(req, &err);
-    if (!qdict) {
-        goto err;
-    }
-
     /* Check against OOB specific */
-    if (!qmp_cmd_oob_check(mon, qdict, &err)) {
+    if (!qmp_cmd_oob_check(mon, req, &err)) {
         goto err;
     }
 
-    id = qdict_get(qdict, "id");
+    id = qdict_get(req, "id");
 
     /* When OOB is enabled, the "id" field is mandatory. */
     if (qmp_oob_enabled(mon) && !id) {
@@ -4045,12 +4030,13 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
         goto err;
     }
 
+    QINCREF(req);
     req_obj = g_new0(QMPRequest, 1);
     req_obj->mon = mon;
     req_obj->id = id;
-    req_obj->req = qdict;
+    req_obj->req = req;
 
-    if (qmp_is_oob(qdict)) {
+    if (qmp_is_oob(req)) {
         /* Out-Of-Band (OOB) requests are executed directly in parser. */
         trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(req_obj->id)
                                           ?: "");
@@ -4076,7 +4062,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
             qapi_event_send_command_dropped(id,
                                             COMMAND_DROP_REASON_QUEUE_FULL,
                                             &error_abort);
-            qobject_decref(req);
+            QDECREF(req);
             g_free(req_obj);
             return;
         }
@@ -4095,19 +4081,18 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     return;
 
 err:
-    qdict = qdict_new();
-    qdict_put_obj(qdict, "error", qmp_build_error_object(err));
+    rsp = qdict_new();
+    qdict_put_obj(rsp, "error", qmp_build_error_object(err));
     error_free(err);
-    monitor_json_emitter(mon, QOBJECT(qdict));
-    QDECREF(qdict);
-    qobject_decref(req);
+    monitor_json_emitter(mon, QOBJECT(rsp));
+    QDECREF(rsp);
 }
 
 static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
 {
     Monitor *mon = opaque;
 
-    json_message_parser_feed(&mon->qmp.parser, (const char *) buf, size);
+    qmp_session_feed(&mon->qmp.session, (const char *) buf, size);
 }
 
 static void monitor_read(void *opaque, const uint8_t *buf, int size)
@@ -4217,7 +4202,7 @@ static void monitor_qmp_event(void *opaque, int event)
     case CHR_EVENT_OPENED:
         qmp_session_init(&mon->qmp.session,
                          &qmp_cap_negotiation_commands,
-                         NULL, /* XXX: not in use yet, but in following patch */
+                         qmp_dispatch_cb,
                          dispatch_return_cb);
         monitor_qmp_caps_reset(mon);
         data = get_qmp_greeting(mon);
@@ -4227,8 +4212,6 @@ static void monitor_qmp_event(void *opaque, int event)
         break;
     case CHR_EVENT_CLOSED:
         qmp_session_destroy(&mon->qmp.session);
-        json_message_parser_destroy(&mon->qmp.parser);
-        json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
         mon_refcount--;
         monitor_fdsets_cleanup();
         break;
@@ -4429,7 +4412,6 @@ void monitor_init(Chardev *chr, int flags)
 
     if (monitor_is_qmp(mon)) {
         qemu_chr_fe_set_echo(&mon->chr, true);
-        json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
         if (mon->use_io_thr) {
             /*
              * Make sure the old iowatch is gone.  It's possible when
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 23/38] QmpSession: introduce QmpReturn
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (21 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 22/38] monitor: use QmpSession parsing and common dispatch code Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 24/38] qmp: remove qmp_build_error_object() Marc-André Lureau
                   ` (20 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

QmpReturn and associated functions are used internally for synchronous
dispatch return for now. They will be used for returning in an
asynchronous way, by holding the pre-prepared response, and having
some bookkeeping in QmpSession.

They also help to factor out a bit of code preparing the json reply
and calling the return_cb.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h | 33 +++++++++++++++++++
 monitor.c                   |  7 +---
 qapi/qmp-dispatch.c         | 65 ++++++++++++++++++++++++-------------
 3 files changed, 76 insertions(+), 29 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 5329d0052a..7ca8ab17d9 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -17,6 +17,8 @@
 #include "qemu/queue.h"
 #include "qapi/qmp/json-streamer.h"
 
+typedef struct QmpReturn QmpReturn;
+
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
 typedef enum QmpCommandOptions
@@ -48,6 +50,37 @@ struct QmpSession {
     QmpCommandList *cmds;
 };
 
+struct QmpReturn {
+    QmpSession *session;
+    QDict *rsp;
+};
+
+/*
+ * @qmp_return_new:
+ *
+ * Allocates and initializes a QmpReturn.
+ */
+QmpReturn *qmp_return_new(QmpSession *session, const QDict *req);
+
+/*
+ * @qmp_return_free:
+ *
+ * Free a QmpReturn. This shouldn't be needed if you actually return
+ * with qmp_return{_error}.
+ */
+void qmp_return_free(QmpReturn *qret);
+
+/*
+ * @qmp_return{_error}:
+ *
+ * Construct the command reply, and call the
+ * return_cb() associated with the session.
+ *
+ * Finally, free the QmpReturn.
+ */
+void qmp_return(QmpReturn *qret, QObject *rsp);
+void qmp_return_error(QmpReturn *qret, Error *err);
+
 void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
diff --git a/monitor.c b/monitor.c
index 94ad366c2d..73a06d4156 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4010,7 +4010,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
 static void qmp_dispatch_cb(QmpSession *session, QDict *req)
 {
-    QDict *rsp;
     QObject *id;
     Monitor *mon = container_of(session, Monitor, qmp.session);
     Error *err = NULL;
@@ -4081,11 +4080,7 @@ static void qmp_dispatch_cb(QmpSession *session, QDict *req)
     return;
 
 err:
-    rsp = qdict_new();
-    qdict_put_obj(rsp, "error", qmp_build_error_object(err));
-    error_free(err);
-    monitor_json_emitter(mon, QOBJECT(rsp));
-    QDECREF(rsp);
+    qmp_return_error(qmp_return_new(session, req), err);
 }
 
 static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 53d099d303..7b57fa7987 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -19,6 +19,42 @@
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qbool.h"
 
+QmpReturn *qmp_return_new(QmpSession *session, const QDict *req)
+{
+    QmpReturn *qret = g_new0(QmpReturn, 1);
+    QObject *id = req ? qdict_get(req, "id") : NULL;
+
+    qret->session = session;
+    qret->rsp = qdict_new();
+    if (id) {
+        qobject_incref(id);
+        qdict_put_obj(qret->rsp, "id", id);
+    }
+
+    return qret;
+}
+
+void qmp_return_free(QmpReturn *qret)
+{
+    QDECREF(qret->rsp);
+    g_free(qret);
+}
+
+void qmp_return(QmpReturn *qret, QObject *rsp)
+{
+    qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new()));
+    qret->session->return_cb(qret->session, qret->rsp);
+    qmp_return_free(qret);
+}
+
+void qmp_return_error(QmpReturn *qret, Error *err)
+{
+    qdict_put_obj(qret->rsp, "error", qmp_build_error_object(err));
+    error_free(err);
+    qret->session->return_cb(qret->session, qret->rsp);
+    qmp_return_free(qret);
+}
+
 QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
 {
     const QDictEntry *ent;
@@ -150,7 +186,7 @@ static void qmp_json_parser_emit(JSONMessageParser *parser, GQueue *tokens)
 {
     QmpSession *session = container_of(parser, QmpSession, parser);
     QObject *obj;
-    QDict *req;
+    QDict *req = NULL;
     Error *err = NULL;
 
     obj = json_parser_parse_err(tokens, NULL, &err);
@@ -167,11 +203,7 @@ static void qmp_json_parser_emit(JSONMessageParser *parser, GQueue *tokens)
 
 end:
     if (err) {
-        QDict *rsp = qdict_new();
-        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
-        error_free(err);
-        session->return_cb(session, rsp);
-        QDECREF(rsp);
+        qmp_return_error(qmp_return_new(session, req), err);
     }
     qobject_decref(obj);
 }
@@ -204,28 +236,15 @@ void qmp_session_destroy(QmpSession *session)
 
 void qmp_dispatch(QmpSession *session, QDict *req)
 {
+    QmpReturn *qret = qmp_return_new(session, req);
     Error *err = NULL;
     QObject *ret;
-    QDict *rsp;
-    QObject *id = qdict_get(req, "id");
 
     ret = do_qmp_dispatch(session->cmds, req, &err);
-
-    rsp = qdict_new();
-    if (id) {
-        qobject_incref(id);
-        qdict_put_obj(rsp, "id", id);
-    }
     if (err) {
-        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
-        error_free(err);
+        assert(!ret);
+        qmp_return_error(qret, err);
     } else if (ret) {
-        qdict_put_obj(rsp, "return", ret);
-    } else {
-        QDECREF(rsp);
-        return;
+        qmp_return(qret, ret);
     }
-
-    session->return_cb(session, rsp);
-    QDECREF(rsp);
 }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 24/38] qmp: remove qmp_build_error_object()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (22 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 23/38] QmpSession: introduce QmpReturn Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf() Marc-André Lureau
                   ` (19 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Now that we have a single caller, we may as well fold the function.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  1 -
 qapi/qmp-dispatch.c         | 12 ++++--------
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 7ca8ab17d9..c5ac3bd41e 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -105,7 +105,6 @@ void qmp_enable_command(QmpCommandList *cmds, const char *name);
 bool qmp_command_is_enabled(const QmpCommand *cmd);
 const char *qmp_command_name(const QmpCommand *cmd);
 bool qmp_has_success_response(const QmpCommand *cmd);
-QObject *qmp_build_error_object(Error *err);
 QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp);
 bool qmp_is_oob(const QDict *dict);
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 7b57fa7987..c6089de616 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -49,7 +49,10 @@ void qmp_return(QmpReturn *qret, QObject *rsp)
 
 void qmp_return_error(QmpReturn *qret, Error *err)
 {
-    qdict_put_obj(qret->rsp, "error", qmp_build_error_object(err));
+    qdict_put_obj(qret->rsp, "error",
+                  qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
+                                     QapiErrorClass_str(error_get_class(err)),
+                                     error_get_pretty(err)));
     error_free(err);
     qret->session->return_cb(qret->session, qret->rsp);
     qmp_return_free(qret);
@@ -153,13 +156,6 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QDict *dict,
     return ret;
 }
 
-QObject *qmp_build_error_object(Error *err)
-{
-    return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
-                              QapiErrorClass_str(error_get_class(err)),
-                              error_get_pretty(err));
-}
-
 /*
  * Detect whether a request should be run out-of-band, by quickly
  * peeking at whether we have: { "control": { "run-oob": true } }. By
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (23 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 24/38] qmp: remove qmp_build_error_object() Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 26/38] qmp: fold do_qmp_dispatch() in qmp_dispatch() Marc-André Lureau
                   ` (18 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/qmp-dispatch.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index c6089de616..92079c0621 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -49,10 +49,11 @@ void qmp_return(QmpReturn *qret, QObject *rsp)
 
 void qmp_return_error(QmpReturn *qret, Error *err)
 {
-    qdict_put_obj(qret->rsp, "error",
-                  qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
-                                     QapiErrorClass_str(error_get_class(err)),
-                                     error_get_pretty(err)));
+    QDict *qdict = qdict_new();
+
+    qdict_put_str(qdict, "class", QapiErrorClass_str(error_get_class(err)));
+    qdict_put_str(qdict, "desc", error_get_pretty(err));
+    qdict_put_obj(qret->rsp, "error", QOBJECT(qdict));
     error_free(err);
     qret->session->return_cb(qret->session, qret->rsp);
     qmp_return_free(qret);
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 26/38] qmp: fold do_qmp_dispatch() in qmp_dispatch()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (24 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf() Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 27/38] QmpSession: keep a queue of pending commands Marc-André Lureau
                   ` (17 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

qmp_dispatch() is now a simple wrapper for do_qmp_dispatch(). In order
to prepare for following asynchronous function, merge the two
functions, which result in less code.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/qmp-dispatch.c | 62 ++++++++++++++++++---------------------------
 1 file changed, 25 insertions(+), 37 deletions(-)

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 92079c0621..4a73cf88b3 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -114,47 +114,50 @@ QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
     return dict;
 }
 
-static QObject *do_qmp_dispatch(QmpCommandList *cmds, QDict *dict,
-                                Error **errp)
+void qmp_dispatch(QmpSession *session, QDict *req)
 {
-    Error *local_err = NULL;
     const char *command;
-    QDict *args;
+    QDict *args = NULL;
     QmpCommand *cmd;
-    QObject *ret = NULL;
+    Error *err = NULL;
 
-    command = qdict_get_str(dict, "execute");
-    cmd = qmp_find_command(cmds, command);
+    command = qdict_get_str(req, "execute");
+    cmd = qmp_find_command(session->cmds, command);
     if (cmd == NULL) {
-        error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+        error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
                   "The command %s has not been found", command);
-        return NULL;
+        goto end;
     }
     if (!cmd->enabled) {
-        error_setg(errp, "The command %s has been disabled for this instance",
+        error_setg(&err, "The command %s has been disabled for this instance",
                    command);
-        return NULL;
+        goto end;
     }
 
-    if (!qdict_haskey(dict, "arguments")) {
+    if (!qdict_haskey(req, "arguments")) {
         args = qdict_new();
     } else {
-        args = qdict_get_qdict(dict, "arguments");
+        args = qdict_get_qdict(req, "arguments");
         QINCREF(args);
     }
 
-    cmd->fn(args, &ret, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-    } else if (cmd->options & QCO_NO_SUCCESS_RESP) {
-        g_assert(!ret);
-    } else if (!ret) {
-        ret = QOBJECT(qdict_new());
+    {
+        QObject *ret = NULL;
+        cmd->fn(args, &ret, &err);
+        if (err || cmd->options & QCO_NO_SUCCESS_RESP) {
+            assert(!ret);
+            goto end;
+        } else if (!ret) {
+            ret = QOBJECT(qdict_new());
+        }
+        qmp_return(qmp_return_new(session, req), ret);
     }
 
+end:
+    if (err) {
+        qmp_return_error(qmp_return_new(session, req), err);
+    }
     QDECREF(args);
-
-    return ret;
 }
 
 /*
@@ -230,18 +233,3 @@ void qmp_session_destroy(QmpSession *session)
     session->return_cb = NULL;
     json_message_parser_destroy(&session->parser);
 }
-
-void qmp_dispatch(QmpSession *session, QDict *req)
-{
-    QmpReturn *qret = qmp_return_new(session, req);
-    Error *err = NULL;
-    QObject *ret;
-
-    ret = do_qmp_dispatch(session->cmds, req, &err);
-    if (err) {
-        assert(!ret);
-        qmp_return_error(qret, err);
-    } else if (ret) {
-        qmp_return(qret, ret);
-    }
-}
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 27/38] QmpSession: keep a queue of pending commands
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (25 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 26/38] qmp: fold do_qmp_dispatch() in qmp_dispatch() Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 28/38] QmpSession: return orderly Marc-André Lureau
                   ` (16 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

The following commit will introduce asynchronous commands. Let's keep
the client aware of the pending commands, so we can do interesting
things like order the replies, or cancel pending operations when the
client is gone.

The queue needs a lock, since QmpSession may be used from multiple
threads.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  4 ++++
 qapi/qmp-dispatch.c         | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index c5ac3bd41e..94a272a5fb 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -15,6 +15,7 @@
 #define QAPI_QMP_DISPATCH_H
 
 #include "qemu/queue.h"
+#include "qemu/thread.h"
 #include "qapi/qmp/json-streamer.h"
 
 typedef struct QmpReturn QmpReturn;
@@ -48,11 +49,14 @@ struct QmpSession {
     QmpDispatch *dispatch_cb;
     QmpDispatchReturn *return_cb;
     QmpCommandList *cmds;
+    QemuMutex pending_lock;
+    QTAILQ_HEAD(, QmpReturn) pending;
 };
 
 struct QmpReturn {
     QmpSession *session;
     QDict *rsp;
+    QTAILQ_ENTRY(QmpReturn) entry;
 };
 
 /*
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 4a73cf88b3..2c162642cb 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -31,11 +31,24 @@ QmpReturn *qmp_return_new(QmpSession *session, const QDict *req)
         qdict_put_obj(qret->rsp, "id", id);
     }
 
+    qemu_mutex_lock(&session->pending_lock);
+    QTAILQ_INSERT_TAIL(&session->pending, qret, entry);
+    qemu_mutex_unlock(&session->pending_lock);
+
     return qret;
 }
 
 void qmp_return_free(QmpReturn *qret)
 {
+    QmpSession *session = qret->session;
+
+    if (session) {
+        qemu_mutex_lock(&session->pending_lock);
+    }
+    QTAILQ_REMOVE(&session->pending, qret, entry);
+    if (session) {
+        qemu_mutex_unlock(&session->pending_lock);
+    }
     QDECREF(qret->rsp);
     g_free(qret);
 }
@@ -43,7 +56,9 @@ void qmp_return_free(QmpReturn *qret)
 void qmp_return(QmpReturn *qret, QObject *rsp)
 {
     qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new()));
-    qret->session->return_cb(qret->session, qret->rsp);
+    if (qret->session) {
+        qret->session->return_cb(qret->session, qret->rsp);
+    }
     qmp_return_free(qret);
 }
 
@@ -55,7 +70,9 @@ void qmp_return_error(QmpReturn *qret, Error *err)
     qdict_put_str(qdict, "desc", error_get_pretty(err));
     qdict_put_obj(qret->rsp, "error", QOBJECT(qdict));
     error_free(err);
-    qret->session->return_cb(qret->session, qret->rsp);
+    if (qret->session) {
+        qret->session->return_cb(qret->session, qret->rsp);
+    }
     qmp_return_free(qret);
 }
 
@@ -220,16 +237,27 @@ void qmp_session_init(QmpSession *session,
     session->cmds = cmds;
     session->dispatch_cb = dispatch_cb;
     session->return_cb = return_cb;
+    qemu_mutex_init(&session->pending_lock);
+    QTAILQ_INIT(&session->pending);
 }
 
 void qmp_session_destroy(QmpSession *session)
 {
+    QmpReturn *ret, *next;
+
     if (!session->return_cb) {
         return;
     }
 
+    qemu_mutex_lock(&session->pending_lock);
+    QTAILQ_FOREACH_SAFE(ret, &session->pending, entry, next) {
+        ret->session = NULL;
+        QTAILQ_REMOVE(&session->pending, ret, entry);
+    }
+    qemu_mutex_unlock(&session->pending_lock);
     session->cmds = NULL;
     session->dispatch_cb = NULL;
     session->return_cb = NULL;
     json_message_parser_destroy(&session->parser);
+    qemu_mutex_destroy(&session->pending_lock);
 }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 28/38] QmpSession: return orderly
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (26 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 27/38] QmpSession: keep a queue of pending commands Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 29/38] qmp: introduce asynchronous command type Marc-André Lureau
                   ` (15 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

QEMU will gain support for asynchronous commands, and may thus finish
commands in various order. However, the clients expect replies in
order. Let's enforce ordering of replies in QmpReturn: starting from
the older command, process each pending QmpReturn, and return until
reaching one that is unfinished.

Or if the command is OOB, it should return immediately.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  1 +
 qapi/qmp-dispatch.c         | 59 ++++++++++++++++++++++++++++++-------
 tests/test-qmp-cmds.c       | 36 ++++++++++++++++++++++
 3 files changed, 85 insertions(+), 11 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 94a272a5fb..f6db06c164 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -56,6 +56,7 @@ struct QmpSession {
 struct QmpReturn {
     QmpSession *session;
     QDict *rsp;
+    bool oob;
     QTAILQ_ENTRY(QmpReturn) entry;
 };
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 2c162642cb..aa8b71a2c0 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -24,6 +24,7 @@ QmpReturn *qmp_return_new(QmpSession *session, const QDict *req)
     QmpReturn *qret = g_new0(QmpReturn, 1);
     QObject *id = req ? qdict_get(req, "id") : NULL;
 
+    qret->oob = req ? qmp_is_oob(req) : false;
     qret->session = session;
     qret->rsp = qdict_new();
     if (id) {
@@ -38,6 +39,15 @@ QmpReturn *qmp_return_new(QmpSession *session, const QDict *req)
     return qret;
 }
 
+static void qmp_return_free_with_lock(QmpReturn *qret)
+{
+    if (qret->session) {
+        QTAILQ_REMOVE(&qret->session->pending, qret, entry);
+    }
+    QDECREF(qret->rsp);
+    g_free(qret);
+}
+
 void qmp_return_free(QmpReturn *qret)
 {
     QmpSession *session = qret->session;
@@ -45,21 +55,51 @@ void qmp_return_free(QmpReturn *qret)
     if (session) {
         qemu_mutex_lock(&session->pending_lock);
     }
-    QTAILQ_REMOVE(&session->pending, qret, entry);
+
+    qmp_return_free_with_lock(qret);
+
     if (session) {
         qemu_mutex_unlock(&session->pending_lock);
     }
-    QDECREF(qret->rsp);
-    g_free(qret);
+}
+
+static void qmp_return_orderly(QmpReturn *qret)
+{
+    QmpSession *session = qret->session;
+    QmpReturn *ret, *next;
+
+    if (!session) {
+        /* the client was destroyed before return, discard */
+        qmp_return_free(qret);
+        return;
+    }
+    if (qret->oob) {
+        session->return_cb(session, qret->rsp);
+        qmp_return_free(qret);
+        return;
+    }
+
+    /* mark as finished */
+    qret->session = NULL;
+
+    qemu_mutex_lock(&session->pending_lock);
+    /* process the list of pending and return until reaching an unfinshed */
+    QTAILQ_FOREACH_SAFE(ret, &session->pending, entry, next) {
+        if (ret->session) {
+            goto end;
+        }
+        session->return_cb(session, ret->rsp);
+        ret->session = session;
+        qmp_return_free_with_lock(ret);
+    }
+end:
+    qemu_mutex_unlock(&session->pending_lock);
 }
 
 void qmp_return(QmpReturn *qret, QObject *rsp)
 {
     qdict_put_obj(qret->rsp, "return", rsp ?: QOBJECT(qdict_new()));
-    if (qret->session) {
-        qret->session->return_cb(qret->session, qret->rsp);
-    }
-    qmp_return_free(qret);
+    qmp_return_orderly(qret);
 }
 
 void qmp_return_error(QmpReturn *qret, Error *err)
@@ -70,10 +110,7 @@ void qmp_return_error(QmpReturn *qret, Error *err)
     qdict_put_str(qdict, "desc", error_get_pretty(err));
     qdict_put_obj(qret->rsp, "error", QOBJECT(qdict));
     error_free(err);
-    if (qret->session) {
-        qret->session->return_cb(qret->session, qret->rsp);
-    }
-    qmp_return_free(qret);
+    qmp_return_orderly(qret);
 }
 
 QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 5246650f71..eeaac03d50 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -309,6 +309,41 @@ static void test_dispatch_cmd_id(void)
     qmp_session_destroy(&session);
 }
 
+typedef struct QmpReturnOrderly {
+    QmpSession session;
+    int returns;
+} QmpReturnOrderly;
+
+static void dispatch_return_orderly(QmpSession *session, QDict *resp)
+{
+    QmpReturnOrderly *o = container_of(session, QmpReturnOrderly, session);
+
+    o->returns++;
+}
+
+static void test_qmp_return_orderly(void)
+{
+    QDict *dict = qdict_new();
+    QDict *ctrl = qdict_new();
+    QmpReturnOrderly o = { 0, };
+    QmpReturn *r1, *r2, *r3;
+
+    qmp_session_init(&o.session, &qmp_commands,
+                     qmp_dispatch, dispatch_return_orderly);
+    r1 = qmp_return_new(&o.session, NULL);
+    qdict_put_bool(ctrl, "run-oob", true);
+    qdict_put_obj(dict, "control", QOBJECT(ctrl));
+    r2 = qmp_return_new(&o.session, dict);
+    r3 = qmp_return_new(&o.session, NULL);
+    qmp_return(r3, NULL);
+    g_assert_cmpint(o.returns, ==, 0);
+    qmp_return(r2, NULL);
+    g_assert_cmpint(o.returns, ==, 1);
+    qmp_return(r1, NULL);
+    g_assert_cmpint(o.returns, ==, 3);
+    qmp_session_destroy(&o.session);
+    QDECREF(dict);
+}
 
 int main(int argc, char **argv)
 {
@@ -322,6 +357,7 @@ int main(int argc, char **argv)
     g_test_add_func("/qmp/dispatch_cmd_id", test_dispatch_cmd_id);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
     g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
+    g_test_add_func("/qmp/return_orderly", test_qmp_return_orderly);
 
     test_qmp_init_marshal(&qmp_commands);
     g_test_run();
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 29/38] qmp: introduce asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (27 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 28/38] QmpSession: return orderly Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 30/38] scripts: learn 'async' qapi commands Marc-André Lureau
                   ` (14 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Add a new type of command, QmpCommandFuncAsync: those commands can
return later thanks to QmpReturn. This commit introduces the new type
and register function and teach qmp_dipatch() to call it without
qmp_return().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  9 ++++++++-
 qapi/qmp-dispatch.c         |  4 +++-
 qapi/qmp-registry.c         | 27 ++++++++++++++++++++++++---
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index f6db06c164..e426317346 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -21,18 +21,23 @@
 typedef struct QmpReturn QmpReturn;
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+typedef void (QmpCommandAsyncFunc)(QDict *, QmpReturn *);
 
 typedef enum QmpCommandOptions
 {
     QCO_NO_OPTIONS            =  0x0,
     QCO_NO_SUCCESS_RESP       =  (1U << 0),
     QCO_ALLOW_OOB             =  (1U << 1),
+    QCO_ASYNC                 =  (1U << 2),
 } QmpCommandOptions;
 
 typedef struct QmpCommand
 {
     const char *name;
-    QmpCommandFunc *fn;
+    union {
+        QmpCommandFunc *fn;
+        QmpCommandAsyncFunc *async_fn;
+    };
     QmpCommandOptions options;
     QTAILQ_ENTRY(QmpCommand) node;
     bool enabled;
@@ -88,6 +93,8 @@ void qmp_return_error(QmpReturn *qret, Error *err);
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
+void qmp_register_async_command(QmpCommandList *cmds, const char *name,
+                          QmpCommandAsyncFunc *fn, QmpCommandOptions options);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index aa8b71a2c0..f7d9931734 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -195,7 +195,9 @@ void qmp_dispatch(QmpSession *session, QDict *req)
         QINCREF(args);
     }
 
-    {
+    if (cmd->options & QCO_ASYNC) {
+        cmd->async_fn(args, qmp_return_new(session, req));
+    } else {
         QObject *ret = NULL;
         cmd->fn(args, &ret, &err);
         if (err || cmd->options & QCO_NO_SUCCESS_RESP) {
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index 5af484cd9a..180b1c1e69 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -15,16 +15,37 @@
 #include "qemu/osdep.h"
 #include "qapi/qmp/dispatch.h"
 
-void qmp_register_command(QmpCommandList *cmds, const char *name,
-                          QmpCommandFunc *fn, QmpCommandOptions options)
+
+static QmpCommand *qmp_command_new(QmpCommandList *cmds, const char *name,
+                                   QmpCommandOptions options)
 {
     QmpCommand *cmd = g_malloc0(sizeof(*cmd));
 
     cmd->name = name;
-    cmd->fn = fn;
     cmd->enabled = true;
     cmd->options = options;
     QTAILQ_INSERT_TAIL(cmds, cmd, node);
+
+    return cmd;
+}
+
+
+void qmp_register_command(QmpCommandList *cmds, const char *name,
+                          QmpCommandFunc *fn, QmpCommandOptions options)
+{
+    QmpCommand *cmd = qmp_command_new(cmds, name, options);
+
+    assert(!(options & QCO_ASYNC));
+    cmd->fn = fn;
+}
+
+void qmp_register_async_command(QmpCommandList *cmds, const char *name,
+                            QmpCommandAsyncFunc *fn, QmpCommandOptions options)
+{
+    QmpCommand *cmd = qmp_command_new(cmds, name, options);
+
+    assert(options & QCO_ASYNC);
+    cmd->async_fn = fn;
 }
 
 void qmp_unregister_command(QmpCommandList *cmds, const char *name)
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 30/38] scripts: learn 'async' qapi commands
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (28 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 29/38] qmp: introduce asynchronous command type Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 31/38] qmp: add qmp_return_is_cancelled() Marc-André Lureau
                   ` (13 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Commands with the 'async' key will be registered as async type (see
related commit), and will allow a synchronous (in scope callback) or
asynchronous return (when ready, in idle etc) by keeping the given
QmpReturn and calling qmp_return function later.

Ex:
  { 'command': 'foo-async,
    'data': {'arg': 'str'},
    'returns': 'Foo',
    'async': true }

generates the following marshaller:

void qmp_marshal_foo_async(QDict *args, QmpReturn *qret)
{
    Error *err = NULL;
    Visitor *v;
    q_obj_foo_async_arg arg = {0};

    v = qmp_input_visitor_new(QOBJECT(args), true);
    visit_start_struct(v, NULL, NULL, 0, &err);
    if (err) {
        goto out;
    }
    visit_type_q_obj_foo_async_arg_members(v, &arg, &err);
    if (!err) {
        visit_check_struct(v, &err);
    }
    visit_end_struct(v, NULL);
    if (err) {
        goto out;
    }

    qmp_foo_async(arg.arg, qret);

out:
    if (err) {
        qmp_return_error(qret, err);
    }
    visit_free(v);
    v = qapi_dealloc_visitor_new();
    visit_start_struct(v, NULL, NULL, 0, NULL);
    visit_type_q_obj_foo_async_arg_members(v, &arg, NULL);
    visit_end_struct(v, NULL);
    visit_free(v);
}

and return helper:

void qmp_foo_async_return(QmpReturn *qret, Foo *ret_in)
{
    Error *err = NULL;
    QObject *ret_out = NULL;

    qmp_marshal_output_Foo(ret_in, &ret_out, &err);

    if (err) {
        qmp_return_error(qret, err);
    } else {
        qmp_return(qret, ret_out);
    }
}

The dispatched function may call the return helper within the calling
scope or delay the return. To return an error, it should call
qmp_return_error().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi/commands.py                | 149 ++++++++++++++++++++----
 scripts/qapi/common.py                  |  12 +-
 scripts/qapi/doc.py                     |   2 +-
 scripts/qapi/introspect.py              |   2 +-
 tests/test-qmp-cmds.c                   |  60 ++++++++++
 tests/qapi-schema/qapi-schema-test.json |   5 +
 tests/qapi-schema/qapi-schema-test.out  |   8 ++
 tests/qapi-schema/test-qapi.py          |   7 +-
 8 files changed, 210 insertions(+), 35 deletions(-)
 mode change 100644 => 100755 scripts/qapi/doc.py

diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 0c5da3a54d..a292164169 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -16,18 +16,36 @@ See the COPYING file in the top-level directory.
 from qapi.common import *
 
 
-def gen_command_decl(name, arg_type, boxed, ret_type):
-    return mcgen('''
-%(c_type)s qmp_%(c_name)s(%(params)s);
+def gen_command_decl(name, arg_type, boxed, ret_type, success_response, async):
+    if async:
+        extra = "QmpReturn *qret"
+    else:
+        extra = 'Error **errp'
+
+    if async:
+        ret = mcgen('''
+void qmp_%(name)s(%(params)s);
 ''',
-                 c_type=(ret_type and ret_type.c_type()) or 'void',
-                 c_name=c_name(name),
-                 params=build_params(arg_type, boxed, 'Error **errp'))
+                     name=c_name(name),
+                     params=build_params(arg_type, boxed, extra))
+        if success_response:
+            ret += mcgen('''
+void qmp_%(name)s_return(QmpReturn *qret%(c_type)s);
+''',
+                        c_type=(", " + ret_type.c_type() if ret_type else ""),
+                        name=c_name(name))
 
+        return ret
+    else:
+        return mcgen('''
+%(c_type)s qmp_%(c_name)s(%(params)s);
+''',
+                     c_type=(ret_type and ret_type.c_type()) or 'void',
+                     c_name=c_name(name),
+                     params=build_params(arg_type, boxed, extra))
 
-def gen_call(name, arg_type, boxed, ret_type):
-    ret = ''
 
+def gen_argstr(arg_type, boxed):
     argstr = ''
     if boxed:
         assert arg_type and not arg_type.is_empty()
@@ -39,6 +57,13 @@ def gen_call(name, arg_type, boxed, ret_type):
                 argstr += 'arg.has_%s, ' % c_name(memb.name)
             argstr += 'arg.%s, ' % c_name(memb.name)
 
+    return argstr
+
+
+def gen_call(name, arg_type, boxed, ret_type):
+    ret = ''
+
+    argstr = gen_argstr(arg_type, boxed)
     lhs = ''
     if ret_type:
         lhs = 'retval = '
@@ -60,6 +85,50 @@ def gen_call(name, arg_type, boxed, ret_type):
     return ret
 
 
+def gen_async_call(name, arg_type, boxed):
+    argstr = gen_argstr(arg_type, boxed)
+
+    push_indent()
+    ret = mcgen('''
+
+qmp_%(c_name)s(%(args)sqret);
+''',
+                c_name=c_name(name), args=argstr)
+
+    pop_indent()
+    return ret
+
+
+def gen_async_return(name, ret_type):
+    if ret_type:
+        return mcgen('''
+
+void qmp_%(c_name)s_return(QmpReturn *qret, %(ret_type)s ret_in)
+{
+    Error *err = NULL;
+    QObject *ret_out = NULL;
+
+    qmp_marshal_output_%(ret_c_name)s(ret_in, &ret_out, &err);
+
+    if (err) {
+        qmp_return_error(qret, err);
+    } else {
+        qmp_return(qret, ret_out);
+    }
+}
+''',
+                     c_name=c_name(name),
+                     ret_type=ret_type.c_type(), ret_c_name=ret_type.c_name())
+    else:
+        return mcgen('''
+
+void qmp_%(c_name)s_return(QmpReturn *qret)
+{
+    qmp_return(qret, QOBJECT(qdict_new()));
+}
+''',
+                     c_name=c_name(name))
+
 def gen_marshal_output(ret_type):
     return mcgen('''
 
@@ -83,19 +152,22 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out,
                  c_type=ret_type.c_type(), c_name=ret_type.c_name())
 
 
-def build_marshal_proto(name):
-    return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
-            % c_name(name))
+def build_marshal_proto(name, async):
+    if async:
+        tmpl = 'void qmp_marshal_%s(QDict *args, QmpReturn *qret)'
+    else:
+        tmpl = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
+    return tmpl % c_name(name)
 
 
-def gen_marshal_decl(name):
+def gen_marshal_decl(name, async):
     return mcgen('''
 %(proto)s;
 ''',
-                 proto=build_marshal_proto(name))
+                 proto=build_marshal_proto(name, async))
 
 
-def gen_marshal(name, arg_type, boxed, ret_type):
+def gen_marshal(name, arg_type, boxed, ret_type, async):
     have_args = arg_type and not arg_type.is_empty()
 
     ret = mcgen('''
@@ -104,9 +176,9 @@ def gen_marshal(name, arg_type, boxed, ret_type):
 {
     Error *err = NULL;
 ''',
-                proto=build_marshal_proto(name))
+                proto=build_marshal_proto(name, async))
 
-    if ret_type:
+    if ret_type and not async:
         ret += mcgen('''
     %(c_type)s retval;
 ''',
@@ -153,12 +225,28 @@ def gen_marshal(name, arg_type, boxed, ret_type):
     }
 ''')
 
-    ret += gen_call(name, arg_type, boxed, ret_type)
+    if async:
+        ret += gen_async_call(name, arg_type, boxed)
+    else:
+        ret += gen_call(name, arg_type, boxed, ret_type)
 
     ret += mcgen('''
 
 out:
+''')
+
+    if async:
+         ret += mcgen('''
+    if (err) {
+        qmp_return_error(qret, err);
+    }
+''')
+    else:
+        ret += mcgen('''
     error_propagate(errp, err);
+''')
+
+    ret += mcgen('''
     visit_free(v);
 ''')
 
@@ -193,24 +281,31 @@ out:
     return ret
 
 
-def gen_register_command(name, success_response, allow_oob):
+def gen_register_command(name, success_response, allow_oob, async):
     options = []
 
     if not success_response:
         options += ['QCO_NO_SUCCESS_RESP']
     if allow_oob:
         options += ['QCO_ALLOW_OOB']
+    if async:
+        options += ['QCO_ASYNC']
 
     if not options:
         options = ['QCO_NO_OPTIONS']
 
     options = " | ".join(options)
 
+    if async:
+        regfn = 'qmp_register_async_command'
+    else:
+        regfn = 'qmp_register_command'
+
     ret = mcgen('''
-    qmp_register_command(cmds, "%(name)s",
+    %(regfn)s(cmds, "%(name)s",
                          qmp_marshal_%(c_name)s, %(opts)s);
 ''',
-                name=name, c_name=c_name(name),
+                regfn=regfn, name=name, c_name=c_name(name),
                 opts=options)
     return ret
 
@@ -276,16 +371,20 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
         genc.add(gen_registry(self._regy, self._prefix))
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed, allow_oob):
+                      gen, success_response, boxed, allow_oob, async):
         if not gen:
             return
-        self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
+        self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type,
+                                        success_response, async))
         if ret_type and ret_type not in self._visited_ret_types[self._genc]:
             self._visited_ret_types[self._genc].add(ret_type)
             self._genc.add(gen_marshal_output(ret_type))
-        self._genh.add(gen_marshal_decl(name))
-        self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
-        self._regy += gen_register_command(name, success_response, allow_oob)
+        if async and success_response:
+            self._genc.add(gen_async_return(name, ret_type))
+        self._genh.add(gen_marshal_decl(name, async))
+        self._genc.add(gen_marshal(name, arg_type, boxed, ret_type, async))
+        self._regy += gen_register_command(name, success_response,
+                                           allow_oob, async)
 
 
 def gen_commands(schema, output_dir, prefix):
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 2c05e3c284..109562ccb4 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -922,7 +922,7 @@ def check_exprs(exprs):
             meta = 'command'
             check_keys(expr_elem, 'command', [],
                        ['data', 'returns', 'gen', 'success-response',
-                        'boxed', 'allow-oob'])
+                        'boxed', 'allow-oob', 'async'])
         elif 'event' in expr:
             meta = 'event'
             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1045,7 +1045,7 @@ class QAPISchemaVisitor(object):
         pass
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed, allow_oob):
+                      gen, success_response, boxed, allow_oob, async):
         pass
 
     def visit_event(self, name, info, arg_type, boxed):
@@ -1422,7 +1422,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
 
 class QAPISchemaCommand(QAPISchemaEntity):
     def __init__(self, name, info, doc, arg_type, ret_type,
-                 gen, success_response, boxed, allow_oob):
+                 gen, success_response, boxed, allow_oob, async):
         QAPISchemaEntity.__init__(self, name, info, doc)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -1434,6 +1434,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.success_response = success_response
         self.boxed = boxed
         self.allow_oob = allow_oob
+        self.async = async
 
     def check(self, schema):
         if self._arg_type_name:
@@ -1458,7 +1459,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
                               self.gen, self.success_response,
-                              self.boxed, self.allow_oob)
+                              self.boxed, self.allow_oob, self.async)
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
@@ -1678,6 +1679,7 @@ class QAPISchema(object):
         success_response = expr.get('success-response', True)
         boxed = expr.get('boxed', False)
         allow_oob = expr.get('allow-oob', False)
+        async = expr.get('async', False)
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
                 name, info, doc, 'arg', self._make_members(data, info))
@@ -1686,7 +1688,7 @@ class QAPISchema(object):
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
                                            gen, success_response,
-                                           boxed, allow_oob))
+                                           boxed, allow_oob, async))
 
     def _def_event(self, expr, info, doc):
         name = expr['event']
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
old mode 100644
new mode 100755
index 9b312b2c51..33b26e2bef
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -227,7 +227,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
                                body=texi_entity(doc, 'Members')))
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed, allow_oob):
+                      gen, success_response, boxed, allow_oob, async):
         doc = self.cur_doc
         if boxed:
             body = texi_body(doc)
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index f9e67e8227..5de60d0357 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -172,7 +172,7 @@ const QLitObject %(c_name)s = %(c_string)s;
                                     for m in variants.variants]})
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed, allow_oob):
+                      gen, success_response, boxed, allow_oob, async):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         self._gen_qlit(name, 'command',
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index eeaac03d50..f1e6cde990 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -20,6 +20,28 @@ void qmp_cmd_success_response(Error **errp)
 {
 }
 
+static gboolean cmd_async_idle(gpointer user_data)
+{
+    QmpReturn *qret = user_data;
+
+    qmp_cmd_async_return(qret, g_new0(Empty2, 1));
+
+    return G_SOURCE_REMOVE;
+}
+
+void qmp_cmd_async(const char *filename, QmpReturn *qret)
+{
+    g_idle_add(cmd_async_idle, qret);
+}
+
+void qmp_cmd_success_response_async(const char *filename, QmpReturn *qret)
+{
+    Error *err = NULL;
+
+    error_setg(&err, "no response, but error ok");
+    qmp_return_error(qret, err);
+}
+
 Empty2 *qmp_user_def_cmd0(Error **errp)
 {
     return g_new0(Empty2, 1);
@@ -345,6 +367,43 @@ static void test_qmp_return_orderly(void)
     QDECREF(dict);
 }
 
+typedef struct QmpReturnAsync {
+    QmpSession session;
+    GMainLoop *loop;
+} QmpReturnAsync;
+
+static void dispatch_return_async(QmpSession *session, QDict *resp)
+{
+    QmpReturnAsync *a = container_of(session, QmpReturnAsync, session);
+
+    g_main_loop_quit(a->loop);
+    g_main_loop_unref(a->loop);
+    a->loop = NULL;
+}
+
+static void test_qmp_return_async(void)
+{
+    QmpReturnAsync a = { 0, };
+    QDict *args = qdict_new();
+    QDict *req = qdict_new();
+
+    a.loop = g_main_loop_new(NULL, TRUE);
+    qmp_session_init(&a.session, &qmp_commands,
+                    qmp_dispatch, dispatch_return_async);
+
+    qdict_put_str(args, "filename", "test-filename");
+    qdict_put_str(req, "execute", "cmd-async");
+    qdict_put(req, "arguments", args);
+    qmp_dispatch(&a.session, req);
+    g_assert(a.loop);
+
+    g_main_loop_run(a.loop);
+    g_assert(!a.loop);
+
+    qmp_session_destroy(&a.session);
+    QDECREF(req);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
@@ -358,6 +417,7 @@ int main(int argc, char **argv)
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
     g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
     g_test_add_func("/qmp/return_orderly", test_qmp_return_orderly);
+    g_test_add_func("/qmp/return_async", test_qmp_return_async);
 
     test_qmp_init_marshal(&qmp_commands);
     g_test_run();
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 96ff3a8e47..383369cd58 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -134,6 +134,11 @@
 
 { 'command': 'cmd-success-response', 'data': {}, 'success-response': false }
 
+{ 'command': 'cmd-async', 'data': {'filename': 'str'},
+  'returns': 'Empty2', 'async': true }
+{ 'command': 'cmd-success-response-async', 'data': {'filename': 'str'},
+  'async': true, 'success-response': false}
+
 # Returning a non-dictionary requires a name from the whitelist
 { 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
   'returns': 'int' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index cd3642be34..aa18f2c811 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -155,6 +155,14 @@ command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
    gen=True success_response=True boxed=False
 command cmd-success-response None -> None
    gen=True success_response=False boxed=False
+object q_obj_cmd-async-arg
+    member filename: str optional=False
+command cmd-async q_obj_cmd-async-arg -> Empty2
+   gen=True success_response=True boxed=False async=True
+object q_obj_cmd-success-response-async-arg
+    member filename: str optional=False
+command cmd-success-response-async q_obj_cmd-success-response-async-arg -> None
+   gen=True success_response=False boxed=False async=True
 object q_obj_guest-get-time-arg
     member a: int optional=False
     member b: int optional=True
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 10e68b01d9..491bdc73dd 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -42,11 +42,12 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         self._print_variants(variants)
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed, allow_oob):
+                      gen, success_response, boxed, allow_oob, async):
         print('command %s %s -> %s' % \
               (name, arg_type and arg_type.name, ret_type and ret_type.name))
-        print('   gen=%s success_response=%s boxed=%s' % \
-              (gen, success_response, boxed))
+        print('   gen=%s success_response=%s boxed=%s%s' % \
+              (gen, success_response, boxed,
+               ' async=True' if async else ''))
 
     def visit_event(self, name, info, arg_type, boxed):
         print('event %s %s' % (name, arg_type and arg_type.name))
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 31/38] qmp: add qmp_return_is_cancelled()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (29 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 30/38] scripts: learn 'async' qapi commands Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 32/38] monitor: add qmp_return_get_monitor() Marc-André Lureau
                   ` (12 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

If the client is gone, and the session finished, no need to
return. The async handler can use this information to avoid
unnecessary work and exit earlier.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  8 ++++++++
 qapi/qmp-dispatch.c         | 10 ++++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index e426317346..6ee82371a2 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -91,6 +91,14 @@ void qmp_return_free(QmpReturn *qret);
 void qmp_return(QmpReturn *qret, QObject *rsp);
 void qmp_return_error(QmpReturn *qret, Error *err);
 
+/*
+ * @qmp_return_is_cancelled:
+ *
+ * Return true if the QmpReturn is cancelled, and free the QmpReturn
+ * in this case.
+ */
+bool qmp_return_is_cancelled(QmpReturn *qret);
+
 void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
 void qmp_register_async_command(QmpCommandList *cmds, const char *name,
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index f7d9931734..99f5128170 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -63,6 +63,16 @@ void qmp_return_free(QmpReturn *qret)
     }
 }
 
+bool qmp_return_is_cancelled(QmpReturn *qret)
+{
+    if (!qret->session) {
+        qmp_return_free(qret);
+        return true;
+    }
+
+    return false;
+}
+
 static void qmp_return_orderly(QmpReturn *qret)
 {
     QmpSession *session = qret->session;
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 32/38] monitor: add qmp_return_get_monitor()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (30 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 31/38] qmp: add qmp_return_is_cancelled() Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 33/38] console: graphic_hw_update return true if async Marc-André Lureau
                   ` (11 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

If necessary, add an helper that can be used to retrieve the
associated monitor. This is useful for asynchronous commands that may
have to update cur_mon for various reasons.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/monitor/monitor.h | 3 +++
 monitor.c                 | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 0cb0538a31..2052a6b4e4 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -5,6 +5,7 @@
 #include "block/block.h"
 #include "qapi/qapi-types-misc.h"
 #include "qemu/readline.h"
+#include "qapi/qmp/dispatch.h"
 
 extern Monitor *cur_mon;
 
@@ -46,4 +47,6 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
 void monitor_fdset_dup_fd_remove(int dup_fd);
 int monitor_fdset_dup_fd_find(int dup_fd);
 
+Monitor *qmp_return_get_monitor(QmpReturn *qret);
+
 #endif /* MONITOR_H */
diff --git a/monitor.c b/monitor.c
index 73a06d4156..f7826f5626 100644
--- a/monitor.c
+++ b/monitor.c
@@ -281,6 +281,12 @@ bool monitor_cur_is_qmp(void)
     return cur_mon && monitor_is_qmp(cur_mon);
 }
 
+Monitor *qmp_return_get_monitor(QmpReturn *qret)
+{
+    return qret->session ?
+        container_of(qret->session, Monitor, qmp.session) : NULL;
+}
+
 void monitor_read_command(Monitor *mon, int show_prompt)
 {
     if (!mon->rs)
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 33/38] console: graphic_hw_update return true if async
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (31 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 32/38] monitor: add qmp_return_get_monitor() Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 34/38] console: add graphic_hw_update_done() Marc-André Lureau
                   ` (10 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

qxl_render_update() returns true if the update is deferred.

Let the caller know if the update is immediate or async.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/display/qxl.h        |  2 +-
 include/ui/console.h    |  3 ++-
 hw/display/qxl-render.c |  5 +++--
 hw/display/qxl.c        |  8 ++++----
 ui/console.c            | 14 ++++++++++++--
 5 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index 089696ef62..cc4f83f990 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -169,7 +169,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
 
 /* qxl-render.c */
 void qxl_render_resize(PCIQXLDevice *qxl);
-void qxl_render_update(PCIQXLDevice *qxl);
+bool qxl_render_update(PCIQXLDevice *qxl);
 int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
 void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
 void qxl_render_update_area_bh(void *opaque);
diff --git a/include/ui/console.h b/include/ui/console.h
index 6d2c052068..d2b6c46a62 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -374,6 +374,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
 typedef struct GraphicHwOps {
     void (*invalidate)(void *opaque);
     void (*gfx_update)(void *opaque);
+    bool (*gfx_update_async)(void *opaque);
     void (*text_update)(void *opaque, console_ch_t *text);
     void (*update_interval)(void *opaque, uint64_t interval);
     int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
@@ -388,7 +389,7 @@ void graphic_console_set_hwops(QemuConsole *con,
                                void *opaque);
 void graphic_console_close(QemuConsole *con);
 
-void graphic_hw_update(QemuConsole *con);
+bool graphic_hw_update(QemuConsole *con);
 void graphic_hw_invalidate(QemuConsole *con);
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index e7ac4f8789..62574173a2 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -163,7 +163,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
  * callbacks are called by spice_server thread, deferring to bh called from the
  * io thread.
  */
-void qxl_render_update(PCIQXLDevice *qxl)
+bool qxl_render_update(PCIQXLDevice *qxl)
 {
     QXLCookie *cookie;
 
@@ -172,7 +172,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
     if (!runstate_is_running() || !qxl->guest_primary.commands) {
         qxl_render_update_area_unlocked(qxl);
         qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
+        return false;
     }
 
     qxl->guest_primary.commands = 0;
@@ -183,6 +183,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
     qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
     qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
                           0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
+    return true;
 }
 
 void qxl_render_update_area_bh(void *opaque)
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index a71714ccb4..7dda2ae576 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -136,7 +136,7 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
 static void qxl_reset_surfaces(PCIQXLDevice *d);
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
 
-static void qxl_hw_update(void *opaque);
+static bool qxl_hw_update_async(void *opaque);
 
 void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
 {
@@ -1167,7 +1167,7 @@ static const QXLInterface qxl_interface = {
 };
 
 static const GraphicHwOps qxl_ops = {
-    .gfx_update  = qxl_hw_update,
+    .gfx_update_async = qxl_hw_update_async,
 };
 
 static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -1889,11 +1889,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
 
 /* graphics console */
 
-static void qxl_hw_update(void *opaque)
+static bool qxl_hw_update_async(void *opaque)
 {
     PCIQXLDevice *qxl = opaque;
 
-    qxl_render_update(qxl);
+    return qxl_render_update(qxl);
 }
 
 static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
diff --git a/ui/console.c b/ui/console.c
index 530a491987..0774cd3366 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -256,14 +256,24 @@ static void gui_setup_refresh(DisplayState *ds)
     ds->have_text = have_text;
 }
 
-void graphic_hw_update(QemuConsole *con)
+bool graphic_hw_update(QemuConsole *con)
 {
     if (!con) {
         con = active_console;
     }
-    if (con && con->hw_ops->gfx_update) {
+
+    if (!con) {
+        return false;
+    }
+
+    if (con->hw_ops->gfx_update_async) {
+        return con->hw_ops->gfx_update_async(con->hw);
+    } else if (con->hw_ops->gfx_update) {
         con->hw_ops->gfx_update(con->hw);
+        return false;
     }
+
+    return false;
 }
 
 void graphic_hw_gl_block(QemuConsole *con, bool block)
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 34/38] console: add graphic_hw_update_done()
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (32 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 33/38] console: graphic_hw_update return true if async Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous Marc-André Lureau
                   ` (9 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Add a function to be called when an async graphic update is done.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/ui/console.h    | 1 +
 hw/display/qxl-render.c | 9 +++++++--
 ui/console.c            | 4 ++++
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index d2b6c46a62..fc21621656 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -390,6 +390,7 @@ void graphic_console_set_hwops(QemuConsole *con,
 void graphic_console_close(QemuConsole *con);
 
 bool graphic_hw_update(QemuConsole *con);
+void graphic_hw_update_done(QemuConsole *con);
 void graphic_hw_invalidate(QemuConsole *con);
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index 62574173a2..08722d2833 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -106,7 +106,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
                                                 qxl->guest_primary.surface.mem,
                                                 MEMSLOT_GROUP_GUEST);
         if (!qxl->guest_primary.data) {
-            return;
+            goto end;
         }
         qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
         qxl->num_dirty_rects = 1;
@@ -134,7 +134,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
     }
 
     if (!qxl->guest_primary.data) {
-        return;
+        goto end;
     }
     for (i = 0; i < qxl->num_dirty_rects; i++) {
         if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
@@ -155,6 +155,11 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
                        qxl->dirty[i].bottom - qxl->dirty[i].top);
     }
     qxl->num_dirty_rects = 0;
+
+end:
+    if (qxl->render_update_cookie_num == 0) {
+        graphic_hw_update_done(qxl->ssd.dcl.con);
+    }
 }
 
 /*
diff --git a/ui/console.c b/ui/console.c
index 0774cd3366..29234605a7 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -256,6 +256,10 @@ static void gui_setup_refresh(DisplayState *ds)
     ds->have_text = have_text;
 }
 
+void graphic_hw_update_done(QemuConsole *con)
+{
+}
+
 bool graphic_hw_update(QemuConsole *con)
 {
     if (!con) {
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (33 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 34/38] console: add graphic_hw_update_done() Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-04-12 14:48   ` Dr. David Alan Gilbert
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 36/38] monitor: start making qmp_human_monitor_command() asynchronous Marc-André Lureau
                   ` (8 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Make screendump asynchronous to provide correct screendumps.

HMP doesn't have async support, so it has to remain synchronous and
potentially incorrect to avoid potential races.

Fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=1230527

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/ui.json         |  3 +-
 include/ui/console.h |  3 ++
 hmp.c                |  2 +-
 ui/console.c         | 99 ++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 96 insertions(+), 11 deletions(-)

diff --git a/qapi/ui.json b/qapi/ui.json
index 5d01ad4304..4d2c326fb9 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -96,7 +96,8 @@
 #
 ##
 { 'command': 'screendump',
-  'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
+  'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
+  'async': true }
 
 ##
 # == Spice
diff --git a/include/ui/console.h b/include/ui/console.h
index fc21621656..0c02190963 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -74,6 +74,9 @@ struct MouseTransformInfo {
 };
 
 void hmp_mouse_set(Monitor *mon, const QDict *qdict);
+void hmp_screendump_sync(const char *filename,
+                         bool has_device, const char *device,
+                         bool has_head, int64_t head, Error **errp);
 
 /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
    constants) */
diff --git a/hmp.c b/hmp.c
index 679467d85a..da9008fe63 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2144,7 +2144,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
     int64_t head = qdict_get_try_int(qdict, "head", 0);
     Error *err = NULL;
 
-    qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
+    hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err);
     hmp_handle_error(mon, &err);
 }
 
diff --git a/ui/console.c b/ui/console.c
index 29234605a7..da51861191 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -32,6 +32,7 @@
 #include "chardev/char-fe.h"
 #include "trace.h"
 #include "exec/memory.h"
+#include "monitor/monitor.h"
 
 #define DEFAULT_BACKSCROLL 512
 #define CONSOLE_CURSOR_PERIOD 500
@@ -116,6 +117,12 @@ typedef enum {
     TEXT_CONSOLE_FIXED_SIZE
 } console_type_t;
 
+struct qmp_screendump {
+    gchar *filename;
+    QmpReturn *ret;
+    QLIST_ENTRY(qmp_screendump) link;
+};
+
 struct QemuConsole {
     Object parent;
 
@@ -165,6 +172,8 @@ struct QemuConsole {
     QEMUFIFO out_fifo;
     uint8_t out_fifo_buf[16];
     QEMUTimer *kbd_timer;
+
+    QLIST_HEAD(, qmp_screendump) qmp_screendumps;
 };
 
 struct DisplayState {
@@ -190,6 +199,8 @@ static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
 static void text_console_update_cursor_timer(void);
 static void text_console_update_cursor(void *opaque);
+static void ppm_save(const char *filename, DisplaySurface *ds,
+                     Error **errp);
 
 static void gui_update(void *opaque)
 {
@@ -256,8 +267,42 @@ static void gui_setup_refresh(DisplayState *ds)
     ds->have_text = have_text;
 }
 
+static void qmp_screendump_finish(QemuConsole *con, const char *filename,
+                                  QmpReturn *ret)
+{
+    Error *err = NULL;
+    DisplaySurface *surface;
+    Monitor *prev_mon = cur_mon;
+
+    if (qmp_return_is_cancelled(ret)) {
+        return;
+    }
+
+    cur_mon = qmp_return_get_monitor(ret);
+    surface = qemu_console_surface(con);
+
+    /* FIXME: async save with coroutine? it would have to copy or lock
+     * the surface. */
+    ppm_save(filename, surface, &err);
+
+    if (err) {
+        qmp_return_error(ret, err);
+    } else {
+        qmp_screendump_return(ret);
+    }
+    cur_mon = prev_mon;
+}
+
 void graphic_hw_update_done(QemuConsole *con)
 {
+    struct qmp_screendump *dump, *next;
+
+    QLIST_FOREACH_SAFE(dump, &con->qmp_screendumps, link, next) {
+        qmp_screendump_finish(con, dump->filename, dump->ret);
+        g_free(dump->filename);
+        QLIST_REMOVE(dump, link);
+        g_free(dump);
+    }
 }
 
 bool graphic_hw_update(QemuConsole *con)
@@ -358,35 +403,70 @@ write_err:
     goto out;
 }
 
-void qmp_screendump(const char *filename, bool has_device, const char *device,
-                    bool has_head, int64_t head, Error **errp)
+
+static QemuConsole *get_console(bool has_device, const char *device,
+                                bool has_head, int64_t head, Error **errp)
 {
-    QemuConsole *con;
-    DisplaySurface *surface;
+    QemuConsole *con = NULL;
 
     if (has_device) {
         con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
                                                  errp);
-        if (!con) {
-            return;
-        }
     } else {
         if (has_head) {
             error_setg(errp, "'head' must be specified together with 'device'");
-            return;
+            return NULL;
         }
         con = qemu_console_lookup_by_index(0);
         if (!con) {
             error_setg(errp, "There is no console to take a screendump from");
-            return;
         }
     }
 
+    return con;
+}
+
+void hmp_screendump_sync(const char *filename,
+                         bool has_device, const char *device,
+                         bool has_head, int64_t head, Error **errp)
+{
+    DisplaySurface *surface;
+    QemuConsole *con = get_console(has_device, device, has_head, head, errp);
+
+    if (!con) {
+        return;
+    }
+    /* This may not complete the drawing with Spice, you may have
+     * glitches or outdated dumps, use qmp instead! */
     graphic_hw_update(con);
     surface = qemu_console_surface(con);
     ppm_save(filename, surface, errp);
 }
 
+void qmp_screendump(const char *filename,
+                    bool has_device, const char *device,
+                    bool has_head, int64_t head,
+                    QmpReturn *qret)
+{
+    Error *err = NULL;
+    bool async;
+    QemuConsole *con = get_console(has_device, device, has_head, head, &err);
+
+    if (!con) {
+        qmp_return_error(qret, err);
+        return;
+    }
+    async = graphic_hw_update(con);
+    if (async) {
+        struct qmp_screendump *dump = g_new(struct qmp_screendump, 1);
+        dump->filename = g_strdup(filename);
+        dump->ret = qret;
+        QLIST_INSERT_HEAD(&con->qmp_screendumps, dump, link);
+    } else {
+        qmp_screendump_finish(con, filename, qret);
+    }
+}
+
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
 {
     if (!con) {
@@ -1280,6 +1360,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
     obj = object_new(TYPE_QEMU_CONSOLE);
     s = QEMU_CONSOLE(obj);
     s->head = head;
+    QLIST_INIT(&s->qmp_screendumps);
     object_property_add_link(obj, "device", TYPE_DEVICE,
                              (Object **)&s->device,
                              object_property_allow_set_link,
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 36/38] monitor: start making qmp_human_monitor_command() asynchronous
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (34 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands Marc-André Lureau
                   ` (7 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

This prepares the work for HMP commands to be asynchronous. For now
this will and the return synchronously.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/misc.json |  3 ++-
 monitor.c      | 14 ++++++++------
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/qapi/misc.json b/qapi/misc.json
index 5636f4a149..04e704eb6c 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -1307,7 +1307,8 @@
 ##
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
-  'returns': 'str' }
+  'returns': 'str',
+  'async': true }
 
 ##
 # @ObjectPropertyInfo:
diff --git a/monitor.c b/monitor.c
index f7826f5626..e11c0abdca 100644
--- a/monitor.c
+++ b/monitor.c
@@ -637,8 +637,8 @@ static void monitor_data_destroy(Monitor *mon)
     g_queue_free(mon->qmp.qmp_requests);
 }
 
-char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
-                                int64_t cpu_index, Error **errp)
+void qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
+                               int64_t cpu_index, QmpReturn *qret)
 {
     char *output = NULL;
     Monitor *old_mon, hmp;
@@ -651,15 +651,15 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     if (has_cpu_index) {
         int ret = monitor_set_cpu(cpu_index);
         if (ret < 0) {
-            cur_mon = old_mon;
-            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+            Error *err = NULL;
+            error_setg(&err, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
                        "a CPU number");
+            qmp_return_error(qret, err);
             goto out;
         }
     }
 
     handle_hmp_command(&hmp, command_line);
-    cur_mon = old_mon;
 
     qemu_mutex_lock(&hmp.out_lock);
     if (qstring_get_length(hmp.outbuf) > 0) {
@@ -669,9 +669,11 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     }
     qemu_mutex_unlock(&hmp.out_lock);
 
+    qmp_human_monitor_command_return(qret, output);
+
 out:
     monitor_data_destroy(&hmp);
-    return output;
+    cur_mon = old_mon;
 }
 
 static int compare_cmd(const char *name, const char *list)
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (35 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 36/38] monitor: start making qmp_human_monitor_command() asynchronous Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 38/38] hmp: call the asynchronous QMP screendump to fix outdated/glitches Marc-André Lureau
                   ` (6 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

Similar to how we handle both synchronous and asynchronous commands in
QMP, HMP gains a new async_cmd() that will allow the command to
complete asynchronously. For interactive reasons, and command
ordering, the HMP monitor is suspended until the asynchronous command
completes.

Note that QMP human-monitor-command is modified to deal with it, by
using a specialized QmpSession return callback to destroy the
temporary HMP monitor.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 monitor.c | 106 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 79 insertions(+), 27 deletions(-)

diff --git a/monitor.c b/monitor.c
index e11c0abdca..018bd9280f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -127,13 +127,17 @@ typedef struct mon_cmd_t {
     const char *args_type;
     const char *params;
     const char *help;
-    void (*cmd)(Monitor *mon, const QDict *qdict);
+    union {
+        void (*cmd)(Monitor *mon, const QDict *qdict);
+        void (*async_cmd)(Monitor *mon, const QDict *qdict, QmpReturn *qret);
+    };
     /* @sub_table is a list of 2nd level of commands. If it does not exist,
      * cmd should be used. If it exists, sub_table[?].cmd should be
      * used, and cmd of 1st level plays the role of help function.
      */
     struct mon_cmd_t *sub_table;
     void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
+    bool async;
 } mon_cmd_t;
 
 /* file descriptors passed via SCM_RIGHTS */
@@ -203,6 +207,7 @@ struct Monitor {
     int suspend_cnt;            /* Needs to be accessed atomically */
     bool skip_flush;
     bool use_io_thr;
+    QmpReturn *for_qmp_command;
 
     QemuMutex out_lock;
     QString *outbuf;
@@ -607,7 +612,7 @@ static void monitor_qapi_event_init(void)
     qmp_event_set_func_emit(monitor_qapi_event_queue);
 }
 
-static void handle_hmp_command(Monitor *mon, const char *cmdline);
+static bool handle_hmp_command(Monitor *mon, const char *cmdline);
 
 static void monitor_data_init(Monitor *mon, bool skip_flush,
                               bool use_io_thr)
@@ -637,16 +642,68 @@ static void monitor_data_destroy(Monitor *mon)
     g_queue_free(mon->qmp.qmp_requests);
 }
 
+static void free_temporary_hmp(void *opaque)
+{
+    Monitor *hmp = opaque;
+
+    qmp_session_destroy(&hmp->qmp.session);
+    monitor_data_destroy(hmp);
+    g_free(hmp);
+}
+
+static AioContext *monitor_get_aio_context(void)
+{
+    return iothread_get_aio_context(mon_global.mon_iothread);
+}
+
+static void qmp_human_monitor_command_finish(Monitor *hmp, QmpReturn *qret)
+{
+    char *output;
+
+    if (qstring_get_length(hmp->outbuf) > 0) {
+        output = g_strdup(qstring_get_str(hmp->outbuf));
+    } else {
+        output = g_strdup("");
+    }
+
+    qmp_human_monitor_command_return(qret, output);
+
+    if (hmp->for_qmp_command) {
+        aio_bh_schedule_oneshot(monitor_get_aio_context(),
+                                free_temporary_hmp, hmp);
+    }
+}
+
+static void hmp_dispatch_return_cb(QmpSession *session, QDict *rsp)
+{
+    Monitor *hmp = container_of(session, Monitor, qmp.session);
+    QDict *err = qdict_get_qdict(rsp, "error");
+    Monitor *old_mon = cur_mon;
+
+    cur_mon = hmp;
+    if (err) {
+        error_report("%s", qdict_get_str(err, "desc"));
+    } /* XXX: else, report depending on command */
+
+    if (hmp->for_qmp_command) {
+        qmp_human_monitor_command_finish(hmp, hmp->for_qmp_command);
+    } else {
+        monitor_resume(hmp);
+    }
+    cur_mon = old_mon;
+}
+
 void qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
                                int64_t cpu_index, QmpReturn *qret)
 {
-    char *output = NULL;
-    Monitor *old_mon, hmp;
+    Monitor *old_mon, *hmp = g_new0(Monitor, 1);
 
-    monitor_data_init(&hmp, true, false);
+    monitor_data_init(hmp, true, false);
+    qmp_session_init(&hmp->qmp.session, NULL, NULL, hmp_dispatch_return_cb);
+    hmp->for_qmp_command = qret;
 
     old_mon = cur_mon;
-    cur_mon = &hmp;
+    cur_mon = hmp;
 
     if (has_cpu_index) {
         int ret = monitor_set_cpu(cpu_index);
@@ -659,20 +716,11 @@ void qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
         }
     }
 
-    handle_hmp_command(&hmp, command_line);
-
-    qemu_mutex_lock(&hmp.out_lock);
-    if (qstring_get_length(hmp.outbuf) > 0) {
-        output = g_strdup(qstring_get_str(hmp.outbuf));
-    } else {
-        output = g_strdup("");
+    if (!handle_hmp_command(hmp, command_line)) {
+        qmp_human_monitor_command_finish(hmp, qret);
     }
-    qemu_mutex_unlock(&hmp.out_lock);
-
-    qmp_human_monitor_command_return(qret, output);
 
 out:
-    monitor_data_destroy(&hmp);
     cur_mon = old_mon;
 }
 
@@ -3244,7 +3292,7 @@ fail:
     return NULL;
 }
 
-static void handle_hmp_command(Monitor *mon, const char *cmdline)
+static bool handle_hmp_command(Monitor *mon, const char *cmdline)
 {
     QDict *qdict;
     const mon_cmd_t *cmd;
@@ -3253,18 +3301,25 @@ static void handle_hmp_command(Monitor *mon, const char *cmdline)
 
     cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
     if (!cmd) {
-        return;
+        return false;
     }
 
     qdict = monitor_parse_arguments(mon, &cmdline, cmd);
     if (!qdict) {
         monitor_printf(mon, "Try \"help %s\" for more information\n",
                        cmd->name);
-        return;
+        return false;
+    }
+    if (cmd->async) {
+        QmpReturn *qret = qmp_return_new(&mon->qmp.session, NULL);
+        monitor_suspend(mon);
+        cmd->async_cmd(mon, qdict, qret);
+    } else {
+        cmd->cmd(mon, qdict);
     }
-
-    cmd->cmd(mon, qdict);
     QDECREF(qdict);
+
+    return cmd->async;
 }
 
 static void cmd_completion(Monitor *mon, const char *name, const char *list)
@@ -4296,11 +4351,6 @@ static GMainContext *monitor_get_io_context(void)
     return iothread_get_g_main_context(mon_global.mon_iothread);
 }
 
-static AioContext *monitor_get_aio_context(void)
-{
-    return iothread_get_aio_context(mon_global.mon_iothread);
-}
-
 static void monitor_iothread_init(void)
 {
     mon_global.mon_iothread = iothread_create("mon_iothread",
@@ -4439,6 +4489,8 @@ void monitor_init(Chardev *chr, int flags)
                                      NULL, mon, NULL, true);
         }
     } else {
+        qmp_session_init(&mon->qmp.session,
+                         NULL, NULL, hmp_dispatch_return_cb);
         qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
                                  monitor_event, NULL, mon, NULL, true);
     }
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* [Qemu-devel] [PATCH v3 38/38] hmp: call the asynchronous QMP screendump to fix outdated/glitches
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (36 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands Marc-André Lureau
@ 2018-03-26 15:09 ` Marc-André Lureau
  2018-03-26 17:24 ` [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Dr. David Alan Gilbert
                   ` (5 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 15:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Eric Blake, Cleber Rosa, Markus Armbruster, Gerd Hoffmann,
	Michael Roth, Marc-André Lureau

In order to fix the bad screendumps (same as rhbz#1230527), call into
the asynchonous version of the QMP command.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hmp.h           |  3 ++-
 hmp.c           |  6 ++----
 ui/console.c    | 17 -----------------
 hmp-commands.hx |  3 ++-
 4 files changed, 6 insertions(+), 23 deletions(-)

diff --git a/hmp.h b/hmp.h
index 4e2ec375b0..6ad43b7828 100644
--- a/hmp.h
+++ b/hmp.h
@@ -16,6 +16,7 @@
 
 #include "qemu-common.h"
 #include "qemu/readline.h"
+#include "qapi/qmp/dispatch.h"
 
 void hmp_info_name(Monitor *mon, const QDict *qdict);
 void hmp_info_version(Monitor *mon, const QDict *qdict);
@@ -96,7 +97,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict);
 void hmp_getfd(Monitor *mon, const QDict *qdict);
 void hmp_closefd(Monitor *mon, const QDict *qdict);
 void hmp_sendkey(Monitor *mon, const QDict *qdict);
-void hmp_screendump(Monitor *mon, const QDict *qdict);
+void hmp_screendump_async(Monitor *mon, const QDict *qdict, QmpReturn *qret);
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict);
diff --git a/hmp.c b/hmp.c
index da9008fe63..ca1ee8e146 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2137,15 +2137,13 @@ err_out:
     goto out;
 }
 
-void hmp_screendump(Monitor *mon, const QDict *qdict)
+void hmp_screendump_async(Monitor *mon, const QDict *qdict, QmpReturn *qret)
 {
     const char *filename = qdict_get_str(qdict, "filename");
     const char *id = qdict_get_try_str(qdict, "device");
     int64_t head = qdict_get_try_int(qdict, "head", 0);
-    Error *err = NULL;
 
-    hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err);
-    hmp_handle_error(mon, &err);
+    qmp_screendump(filename, id != NULL, id, id != NULL, head, qret);
 }
 
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
diff --git a/ui/console.c b/ui/console.c
index da51861191..f1cbbd6317 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -426,23 +426,6 @@ static QemuConsole *get_console(bool has_device, const char *device,
     return con;
 }
 
-void hmp_screendump_sync(const char *filename,
-                         bool has_device, const char *device,
-                         bool has_head, int64_t head, Error **errp)
-{
-    DisplaySurface *surface;
-    QemuConsole *con = get_console(has_device, device, has_head, head, errp);
-
-    if (!con) {
-        return;
-    }
-    /* This may not complete the drawing with Spice, you may have
-     * glitches or outdated dumps, use qmp instead! */
-    graphic_hw_update(con);
-    surface = qemu_console_surface(con);
-    ppm_save(filename, surface, errp);
-}
-
 void qmp_screendump(const char *filename,
                     bool has_device, const char *device,
                     bool has_head, int64_t head,
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 35d862a5d2..4911fc6474 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -258,7 +258,8 @@ ETEXI
         .params     = "filename [device [head]]",
         .help       = "save screen from head 'head' of display device 'device' "
                       "into PPM image 'filename'",
-        .cmd        = hmp_screendump,
+        .async_cmd  = hmp_screendump_async,
+        .async      = true,
     },
 
 STEXI
-- 
2.17.0.rc1.1.g4c4f2b46a3

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (37 preceding siblings ...)
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 38/38] hmp: call the asynchronous QMP screendump to fix outdated/glitches Marc-André Lureau
@ 2018-03-26 17:24 ` Dr. David Alan Gilbert
  2018-03-26 17:30   ` Marc-André Lureau
  2018-03-26 17:43 ` no-reply
                   ` (4 subsequent siblings)
  43 siblings, 1 reply; 61+ messages in thread
From: Dr. David Alan Gilbert @ 2018-03-26 17:24 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela, Eric Blake,
	Cleber Rosa, Markus Armbruster, Gerd Hoffmann, Michael Roth

* Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
> Hi,

Without having gone too deep here, it looks like you've got a mix
of cleanups and adding the async stuff.
You might want to split it into the set of simple cleanups first.

Dave

> One of initial design goals of QMP was to have "asynchronous command
> completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
> goal was not fully achieved, and some broken bits left were removed
> progressively until commit 65207c59d that removed async command
> support.
> 
> Yet there are clear benefits allowing the command handler to re-enter
> the main loop if the command cannot be handled synchronously, or if it
> is long-lasting. This is currently not possible and make some bugs
> such as rhbz#1230527 difficult to solve.  Furthermore, many QMP
> commands do IO and could be considered 'slow' and blocking the main
> loop today. The unwritten solution so far is to use a pair of
> command+event. But this approach has a number of issues, in particular
> to fix existing commands, and inadequacy since the event is
> broadcasted and may thus have command 'id' conflict, beside being
> rather inefficient and incorrect.
> 
> The following series implements an async command solution instead. By
> introducing a session context and a command return handler, it can:
> - defer the return, allowing the mainloop to reenter
> - return only to the caller (no broadcasted event)
> - optionnally allow cancellation when the client is gone
> - track on-going qapi command(s) per client/session
> 
> Existing qemu commands can be gradually replaced by async:true
> variants when needed, and by carefully reviewing the concurrency
> aspects. The async:true commands marshaller helpers are splitted in
> half, the calling and return functions. The command is called with a
> QmpReturn context, that can return immediately or later, using the
> generated return helper, which allows for step-by-step conversion.
> 
> The screendump command is converted to an async:true version to solve
> rhbz#1230527. The command shows basic cancellation (this could be
> extended if needed). It could be further improved to do asynchronous
> IO write as well.
> 
> v3:
> - complete rework, dropping the asynchronous commands visibility from
>   the protocol side entirely (until there is a real need for it)
> - rebased, with a few preliminary cleanup patches
> - teach asynchronous commands to HMP
> 
> v2:
> - documentation fixes and improvements
> - fix calling async commands sync without id
> - fix bad hmp monitor assert
> - add a few extra asserts
> - add async with no-id failure and screendump test
> 
> Marc-André Lureau (38):
>   HACK: add back OOB
>   qmp-shell: learn to send commands with quoted arguments
>   Revert "qmp: isolate responses into io thread"
>   monitor: no need to save need_resume
>   monitor: further simplify previous patch
>   monitor: no need to remove desc before replacing it
>   json-parser: always set an error if return NULL
>   json-lexer: make it safe to call multiple times
>   json: remove useless return value from lexer/parser
>   tests: add a few qemu-qmp tests
>   tests: change /0.15/* tests to /qmp/*
>   tests: add a qmp success-response test
>   qga: process_event() simplification
>   monitor: simplify monitor_qmp_respond()
>   qmp: pass and return a QDict to qmp_dispatch()
>   qmp: move 'id' copy to qmp_dispatch()
>   qmp: constify qmp_is_oob()
>   qmp: add QmpSession
>   QmpSession: add a return_cb
>   QmpSession: add json parser and use it in qga
>   QmpSession: add a dispatch callback
>   monitor: use QmpSession parsing and common dispatch code
>   QmpSession: introduce QmpReturn
>   qmp: remove qmp_build_error_object()
>   qmp: remove need for qobject_from_jsonf()
>   qmp: fold do_qmp_dispatch() in qmp_dispatch()
>   QmpSession: keep a queue of pending commands
>   QmpSession: return orderly
>   qmp: introduce asynchronous command type
>   scripts: learn 'async' qapi commands
>   qmp: add qmp_return_is_cancelled()
>   monitor: add qmp_return_get_monitor()
>   console: graphic_hw_update return true if async
>   console: add graphic_hw_update_done()
>   console: make screendump asynchronous
>   monitor: start making qmp_human_monitor_command() asynchronous
>   monitor: teach HMP about asynchronous commands
>   hmp: call the asynchronous QMP screendump to fix outdated/glitches
> 
>  qapi/misc.json                          |   3 +-
>  qapi/ui.json                            |   3 +-
>  scripts/qapi/commands.py                | 149 +++++++--
>  scripts/qapi/common.py                  |  12 +-
>  scripts/qapi/doc.py                     |   2 +-
>  scripts/qapi/introspect.py              |   2 +-
>  hmp.h                                   |   3 +-
>  hw/display/qxl.h                        |   2 +-
>  include/monitor/monitor.h               |   3 +
>  include/qapi/qmp/dispatch.h             |  85 ++++-
>  include/qapi/qmp/json-lexer.h           |   4 +-
>  include/qapi/qmp/json-streamer.h        |   4 +-
>  include/ui/console.h                    |   7 +-
>  hmp.c                                   |   6 +-
>  hw/display/qxl-render.c                 |  14 +-
>  hw/display/qxl.c                        |   8 +-
>  migration/postcopy-ram.c                |   1 +
>  monitor.c                               | 393 +++++++++---------------
>  qapi/qmp-dispatch.c                     | 234 +++++++++++---
>  qapi/qmp-registry.c                     |  27 +-
>  qga/main.c                              |  73 +----
>  qobject/json-lexer.c                    |  28 +-
>  qobject/json-parser.c                   |   7 +-
>  qobject/json-streamer.c                 |   8 +-
>  tests/qmp-test.c                        | 146 ++++++++-
>  tests/test-qmp-cmds.c                   | 206 +++++++++++--
>  ui/console.c                            | 106 ++++++-
>  hmp-commands.hx                         |   3 +-
>  scripts/qmp/qmp-shell                   |   3 +-
>  tests/Makefile.include                  |   6 +-
>  tests/qapi-schema/qapi-schema-test.json |   7 +
>  tests/qapi-schema/qapi-schema-test.out  |  10 +
>  tests/qapi-schema/test-qapi.py          |   7 +-
>  33 files changed, 1078 insertions(+), 494 deletions(-)
>  mode change 100644 => 100755 scripts/qapi/doc.py
> 
> -- 
> 2.17.0.rc1.1.g4c4f2b46a3
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 17:24 ` [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Dr. David Alan Gilbert
@ 2018-03-26 17:30   ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-03-26 17:30 UTC (permalink / raw)
  To: Dr. David Alan Gilbert
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela, Eric Blake,
	Cleber Rosa, Markus Armbruster, Gerd Hoffmann, Michael Roth

Hi

On Mon, Mar 26, 2018 at 7:24 PM, Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
> * Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
>> Hi,
>
> Without having gone too deep here, it looks like you've got a mix
> of cleanups and adding the async stuff.
> You might want to split it into the set of simple cleanups first.

Yes, the preliminary patches should be easy to pick for inclusion
before the rest of the work.

Thanks

> Dave
>
>> One of initial design goals of QMP was to have "asynchronous command
>> completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
>> goal was not fully achieved, and some broken bits left were removed
>> progressively until commit 65207c59d that removed async command
>> support.
>>
>> Yet there are clear benefits allowing the command handler to re-enter
>> the main loop if the command cannot be handled synchronously, or if it
>> is long-lasting. This is currently not possible and make some bugs
>> such as rhbz#1230527 difficult to solve.  Furthermore, many QMP
>> commands do IO and could be considered 'slow' and blocking the main
>> loop today. The unwritten solution so far is to use a pair of
>> command+event. But this approach has a number of issues, in particular
>> to fix existing commands, and inadequacy since the event is
>> broadcasted and may thus have command 'id' conflict, beside being
>> rather inefficient and incorrect.
>>
>> The following series implements an async command solution instead. By
>> introducing a session context and a command return handler, it can:
>> - defer the return, allowing the mainloop to reenter
>> - return only to the caller (no broadcasted event)
>> - optionnally allow cancellation when the client is gone
>> - track on-going qapi command(s) per client/session
>>
>> Existing qemu commands can be gradually replaced by async:true
>> variants when needed, and by carefully reviewing the concurrency
>> aspects. The async:true commands marshaller helpers are splitted in
>> half, the calling and return functions. The command is called with a
>> QmpReturn context, that can return immediately or later, using the
>> generated return helper, which allows for step-by-step conversion.
>>
>> The screendump command is converted to an async:true version to solve
>> rhbz#1230527. The command shows basic cancellation (this could be
>> extended if needed). It could be further improved to do asynchronous
>> IO write as well.
>>
>> v3:
>> - complete rework, dropping the asynchronous commands visibility from
>>   the protocol side entirely (until there is a real need for it)
>> - rebased, with a few preliminary cleanup patches
>> - teach asynchronous commands to HMP
>>
>> v2:
>> - documentation fixes and improvements
>> - fix calling async commands sync without id
>> - fix bad hmp monitor assert
>> - add a few extra asserts
>> - add async with no-id failure and screendump test
>>
>> Marc-André Lureau (38):
>>   HACK: add back OOB
>>   qmp-shell: learn to send commands with quoted arguments
>>   Revert "qmp: isolate responses into io thread"
>>   monitor: no need to save need_resume
>>   monitor: further simplify previous patch
>>   monitor: no need to remove desc before replacing it
>>   json-parser: always set an error if return NULL
>>   json-lexer: make it safe to call multiple times
>>   json: remove useless return value from lexer/parser
>>   tests: add a few qemu-qmp tests
>>   tests: change /0.15/* tests to /qmp/*
>>   tests: add a qmp success-response test
>>   qga: process_event() simplification
>>   monitor: simplify monitor_qmp_respond()
>>   qmp: pass and return a QDict to qmp_dispatch()
>>   qmp: move 'id' copy to qmp_dispatch()
>>   qmp: constify qmp_is_oob()
>>   qmp: add QmpSession
>>   QmpSession: add a return_cb
>>   QmpSession: add json parser and use it in qga
>>   QmpSession: add a dispatch callback
>>   monitor: use QmpSession parsing and common dispatch code
>>   QmpSession: introduce QmpReturn
>>   qmp: remove qmp_build_error_object()
>>   qmp: remove need for qobject_from_jsonf()
>>   qmp: fold do_qmp_dispatch() in qmp_dispatch()
>>   QmpSession: keep a queue of pending commands
>>   QmpSession: return orderly
>>   qmp: introduce asynchronous command type
>>   scripts: learn 'async' qapi commands
>>   qmp: add qmp_return_is_cancelled()
>>   monitor: add qmp_return_get_monitor()
>>   console: graphic_hw_update return true if async
>>   console: add graphic_hw_update_done()
>>   console: make screendump asynchronous
>>   monitor: start making qmp_human_monitor_command() asynchronous
>>   monitor: teach HMP about asynchronous commands
>>   hmp: call the asynchronous QMP screendump to fix outdated/glitches
>>
>>  qapi/misc.json                          |   3 +-
>>  qapi/ui.json                            |   3 +-
>>  scripts/qapi/commands.py                | 149 +++++++--
>>  scripts/qapi/common.py                  |  12 +-
>>  scripts/qapi/doc.py                     |   2 +-
>>  scripts/qapi/introspect.py              |   2 +-
>>  hmp.h                                   |   3 +-
>>  hw/display/qxl.h                        |   2 +-
>>  include/monitor/monitor.h               |   3 +
>>  include/qapi/qmp/dispatch.h             |  85 ++++-
>>  include/qapi/qmp/json-lexer.h           |   4 +-
>>  include/qapi/qmp/json-streamer.h        |   4 +-
>>  include/ui/console.h                    |   7 +-
>>  hmp.c                                   |   6 +-
>>  hw/display/qxl-render.c                 |  14 +-
>>  hw/display/qxl.c                        |   8 +-
>>  migration/postcopy-ram.c                |   1 +
>>  monitor.c                               | 393 +++++++++---------------
>>  qapi/qmp-dispatch.c                     | 234 +++++++++++---
>>  qapi/qmp-registry.c                     |  27 +-
>>  qga/main.c                              |  73 +----
>>  qobject/json-lexer.c                    |  28 +-
>>  qobject/json-parser.c                   |   7 +-
>>  qobject/json-streamer.c                 |   8 +-
>>  tests/qmp-test.c                        | 146 ++++++++-
>>  tests/test-qmp-cmds.c                   | 206 +++++++++++--
>>  ui/console.c                            | 106 ++++++-
>>  hmp-commands.hx                         |   3 +-
>>  scripts/qmp/qmp-shell                   |   3 +-
>>  tests/Makefile.include                  |   6 +-
>>  tests/qapi-schema/qapi-schema-test.json |   7 +
>>  tests/qapi-schema/qapi-schema-test.out  |  10 +
>>  tests/qapi-schema/test-qapi.py          |   7 +-
>>  33 files changed, 1078 insertions(+), 494 deletions(-)
>>  mode change 100644 => 100755 scripts/qapi/doc.py
>>
>> --
>> 2.17.0.rc1.1.g4c4f2b46a3
>>
> --
> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (38 preceding siblings ...)
  2018-03-26 17:24 ` [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Dr. David Alan Gilbert
@ 2018-03-26 17:43 ` no-reply
  2018-03-26 17:55 ` no-reply
                   ` (3 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: no-reply @ 2018-03-26 17:43 UTC (permalink / raw)
  To: marcandre.lureau
  Cc: famz, qemu-devel, ehabkost, quintela, armbru, dgilbert, kraxel,
	crosa, mdroth

Hi,

This series failed docker-quick@centos6 build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

Type: series
Message-id: 20180326150916.9602-1-marcandre.lureau@redhat.com
Subject: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type

=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
export J=8
time make docker-test-quick@centos6
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
fd0470a9a5 hmp: call the asynchronous QMP screendump to fix outdated/glitches
51e20a57af monitor: teach HMP about asynchronous commands
1da4258136 monitor: start making qmp_human_monitor_command() asynchronous
4dc553eb62 console: make screendump asynchronous
37ce1da30f console: add graphic_hw_update_done()
e1b747ed7c console: graphic_hw_update return true if async
b97cbbac0d monitor: add qmp_return_get_monitor()
5d1e72cc83 qmp: add qmp_return_is_cancelled()
906373083b scripts: learn 'async' qapi commands
32594530ed qmp: introduce asynchronous command type
7436d3c044 QmpSession: return orderly
b5dcacb7b8 QmpSession: keep a queue of pending commands
2aec5b4175 qmp: fold do_qmp_dispatch() in qmp_dispatch()
82787d748a qmp: remove need for qobject_from_jsonf()
5118223e21 qmp: remove qmp_build_error_object()
59bd726436 QmpSession: introduce QmpReturn
123884b2b3 monitor: use QmpSession parsing and common dispatch code
99c8c44b05 QmpSession: add a dispatch callback
5c6561a277 QmpSession: add json parser and use it in qga
566650d56c QmpSession: add a return_cb
8d86248fef qmp: add QmpSession
9cd33a0c42 qmp: constify qmp_is_oob()
e7a01993d2 qmp: move 'id' copy to qmp_dispatch()
5a8e8359b0 qmp: pass and return a QDict to qmp_dispatch()
87de98918d monitor: simplify monitor_qmp_respond()
86a0247e95 qga: process_event() simplification
ba4ee2424c tests: add a qmp success-response test
5949924e12 tests: change /0.15/* tests to /qmp/*
fdeef976fd tests: add a few qemu-qmp tests
77cb805571 json: remove useless return value from lexer/parser
68d8588250 json-lexer: make it safe to call multiple times
4cf11d60e6 json-parser: always set an error if return NULL
7f5c39ac74 monitor: no need to remove desc before replacing it
fec6004793 monitor: further simplify previous patch
1887d35641 monitor: no need to save need_resume
af9f30ebb5 Revert "qmp: isolate responses into io thread"
b2cdd3c9c2 qmp-shell: learn to send commands with quoted arguments
b21608009a HACK: add back OOB

=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-1pv572w4/src/dtc'...
Submodule path 'dtc': checked out 'e54388015af1fb4bf04d0bca99caba1074d9cc42'
  BUILD   centos6
make[1]: Entering directory '/var/tmp/patchew-tester-tmp-1pv572w4/src'
  GEN     /var/tmp/patchew-tester-tmp-1pv572w4/src/docker-src.2018-03-26-13.41.28.30980/qemu.tar
Cloning into '/var/tmp/patchew-tester-tmp-1pv572w4/src/docker-src.2018-03-26-13.41.28.30980/qemu.tar.vroot'...
done.
Your branch is up-to-date with 'origin/test'.
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-1pv572w4/src/docker-src.2018-03-26-13.41.28.30980/qemu.tar.vroot/dtc'...
Submodule path 'dtc': checked out 'e54388015af1fb4bf04d0bca99caba1074d9cc42'
Submodule 'ui/keycodemapdb' (git://git.qemu.org/keycodemapdb.git) registered for path 'ui/keycodemapdb'
Cloning into '/var/tmp/patchew-tester-tmp-1pv572w4/src/docker-src.2018-03-26-13.41.28.30980/qemu.tar.vroot/ui/keycodemapdb'...
Submodule path 'ui/keycodemapdb': checked out '6b3d716e2b6472eb7189d3220552280ef3d832ce'
  COPY    RUNNER
    RUN test-quick in qemu:centos6 
Packages installed:
SDL-devel-1.2.14-7.el6_7.1.x86_64
bison-2.4.1-5.el6.x86_64
bzip2-devel-1.0.5-7.el6_0.x86_64
ccache-3.1.6-2.el6.x86_64
csnappy-devel-0-6.20150729gitd7bc683.el6.x86_64
flex-2.5.35-9.el6.x86_64
gcc-4.4.7-18.el6.x86_64
gettext-0.17-18.el6.x86_64
git-1.7.1-9.el6_9.x86_64
glib2-devel-2.28.8-9.el6.x86_64
libepoxy-devel-1.2-3.el6.x86_64
libfdt-devel-1.4.0-1.el6.x86_64
librdmacm-devel-1.0.21-0.el6.x86_64
lzo-devel-2.03-3.1.el6_5.1.x86_64
make-3.81-23.el6.x86_64
mesa-libEGL-devel-11.0.7-4.el6.x86_64
mesa-libgbm-devel-11.0.7-4.el6.x86_64
package g++ is not installed
pixman-devel-0.32.8-1.el6.x86_64
spice-glib-devel-0.26-8.el6.x86_64
spice-server-devel-0.12.4-16.el6.x86_64
tar-1.23-15.el6_8.x86_64
vte-devel-0.25.1-9.el6.x86_64
xen-devel-4.6.6-2.el6.x86_64
zlib-devel-1.2.3-29.el6.x86_64

Environment variables:
PACKAGES=bison     bzip2-devel     ccache     csnappy-devel     flex     g++     gcc     gettext     git     glib2-devel     libepoxy-devel     libfdt-devel     librdmacm-devel     lzo-devel     make     mesa-libEGL-devel     mesa-libgbm-devel     pixman-devel     SDL-devel     spice-glib-devel     spice-server-devel     tar     vte-devel     xen-devel     zlib-devel
HOSTNAME=8900fa589122
MAKEFLAGS= -j8
J=8
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
TARGET_LIST=
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
FEATURES= dtc
DEBUG=
_=/usr/bin/env

Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/tmp/qemu-test/install
No C++ compiler available; disabling C++ specific optional code
Install prefix    /tmp/qemu-test/install
BIOS directory    /tmp/qemu-test/install/share/qemu
firmware path     /tmp/qemu-test/install/share/qemu-firmware
binary directory  /tmp/qemu-test/install/bin
library directory /tmp/qemu-test/install/lib
module directory  /tmp/qemu-test/install/lib/qemu
libexec directory /tmp/qemu-test/install/libexec
include directory /tmp/qemu-test/install/include
config directory  /tmp/qemu-test/install/etc
local state directory   /tmp/qemu-test/install/var
Manual directory  /tmp/qemu-test/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /tmp/qemu-test/src
GIT binary        git
GIT submodules    
C compiler        cc
Host C compiler   cc
C++ compiler      
Objective-C compiler cc
ARFLAGS           rv
CFLAGS            -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g 
QEMU_CFLAGS       -I/usr/include/pixman-1   -I$(SRC_PATH)/dtc/libfdt -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -Wendif-labels -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all -Wno-missing-braces  -I/usr/include/libpng12   -I/usr/include/libdrm   -I/usr/include/spice-server -I/usr/include/cacard -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/nss3 -I/usr/include/nspr4 -I/usr/include/spice-1  
LDFLAGS           -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g 
make              make
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          x86_64
host big endian   no
target list       x86_64-softmmu aarch64-softmmu
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
SDL support       yes (1.2.14)
GTK support       yes (2.24.23)
GTK GL support    no
VTE support       yes (0.25.1)
TLS priority      NORMAL
GNUTLS support    no
GNUTLS rnd        no
libgcrypt         no
libgcrypt kdf     no
nettle            no 
nettle kdf        no
libtasn1          no
curses support    yes
virgl support     no
curl support      no
mingw32 support   no
Audio drivers     oss
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    no
Multipath support no
VNC support       yes
VNC SASL support  no
VNC JPEG support  yes
VNC PNG support   yes
xen support       yes
xen ctrl version  40600
pv dom build      no
brlapi support    no
bluez  support    no
Documentation     no
PIE               yes
vde support       no
netmap support    no
Linux AIO support no
ATTR/XATTR support yes
Install blobs     yes
KVM support       yes
HAX support       no
HVF support       no
WHPX support      no
TCG support       yes
TCG debug enabled no
TCG interpreter   no
malloc trim support yes
RDMA support      no
fdt support       yes
membarrier        no
preadv support    yes
fdatasync         yes
madvise           yes
posix_madvise     yes
posix_memalign    yes
libcap-ng support no
vhost-net support yes
vhost-crypto support yes
vhost-scsi support yes
vhost-vsock support yes
vhost-user support yes
Trace backends    log
spice support     yes (0.12.6/0.12.4)
rbd support       no
xfsctl support    no
smartcard support yes
libusb            no
usb net redir     no
OpenGL support    yes
OpenGL dmabufs    no
libiscsi support  no
libnfs support    no
build guest agent yes
QGA VSS support   no
QGA w32 disk info no
QGA MSI support   no
seccomp support   no
coroutine backend ucontext
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   no
TPM passthrough   yes
TPM emulator      yes
QOM debugging     yes
Live block migration yes
lzo support       yes
snappy support    no
bzip2 support     yes
NUMA host support no
libxml2           no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
VxHS block device no
capstone          no

WARNING: Use of GTK 2.0 is deprecated and will be removed in
WARNING: future releases. Please switch to using GTK 3.0

WARNING: Use of SDL 1.2 is deprecated and will be removed in
WARNING: future releases. Please switch to using SDL 2.0
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     aarch64-softmmu/config-devices.mak.tmp
mkdir -p dtc/libfdt
  GEN     config-host.h
mkdir -p dtc/tests
  GEN     qemu-options.def
  GEN     qapi-gen
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
  GEN     trace/generated-helpers.h
  GEN     x86_64-softmmu/config-devices.mak
  GEN     aarch64-softmmu/config-devices.mak
  GEN     trace/generated-helpers.c
  GEN     module_block.h
  GEN     ui/input-keymap-atset1-to-qcode.c
  GEN     ui/input-keymap-qcode-to-atset1.c
  GEN     ui/input-keymap-linux-to-qcode.c
  GEN     ui/input-keymap-qcode-to-atset2.c
  GEN     ui/input-keymap-qcode-to-atset3.c
  GEN     ui/input-keymap-qcode-to-linux.c
  GEN     ui/input-keymap-qcode-to-qnum.c
  GEN     ui/input-keymap-qcode-to-sun.c
  GEN     ui/input-keymap-qnum-to-qcode.c
  GEN     ui/input-keymap-usb-to-qcode.c
  GEN     ui/input-keymap-win32-to-qcode.c
  GEN     ui/input-keymap-x11-to-qcode.c
  GEN     ui/input-keymap-xorgevdev-to-qcode.c
  GEN     ui/input-keymap-xorgkbd-to-qcode.c
  GEN     ui/input-keymap-xorgxquartz-to-qcode.c
  GEN     ui/input-keymap-xorgxwin-to-qcode.c
  GEN     tests/test-qapi-gen
  GEN     trace-root.h
  GEN     util/trace.h
  GEN     crypto/trace.h
  GEN     io/trace.h
  GEN     migration/trace.h
  GEN     block/trace.h
  GEN     chardev/trace.h
  GEN     hw/block/trace.h
  GEN     hw/block/dataplane/trace.h
  GEN     hw/char/trace.h
  GEN     hw/intc/trace.h
  GEN     hw/net/trace.h
  GEN     hw/rdma/trace.h
  GEN     hw/rdma/vmw/trace.h
  GEN     hw/virtio/trace.h
  GEN     hw/audio/trace.h
  GEN     hw/misc/trace.h
  GEN     hw/misc/macio/trace.h
  GEN     hw/usb/trace.h
  GEN     hw/scsi/trace.h
  GEN     hw/nvram/trace.h
  GEN     hw/display/trace.h
  GEN     hw/input/trace.h
  GEN     hw/timer/trace.h
  GEN     hw/dma/trace.h
  GEN     hw/sparc/trace.h
  GEN     hw/sparc64/trace.h
  GEN     hw/sd/trace.h
  GEN     hw/isa/trace.h
  GEN     hw/mem/trace.h
  GEN     hw/i386/trace.h
  GEN     hw/i386/xen/trace.h
  GEN     hw/9pfs/trace.h
  GEN     hw/ppc/trace.h
  GEN     hw/pci/trace.h
  GEN     hw/pci-host/trace.h
  GEN     hw/s390x/trace.h
  GEN     hw/vfio/trace.h
  GEN     hw/acpi/trace.h
  GEN     hw/arm/trace.h
  GEN     hw/alpha/trace.h
  GEN     hw/hppa/trace.h
  GEN     hw/xen/trace.h
  GEN     hw/ide/trace.h
  GEN     hw/tpm/trace.h
  GEN     ui/trace.h
  GEN     audio/trace.h
  GEN     net/trace.h
  GEN     target/arm/trace.h
  GEN     target/i386/trace.h
  GEN     target/mips/trace.h
  GEN     target/sparc/trace.h
  GEN     target/s390x/trace.h
  GEN     target/ppc/trace.h
  GEN     qom/trace.h
  GEN     linux-user/trace.h
  GEN     qapi/trace.h
  GEN     accel/tcg/trace.h
  GEN     accel/kvm/trace.h
  GEN     nbd/trace.h
  GEN     scsi/trace.h
  GEN     trace-root.c
  GEN     util/trace.c
  GEN     crypto/trace.c
  GEN     io/trace.c
  GEN     migration/trace.c
  GEN     block/trace.c
  GEN     chardev/trace.c
  GEN     hw/block/trace.c
  GEN     hw/block/dataplane/trace.c
  GEN     hw/char/trace.c
  GEN     hw/intc/trace.c
  GEN     hw/net/trace.c
  GEN     hw/rdma/trace.c
  GEN     hw/rdma/vmw/trace.c
  GEN     hw/virtio/trace.c
  GEN     hw/audio/trace.c
  GEN     hw/misc/trace.c
  GEN     hw/misc/macio/trace.c
  GEN     hw/usb/trace.c
  GEN     hw/scsi/trace.c
  GEN     hw/nvram/trace.c
  GEN     hw/display/trace.c
  GEN     hw/input/trace.c
  GEN     hw/timer/trace.c
  GEN     hw/dma/trace.c
  GEN     hw/sparc/trace.c
  GEN     hw/sparc64/trace.c
  GEN     hw/sd/trace.c
  GEN     hw/isa/trace.c
  GEN     hw/mem/trace.c
  GEN     hw/i386/trace.c
  GEN     hw/i386/xen/trace.c
  GEN     hw/9pfs/trace.c
  GEN     hw/ppc/trace.c
  GEN     hw/pci/trace.c
  GEN     hw/pci-host/trace.c
  GEN     hw/s390x/trace.c
  GEN     hw/vfio/trace.c
  GEN     hw/acpi/trace.c
  GEN     hw/arm/trace.c
  GEN     hw/alpha/trace.c
  GEN     hw/hppa/trace.c
  GEN     hw/xen/trace.c
  GEN     hw/ide/trace.c
  GEN     hw/tpm/trace.c
  GEN     ui/trace.c
  GEN     audio/trace.c
  GEN     net/trace.c
  GEN     target/arm/trace.c
  GEN     target/i386/trace.c
  GEN     target/mips/trace.c
  GEN     target/sparc/trace.c
  GEN     target/s390x/trace.c
  GEN     target/ppc/trace.c
  GEN     qom/trace.c
  GEN     linux-user/trace.c
  GEN     qapi/trace.c
  GEN     accel/tcg/trace.c
  GEN     accel/kvm/trace.c
  GEN     nbd/trace.c
  GEN     scsi/trace.c
  GEN     config-all-devices.mak
	 DEP /tmp/qemu-test/src/dtc/tests/dumptrees.c
	 DEP /tmp/qemu-test/src/dtc/tests/trees.S
	 DEP /tmp/qemu-test/src/dtc/tests/testutils.c
	 DEP /tmp/qemu-test/src/dtc/tests/value-labels.c
	 DEP /tmp/qemu-test/src/dtc/tests/asm_tree_dump.c
	 DEP /tmp/qemu-test/src/dtc/tests/truncated_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/check_path.c
	 DEP /tmp/qemu-test/src/dtc/tests/overlay.c
	 DEP /tmp/qemu-test/src/dtc/tests/overlay_bad_fixup.c
	 DEP /tmp/qemu-test/src/dtc/tests/subnode_iterate.c
	 DEP /tmp/qemu-test/src/dtc/tests/property_iterate.c
	 DEP /tmp/qemu-test/src/dtc/tests/integer-expressions.c
	 DEP /tmp/qemu-test/src/dtc/tests/utilfdt_test.c
	 DEP /tmp/qemu-test/src/dtc/tests/path_offset_aliases.c
	 DEP /tmp/qemu-test/src/dtc/tests/add_subnode_with_nops.c
	 DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_unordered.c
	 DEP /tmp/qemu-test/src/dtc/tests/dtb_reverse.c
	 DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_ordered.c
	 DEP /tmp/qemu-test/src/dtc/tests/extra-terminating-null.c
	 DEP /tmp/qemu-test/src/dtc/tests/incbin.c
	 DEP /tmp/qemu-test/src/dtc/tests/boot-cpuid.c
	 DEP /tmp/qemu-test/src/dtc/tests/phandle_format.c
	 DEP /tmp/qemu-test/src/dtc/tests/path-references.c
	 DEP /tmp/qemu-test/src/dtc/tests/references.c
	 DEP /tmp/qemu-test/src/dtc/tests/string_escapes.c
	 DEP /tmp/qemu-test/src/dtc/tests/appendprop2.c
	 DEP /tmp/qemu-test/src/dtc/tests/appendprop1.c
	 DEP /tmp/qemu-test/src/dtc/tests/propname_escapes.c
	 DEP /tmp/qemu-test/src/dtc/tests/del_node.c
	 DEP /tmp/qemu-test/src/dtc/tests/del_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/setprop.c
	 DEP /tmp/qemu-test/src/dtc/tests/set_name.c
	 DEP /tmp/qemu-test/src/dtc/tests/rw_tree1.c
	 DEP /tmp/qemu-test/src/dtc/tests/nopulate.c
	 DEP /tmp/qemu-test/src/dtc/tests/open_pack.c
	 DEP /tmp/qemu-test/src/dtc/tests/mangle-layout.c
	 DEP /tmp/qemu-test/src/dtc/tests/move_and_save.c
	 DEP /tmp/qemu-test/src/dtc/tests/sw_tree1.c
	 DEP /tmp/qemu-test/src/dtc/tests/nop_node.c
	 DEP /tmp/qemu-test/src/dtc/tests/nop_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/setprop_inplace.c
	 DEP /tmp/qemu-test/src/dtc/tests/addr_size_cells.c
	 DEP /tmp/qemu-test/src/dtc/tests/sized_cells.c
	 DEP /tmp/qemu-test/src/dtc/tests/stringlist.c
	 DEP /tmp/qemu-test/src/dtc/tests/notfound.c
	 DEP /tmp/qemu-test/src/dtc/tests/char_literal.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_alias.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_compatible.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_check_compatible.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_phandle.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_prop_value.c
	 DEP /tmp/qemu-test/src/dtc/tests/parent_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/supernode_atdepth_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_path.c
	 DEP /tmp/qemu-test/src/dtc/tests/getprop.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_phandle.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_name.c
	 DEP /tmp/qemu-test/src/dtc/tests/subnode_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/path_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/find_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/root_node.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_mem_rsv.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_overlay.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_addresses.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_empty_tree.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_strerror.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_rw.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_sw.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_ro.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_wip.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt.c
	 DEP /tmp/qemu-test/src/dtc/util.c
	 DEP /tmp/qemu-test/src/dtc/fdtoverlay.c
	 DEP /tmp/qemu-test/src/dtc/fdtput.c
	 DEP /tmp/qemu-test/src/dtc/fdtget.c
	 DEP /tmp/qemu-test/src/dtc/fdtdump.c
	 LEX convert-dtsv0-lexer.lex.c
	 DEP /tmp/qemu-test/src/dtc/srcpos.c
	 BISON dtc-parser.tab.c
	 LEX dtc-lexer.lex.c
	 DEP /tmp/qemu-test/src/dtc/treesource.c
	 DEP /tmp/qemu-test/src/dtc/livetree.c
	 DEP /tmp/qemu-test/src/dtc/fstree.c
	 DEP /tmp/qemu-test/src/dtc/flattree.c
	 DEP /tmp/qemu-test/src/dtc/dtc.c
	 DEP /tmp/qemu-test/src/dtc/checks.c
	 DEP /tmp/qemu-test/src/dtc/data.c
	 DEP convert-dtsv0-lexer.lex.c
	 DEP dtc-parser.tab.c
	 DEP dtc-lexer.lex.c
	CHK version_gen.h
	UPD version_gen.h
	 DEP /tmp/qemu-test/src/dtc/util.c
	 CC libfdt/fdt.o
	 CC libfdt/fdt_ro.o
	 CC libfdt/fdt_wip.o
	 CC libfdt/fdt_rw.o
	 CC libfdt/fdt_sw.o
	 CC libfdt/fdt_empty_tree.o
	 CC libfdt/fdt_strerror.o
	 CC libfdt/fdt_addresses.o
	 CC libfdt/fdt_overlay.o
	 AR libfdt/libfdt.a
ar: creating libfdt/libfdt.a
a - libfdt/fdt.o
a - libfdt/fdt_ro.o
a - libfdt/fdt_wip.o
a - libfdt/fdt_sw.o
a - libfdt/fdt_rw.o
a - libfdt/fdt_strerror.o
a - libfdt/fdt_empty_tree.o
a - libfdt/fdt_addresses.o
a - libfdt/fdt_overlay.o
mkdir -p dtc/libfdt
mkdir -p dtc/tests
  CC      tests/qemu-iotests/socket_scm_helper.o
  GEN     qga/qapi-generated/qapi-gen
  CC      qapi/qapi-builtin-types.o
  CC      qapi/qapi-types-block.o
  CC      qapi/qapi-types.o
  CC      qapi/qapi-types-char.o
  CC      qapi/qapi-types-block-core.o
  CC      qapi/qapi-types-common.o
  CC      qapi/qapi-types-crypto.o
  CC      qapi/qapi-types-introspect.o
  CC      qapi/qapi-types-migration.o
  CC      qapi/qapi-types-misc.o
  CC      qapi/qapi-types-net.o
  CC      qapi/qapi-types-rocker.o
  CC      qapi/qapi-types-run-state.o
  CC      qapi/qapi-types-sockets.o
  CC      qapi/qapi-types-tpm.o
  CC      qapi/qapi-types-trace.o
  CC      qapi/qapi-types-transaction.o
  CC      qapi/qapi-types-ui.o
  CC      qapi/qapi-builtin-visit.o
  CC      qapi/qapi-visit.o
  CC      qapi/qapi-visit-block-core.o
  CC      qapi/qapi-visit-block.o
  CC      qapi/qapi-visit-char.o
  CC      qapi/qapi-visit-common.o
  CC      qapi/qapi-visit-crypto.o
  CC      qapi/qapi-visit-introspect.o
  CC      qapi/qapi-visit-migration.o
  CC      qapi/qapi-visit-misc.o
  CC      qapi/qapi-visit-net.o
  CC      qapi/qapi-visit-rocker.o
  CC      qapi/qapi-visit-run-state.o
  CC      qapi/qapi-visit-sockets.o
  CC      qapi/qapi-visit-tpm.o
  CC      qapi/qapi-visit-trace.o
  CC      qapi/qapi-visit-transaction.o
  CC      qapi/qapi-visit-ui.o
  CC      qapi/qapi-events.o
  CC      qapi/qapi-events-block-core.o
  CC      qapi/qapi-events-block.o
  CC      qapi/qapi-events-common.o
  CC      qapi/qapi-events-char.o
  CC      qapi/qapi-events-crypto.o
  CC      qapi/qapi-events-introspect.o
  CC      qapi/qapi-events-migration.o
  CC      qapi/qapi-events-misc.o
  CC      qapi/qapi-events-net.o
  CC      qapi/qapi-events-rocker.o
  CC      qapi/qapi-events-run-state.o
  CC      qapi/qapi-events-sockets.o
  CC      qapi/qapi-events-tpm.o
  CC      qapi/qapi-events-trace.o
  CC      qapi/qapi-events-transaction.o
  CC      qapi/qapi-events-ui.o
  CC      qapi/qapi-introspect.o
  CC      qapi/qapi-visit-core.o
  CC      qapi/qapi-dealloc-visitor.o
  CC      qapi/qobject-input-visitor.o
  CC      qapi/qobject-output-visitor.o
  CC      qapi/qmp-registry.o
  CC      qapi/qmp-dispatch.o
  CC      qapi/string-input-visitor.o
  CC      qapi/string-output-visitor.o
  CC      qapi/opts-visitor.o
  CC      qapi/qapi-clone-visitor.o
  CC      qapi/qmp-event.o
  CC      qapi/qapi-util.o
  CC      qobject/qnull.o
  CC      qobject/qnum.o
  CC      qobject/qstring.o
  CC      qobject/qdict.o
  CC      qobject/qlist.o
  CC      qobject/qbool.o
  CC      qobject/qlit.o
  CC      qobject/qjson.o
  CC      qobject/qobject.o
  CC      qobject/json-lexer.o
  CC      qobject/json-streamer.o
  CC      qobject/json-parser.o
  CC      trace/control.o
  CC      trace/qmp.o
  CC      util/osdep.o
  CC      util/cutils.o
  CC      util/unicode.o
  CC      util/qemu-timer-common.o
  CC      util/bufferiszero.o
  CC      util/lockcnt.o
  CC      util/aiocb.o
  CC      util/async.o
  CC      util/aio-wait.o
  CC      util/thread-pool.o
  CC      util/qemu-timer.o
  CC      util/main-loop.o
  CC      util/iohandler.o
  CC      util/compatfd.o
  CC      util/aio-posix.o
  CC      util/event_notifier-posix.o
  CC      util/mmap-alloc.o
  CC      util/oslib-posix.o
  CC      util/qemu-openpty.o
  CC      util/qemu-thread-posix.o
  CC      util/memfd.o
  CC      util/envlist.o
  CC      util/path.o
  CC      util/module.o
  CC      util/host-utils.o
  CC      util/bitmap.o
  CC      util/bitops.o
  CC      util/hbitmap.o
  CC      util/fifo8.o
  CC      util/acl.o
  CC      util/cacheinfo.o
  CC      util/error.o
  CC      util/qemu-error.o
  CC      util/id.o
  CC      util/iov.o
  CC      util/qemu-config.o
  CC      util/qemu-sockets.o
  CC      util/uri.o
  CC      util/notify.o
  CC      util/qemu-option.o
  CC      util/qemu-progress.o
  CC      util/keyval.o
  CC      util/hexdump.o
  CC      util/crc32c.o
  CC      util/uuid.o
  CC      util/throttle.o
  CC      util/getauxval.o
  CC      util/readline.o
  CC      util/rcu.o
  CC      util/qemu-coroutine.o
  CC      util/qemu-coroutine-lock.o
  CC      util/qemu-coroutine-io.o
  CC      util/qemu-coroutine-sleep.o
  CC      util/coroutine-ucontext.o
  CC      util/buffer.o
  CC      util/timed-average.o
  CC      util/base64.o
  CC      util/log.o
  CC      util/pagesize.o
  CC      util/qdist.o
  CC      util/range.o
  CC      util/qht.o
  CC      util/stats64.o
  CC      util/systemd.o
  CC      util/vfio-helpers.o
  CC      trace-root.o
  CC      util/trace.o
  CC      crypto/trace.o
  CC      io/trace.o
  CC      migration/trace.o
  CC      block/trace.o
  CC      chardev/trace.o
  CC      hw/block/trace.o
  CC      hw/block/dataplane/trace.o
  CC      hw/char/trace.o
  CC      hw/intc/trace.o
  CC      hw/net/trace.o
  CC      hw/rdma/trace.o
  CC      hw/rdma/vmw/trace.o
  CC      hw/virtio/trace.o
  CC      hw/audio/trace.o
  CC      hw/misc/trace.o
  CC      hw/misc/macio/trace.o
  CC      hw/usb/trace.o
  CC      hw/scsi/trace.o
  CC      hw/nvram/trace.o
  CC      hw/display/trace.o
  CC      hw/input/trace.o
  CC      hw/timer/trace.o
  CC      hw/dma/trace.o
  CC      hw/sparc/trace.o
  CC      hw/sparc64/trace.o
  CC      hw/sd/trace.o
  CC      hw/isa/trace.o
  CC      hw/mem/trace.o
  CC      hw/i386/trace.o
  CC      hw/i386/xen/trace.o
  CC      hw/9pfs/trace.o
  CC      hw/ppc/trace.o
  CC      hw/pci/trace.o
  CC      hw/pci-host/trace.o
  CC      hw/s390x/trace.o
  CC      hw/vfio/trace.o
  CC      hw/acpi/trace.o
  CC      hw/arm/trace.o
  CC      hw/alpha/trace.o
  CC      hw/hppa/trace.o
  CC      hw/xen/trace.o
  CC      hw/ide/trace.o
  CC      hw/tpm/trace.o
  CC      ui/trace.o
  CC      audio/trace.o
  CC      net/trace.o
  CC      target/arm/trace.o
  CC      target/i386/trace.o
  CC      target/mips/trace.o
  CC      target/sparc/trace.o
  CC      target/s390x/trace.o
  CC      target/ppc/trace.o
  CC      qom/trace.o
  CC      linux-user/trace.o
  CC      qapi/trace.o
  CC      accel/tcg/trace.o
  CC      accel/kvm/trace.o
  CC      nbd/trace.o
  CC      scsi/trace.o
  CC      crypto/pbkdf-stub.o
  CC      stubs/arch-query-cpu-def.o
  CC      stubs/arch-query-cpu-model-expansion.o
  CC      stubs/arch-query-cpu-model-comparison.o
  CC      stubs/arch-query-cpu-model-baseline.o
  CC      stubs/bdrv-next-monitor-owned.o
  CC      stubs/blk-commit-all.o
  CC      stubs/blockdev-close-all-bdrv-states.o
  CC      stubs/cpu-get-clock.o
  CC      stubs/clock-warp.o
  CC      stubs/cpu-get-icount.o
  CC      stubs/dump.o
  CC      stubs/error-printf.o
  CC      stubs/fdset.o
  CC      stubs/gdbstub.o
  CC      stubs/get-vm-name.o
  CC      stubs/iothread.o
  CC      stubs/iothread-lock.o
  CC      stubs/is-daemonized.o
  CC      stubs/machine-init-done.o
  CC      stubs/migr-blocker.o
  CC      stubs/change-state-handler.o
  CC      stubs/monitor.o
  CC      stubs/notify-event.o
  CC      stubs/qtest.o
  CC      stubs/replay.o
  CC      stubs/runstate-check.o
  CC      stubs/set-fd-handler.o
  CC      stubs/slirp.o
  CC      stubs/sysbus.o
  CC      stubs/tpm.o
  CC      stubs/trace-control.o
  CC      stubs/uuid.o
  CC      stubs/vm-stop.o
  CC      stubs/vmstate.o
  CC      stubs/qmp_pc_dimm.o
  CC      stubs/target-monitor-defs.o
  CC      stubs/target-get-monitor-def.o
  CC      stubs/vmgenid.o
  CC      stubs/pc_madt_cpu_entry.o
  CC      stubs/xen-common.o
  CC      stubs/xen-hvm.o
  CC      stubs/pci-host-piix.o
  CC      stubs/ram-block.o
  CC      contrib/ivshmem-client/ivshmem-client.o
  CC      contrib/ivshmem-client/main.o
  CC      contrib/ivshmem-server/ivshmem-server.o
  CC      contrib/ivshmem-server/main.o
  CC      qemu-nbd.o
  CC      blockjob.o
  CC      block.o
  CC      qemu-io-cmds.o
  CC      replication.o
  CC      block/raw-format.o
  CC      block/qcow.o
  CC      block/vdi.o
  CC      block/vmdk.o
  CC      block/cloop.o
  CC      block/bochs.o
/tmp/qemu-test/src/blockjob.c: In function 'block_job_state_transition':
/tmp/qemu-test/src/blockjob.c:75: warning: comparison of unsigned expression >= 0 is always true
/tmp/qemu-test/src/blockjob.c: In function 'block_job_apply_verb':
/tmp/qemu-test/src/blockjob.c:88: warning: comparison of unsigned expression >= 0 is always true
  CC      block/vvfat.o
  CC      block/dmg.o
  CC      block/vpc.o
  CC      block/qcow2.o
  CC      block/qcow2-refcount.o
  CC      block/qcow2-cluster.o
  CC      block/qcow2-snapshot.o
  CC      block/qcow2-cache.o
  CC      block/qcow2-bitmap.o
  CC      block/qed.o
  CC      block/qed-l2-cache.o
  CC      block/qed-table.o
  CC      block/qed-cluster.o
  CC      block/qed-check.o
  CC      block/vhdx.o
  CC      block/vhdx-endian.o
  CC      block/vhdx-log.o
  CC      block/quorum.o
  CC      block/parallels.o
  CC      block/blkdebug.o
  CC      block/blkverify.o
  CC      block/blkreplay.o
  CC      block/block-backend.o
  CC      block/snapshot.o
  CC      block/qapi.o
  CC      block/file-posix.o
  CC      block/null.o
  CC      block/mirror.o
  CC      block/commit.o
  CC      block/io.o
  CC      block/create.o
  CC      block/throttle-groups.o
  CC      block/nvme.o
  CC      block/nbd.o
  CC      block/nbd-client.o
  CC      block/sheepdog.o
  CC      block/accounting.o
  CC      block/dirty-bitmap.o
  CC      block/write-threshold.o
  CC      block/backup.o
  CC      block/replication.o
  CC      block/throttle.o
  CC      block/crypto.o
  CC      nbd/server.o
  CC      nbd/client.o
  CC      nbd/common.o
  CC      scsi/utils.o
  CC      scsi/pr-manager.o
  CC      scsi/pr-manager-helper.o
  CC      block/dmg-bz2.o
  CC      crypto/init.o
  CC      crypto/hash.o
  CC      crypto/hash-glib.o
  CC      crypto/hmac.o
  CC      crypto/hmac-glib.o
  CC      crypto/aes.o
  CC      crypto/desrfb.o
  CC      crypto/cipher.o
  CC      crypto/tlscreds.o
  CC      crypto/tlscredsanon.o
  CC      crypto/tlscredsx509.o
  CC      crypto/tlssession.o
  CC      crypto/secret.o
  CC      crypto/random-platform.o
  CC      crypto/pbkdf.o
  CC      crypto/ivgen.o
  CC      crypto/ivgen-essiv.o
  CC      crypto/ivgen-plain.o
  CC      crypto/ivgen-plain64.o
  CC      crypto/afsplit.o
  CC      crypto/xts.o
  CC      crypto/block.o
  CC      crypto/block-qcow.o
  CC      crypto/block-luks.o
  CC      io/channel.o
  CC      io/channel-buffer.o
  CC      io/channel-command.o
  CC      io/channel-file.o
  CC      io/channel-socket.o
  CC      io/channel-tls.o
  CC      io/channel-watch.o
  CC      io/channel-websock.o
  CC      io/channel-util.o
  CC      io/dns-resolver.o
  CC      io/net-listener.o
  CC      io/task.o
  CC      qom/object.o
  CC      qom/container.o
  CC      qom/qom-qobject.o
  CC      qom/object_interfaces.o
  GEN     qemu-img-cmds.h
  CC      qemu-io.o
  CC      scsi/qemu-pr-helper.o
  CC      qemu-bridge-helper.o
  CC      blockdev.o
  CC      blockdev-nbd.o
  CC      bootdevice.o
  CC      iothread.o
  CC      qdev-monitor.o
  CC      device-hotplug.o
  CC      os-posix.o
  CC      bt-host.o
  CC      dma-helpers.o
  CC      bt-vhci.o
  CC      vl.o
  CC      tpm.o
  CC      device_tree.o
  CC      qapi/qapi-commands.o
  CC      qapi/qapi-commands-block-core.o
  CC      qapi/qapi-commands-block.o
  CC      qapi/qapi-commands-char.o
  CC      qapi/qapi-commands-common.o
  CC      qapi/qapi-commands-crypto.o
  CC      qapi/qapi-commands-introspect.o
  CC      qapi/qapi-commands-migration.o
  CC      qapi/qapi-commands-misc.o
  CC      qapi/qapi-commands-net.o
  CC      qapi/qapi-commands-rocker.o
  CC      qapi/qapi-commands-run-state.o
  CC      qapi/qapi-commands-sockets.o
  CC      qapi/qapi-commands-tpm.o
  CC      qapi/qapi-commands-trace.o
  CC      qapi/qapi-commands-transaction.o
  CC      qapi/qapi-commands-ui.o
  CC      qmp.o
  CC      hmp.o
  CC      cpus-common.o
  CC      audio/audio.o
  CC      audio/noaudio.o
  CC      audio/wavaudio.o
  CC      audio/mixeng.o
  CC      audio/spiceaudio.o
  CC      audio/wavcapture.o
  CC      backends/rng.o
  CC      backends/rng-egd.o
  CC      backends/rng-random.o
  CC      backends/tpm.o
  CC      backends/hostmem.o
  CC      backends/hostmem-ram.o
  CC      backends/hostmem-file.o
  CC      backends/cryptodev.o
  CC      backends/cryptodev-builtin.o
  CC      backends/cryptodev-vhost.o
  CC      backends/cryptodev-vhost-user.o
  CC      backends/hostmem-memfd.o
  CC      block/stream.o
  CC      chardev/msmouse.o
  CC      chardev/wctablet.o
  CC      chardev/testdev.o
  CC      chardev/spice.o
  CC      disas/arm.o
  CC      disas/i386.o
  CC      fsdev/qemu-fsdev-dummy.o
  CC      fsdev/qemu-fsdev-opts.o
  CC      fsdev/qemu-fsdev-throttle.o
  CC      hw/acpi/core.o
  CC      hw/acpi/piix4.o
  CC      hw/acpi/pcihp.o
  CC      hw/acpi/ich9.o
  CC      hw/acpi/tco.o
  CC      hw/acpi/cpu_hotplug.o
  CC      hw/acpi/memory_hotplug.o
  CC      hw/acpi/cpu.o
  CC      hw/acpi/nvdimm.o
  CC      hw/acpi/vmgenid.o
  CC      hw/acpi/acpi_interface.o
  CC      hw/acpi/bios-linker-loader.o
  CC      hw/acpi/aml-build.o
  CC      hw/acpi/ipmi.o
  CC      hw/acpi/acpi-stub.o
  CC      hw/acpi/ipmi-stub.o
  CC      hw/audio/sb16.o
  CC      hw/audio/es1370.o
  CC      hw/audio/ac97.o
  CC      hw/audio/fmopl.o
  CC      hw/audio/adlib.o
  CC      hw/audio/gus.o
  CC      hw/audio/gusemu_hal.o
  CC      hw/audio/gusemu_mixer.o
  CC      hw/audio/cs4231a.o
  CC      hw/audio/intel-hda.o
  CC      hw/audio/hda-codec.o
  CC      hw/audio/pcspk.o
  CC      hw/audio/wm8750.o
  CC      hw/audio/pl041.o
  CC      hw/audio/lm4549.o
  CC      hw/audio/marvell_88w8618.o
  CC      hw/audio/soundhw.o
  CC      hw/block/block.o
  CC      hw/block/cdrom.o
  CC      hw/block/hd-geometry.o
  CC      hw/block/fdc.o
  CC      hw/block/m25p80.o
  CC      hw/block/nand.o
  CC      hw/block/pflash_cfi01.o
  CC      hw/block/pflash_cfi02.o
  CC      hw/block/xen_disk.o
  CC      hw/block/ecc.o
  CC      hw/block/onenand.o
  CC      hw/block/nvme.o
  CC      hw/bt/core.o
  CC      hw/bt/l2cap.o
  CC      hw/bt/sdp.o
  CC      hw/bt/hci.o
  CC      hw/bt/hid.o
  CC      hw/bt/hci-csr.o
  CC      hw/char/ipoctal232.o
  CC      hw/char/parallel.o
  CC      hw/char/parallel-isa.o
  CC      hw/char/pl011.o
  CC      hw/char/serial.o
  CC      hw/char/serial-isa.o
  CC      hw/char/serial-pci.o
  CC      hw/char/virtio-console.o
  CC      hw/char/xen_console.o
  CC      hw/char/cadence_uart.o
  CC      hw/char/cmsdk-apb-uart.o
  CC      hw/char/debugcon.o
  CC      hw/char/imx_serial.o
  CC      hw/core/qdev.o
  CC      hw/core/qdev-properties.o
  CC      hw/core/bus.o
  CC      hw/core/reset.o
  CC      hw/core/qdev-fw.o
  CC      hw/core/fw-path-provider.o
  CC      hw/core/irq.o
  CC      hw/core/nmi.o
  CC      hw/core/stream.o
  CC      hw/core/hotplug.o
  CC      hw/core/ptimer.o
  CC      hw/core/sysbus.o
  CC      hw/core/machine.o
  CC      hw/core/loader.o
  CC      hw/core/qdev-properties-system.o
  CC      hw/core/register.o
  CC      hw/core/or-irq.o
  CC      hw/core/split-irq.o
  CC      hw/core/platform-bus.o
  CC      hw/cpu/core.o
  CC      hw/display/ads7846.o
  CC      hw/display/cirrus_vga.o
  CC      hw/display/pl110.o
  CC      hw/display/sii9022.o
  CC      hw/display/ssd0303.o
  CC      hw/display/ssd0323.o
  CC      hw/display/xenfb.o
  CC      hw/display/vga-pci.o
  CC      hw/display/vga-isa.o
  CC      hw/display/vmware_vga.o
  CC      hw/display/blizzard.o
  CC      hw/display/exynos4210_fimd.o
  CC      hw/display/framebuffer.o
  CC      hw/display/tc6393xb.o
  CC      hw/display/qxl.o
  CC      hw/display/qxl-logger.o
  CC      hw/display/qxl-render.o
  CC      hw/dma/pl080.o
  CC      hw/dma/pl330.o
  CC      hw/dma/i8257.o
  CC      hw/dma/xilinx_axidma.o
  CC      hw/dma/xlnx-zynq-devcfg.o
  CC      hw/gpio/max7310.o
  CC      hw/gpio/pl061.o
  CC      hw/gpio/zaurus.o
  CC      hw/gpio/gpio_key.o
  CC      hw/i2c/core.o
  CC      hw/i2c/smbus.o
  CC      hw/i2c/smbus_eeprom.o
  CC      hw/i2c/i2c-ddc.o
  CC      hw/i2c/smbus_ich9.o
  CC      hw/i2c/versatile_i2c.o
  CC      hw/i2c/pm_smbus.o
  CC      hw/i2c/bitbang_i2c.o
  CC      hw/i2c/exynos4210_i2c.o
  CC      hw/i2c/imx_i2c.o
  CC      hw/i2c/aspeed_i2c.o
  CC      hw/ide/core.o
  CC      hw/ide/atapi.o
  CC      hw/ide/qdev.o
  CC      hw/ide/pci.o
  CC      hw/ide/isa.o
  CC      hw/ide/piix.o
  CC      hw/ide/microdrive.o
  CC      hw/ide/ahci.o
  CC      hw/ide/ich.o
  CC      hw/ide/ahci-allwinner.o
  CC      hw/input/hid.o
  CC      hw/input/lm832x.o
  CC      hw/input/pckbd.o
  CC      hw/input/pl050.o
  CC      hw/input/ps2.o
  CC      hw/input/stellaris_input.o
  CC      hw/input/tsc2005.o
  CC      hw/input/virtio-input.o
  CC      hw/input/virtio-input-hid.o
  CC      hw/input/virtio-input-host.o
  CC      hw/intc/i8259_common.o
  CC      hw/intc/i8259.o
  CC      hw/intc/pl190.o
  CC      hw/intc/xlnx-pmu-iomod-intc.o
  CC      hw/intc/xlnx-zynqmp-ipi.o
  CC      hw/intc/imx_avic.o
  CC      hw/intc/imx_gpcv2.o
  CC      hw/intc/realview_gic.o
  CC      hw/intc/ioapic_common.o
  CC      hw/intc/arm_gic_common.o
  CC      hw/intc/arm_gic.o
  CC      hw/intc/arm_gicv2m.o
  CC      hw/intc/arm_gicv3_common.o
  CC      hw/intc/arm_gicv3.o
  CC      hw/intc/arm_gicv3_dist.o
  CC      hw/intc/arm_gicv3_redist.o
  CC      hw/intc/arm_gicv3_its_common.o
  CC      hw/intc/intc.o
  CC      hw/ipack/ipack.o
  CC      hw/ipack/tpci200.o
  CC      hw/ipmi/ipmi.o
  CC      hw/ipmi/ipmi_bmc_sim.o
  CC      hw/ipmi/ipmi_bmc_extern.o
  CC      hw/ipmi/isa_ipmi_kcs.o
  CC      hw/ipmi/isa_ipmi_bt.o
  CC      hw/isa/isa-superio.o
  CC      hw/isa/isa-bus.o
  CC      hw/isa/smc37c669-superio.o
  CC      hw/isa/apm.o
  CC      hw/mem/pc-dimm.o
  CC      hw/mem/nvdimm.o
  CC      hw/misc/applesmc.o
  CC      hw/misc/max111x.o
  CC      hw/misc/tmp105.o
  CC      hw/misc/tmp421.o
  CC      hw/misc/debugexit.o
  CC      hw/misc/sga.o
  CC      hw/misc/pc-testdev.o
  CC      hw/misc/pci-testdev.o
  CC      hw/misc/edu.o
  CC      hw/misc/unimp.o
  CC      hw/misc/vmcoreinfo.o
  CC      hw/misc/arm_l2x0.o
  CC      hw/misc/arm_integrator_debug.o
  CC      hw/misc/a9scu.o
  CC      hw/misc/arm11scu.o
  CC      hw/net/xen_nic.o
  CC      hw/net/ne2000.o
  CC      hw/net/eepro100.o
  CC      hw/net/pcnet-pci.o
  CC      hw/net/pcnet.o
  CC      hw/net/e1000.o
  CC      hw/net/e1000x_common.o
  CC      hw/net/net_tx_pkt.o
  CC      hw/net/net_rx_pkt.o
  CC      hw/net/e1000e.o
  CC      hw/net/e1000e_core.o
  CC      hw/net/rtl8139.o
  CC      hw/net/vmxnet3.o
  CC      hw/net/smc91c111.o
  CC      hw/net/lan9118.o
  CC      hw/net/ne2000-isa.o
  CC      hw/net/xgmac.o
  CC      hw/net/xilinx_axienet.o
  CC      hw/net/allwinner_emac.o
  CC      hw/net/imx_fec.o
  CC      hw/net/cadence_gem.o
  CC      hw/net/stellaris_enet.o
  CC      hw/net/ftgmac100.o
  CC      hw/net/rocker/rocker.o
  CC      hw/net/rocker/rocker_fp.o
  CC      hw/net/rocker/rocker_desc.o
  CC      hw/net/rocker/rocker_world.o
  CC      hw/net/rocker/rocker_of_dpa.o
  CC      hw/net/can/can_sja1000.o
  CC      hw/net/can/can_kvaser_pci.o
  CC      hw/net/can/can_pcm3680_pci.o
  CC      hw/net/can/can_mioe3680_pci.o
  CC      hw/nvram/eeprom93xx.o
  CC      hw/nvram/eeprom_at24c.o
  CC      hw/nvram/chrp_nvram.o
  CC      hw/nvram/fw_cfg.o
  CC      hw/pci-bridge/pci_bridge_dev.o
  CC      hw/pci-bridge/pcie_root_port.o
  CC      hw/pci-bridge/gen_pcie_root_port.o
  CC      hw/pci-bridge/pcie_pci_bridge.o
  CC      hw/pci-bridge/pci_expander_bridge.o
  CC      hw/pci-bridge/xio3130_upstream.o
  CC      hw/pci-bridge/xio3130_downstream.o
  CC      hw/pci-bridge/ioh3420.o
  CC      hw/pci-bridge/i82801b11.o
  CC      hw/pci-host/pam.o
  CC      hw/pci-host/versatile.o
  CC      hw/pci-host/piix.o
  CC      hw/pci-host/q35.o
  CC      hw/pci-host/gpex.o
  CC      hw/pci-host/designware.o
  CC      hw/pci/pci.o
  CC      hw/pci/pci_bridge.o
  CC      hw/pci/msix.o
  CC      hw/pci/msi.o
  CC      hw/pci/shpc.o
  CC      hw/pci/slotid_cap.o
  CC      hw/pci/pci_host.o
  CC      hw/pci/pcie_host.o
  CC      hw/pci/pcie.o
  CC      hw/pci/pcie_aer.o
  CC      hw/pci/pcie_port.o
  CC      hw/pci/pci-stub.o
  CC      hw/pcmcia/pcmcia.o
  CC      hw/scsi/scsi-disk.o
  CC      hw/scsi/scsi-generic.o
  CC      hw/scsi/scsi-bus.o
  CC      hw/scsi/lsi53c895a.o
  CC      hw/scsi/mptsas.o
  CC      hw/scsi/mptconfig.o
  CC      hw/scsi/mptendian.o
  CC      hw/scsi/megasas.o
  CC      hw/scsi/vmw_pvscsi.o
  CC      hw/scsi/esp.o
  CC      hw/scsi/esp-pci.o
  CC      hw/sd/pl181.o
  CC      hw/sd/ssi-sd.o
  CC      hw/sd/sd.o
  CC      hw/sd/core.o
  CC      hw/sd/sdmmc-internal.o
  CC      hw/sd/sdhci.o
  CC      hw/smbios/smbios.o
  CC      hw/smbios/smbios_type_38.o
  CC      hw/smbios/smbios-stub.o
  CC      hw/smbios/smbios_type_38-stub.o
  CC      hw/ssi/pl022.o
  CC      hw/ssi/ssi.o
  CC      hw/ssi/xilinx_spips.o
  CC      hw/ssi/aspeed_smc.o
  CC      hw/ssi/stm32f2xx_spi.o
  CC      hw/ssi/mss-spi.o
  CC      hw/timer/arm_timer.o
  CC      hw/timer/arm_mptimer.o
  CC      hw/timer/armv7m_systick.o
  CC      hw/timer/a9gtimer.o
  CC      hw/timer/cadence_ttc.o
  CC      hw/timer/ds1338.o
  CC      hw/timer/hpet.o
  CC      hw/timer/i8254_common.o
  CC      hw/timer/i8254.o
  CC      hw/timer/pl031.o
  CC      hw/timer/twl92230.o
  CC      hw/timer/imx_epit.o
  CC      hw/timer/imx_gpt.o
  CC      hw/timer/stm32f2xx_timer.o
  CC      hw/timer/xlnx-zynqmp-rtc.o
  CC      hw/timer/aspeed_timer.o
  CC      hw/timer/cmsdk-apb-timer.o
  CC      hw/timer/mss-timer.o
  CC      hw/tpm/tpm_tis.o
  CC      hw/tpm/tpm_util.o
  CC      hw/tpm/tpm_crb.o
  CC      hw/tpm/tpm_passthrough.o
  CC      hw/tpm/tpm_emulator.o
  CC      hw/usb/core.o
  CC      hw/usb/combined-packet.o
  CC      hw/usb/bus.o
  CC      hw/usb/libhw.o
  CC      hw/usb/desc-msos.o
  CC      hw/usb/desc.o
  CC      hw/usb/hcd-uhci.o
  CC      hw/usb/hcd-ohci.o
  CC      hw/usb/hcd-ehci.o
  CC      hw/usb/hcd-ehci-pci.o
  CC      hw/usb/hcd-ehci-sysbus.o
  CC      hw/usb/hcd-xhci.o
  CC      hw/usb/hcd-xhci-nec.o
  CC      hw/usb/hcd-musb.o
  CC      hw/usb/dev-hub.o
  CC      hw/usb/dev-hid.o
  CC      hw/usb/dev-wacom.o
  CC      hw/usb/dev-storage.o
  CC      hw/usb/dev-uas.o
  CC      hw/usb/dev-audio.o
  CC      hw/usb/dev-serial.o
  CC      hw/usb/dev-network.o
  CC      hw/usb/dev-bluetooth.o
  CC      hw/usb/dev-smartcard-reader.o
  CC      hw/usb/ccid-card-passthru.o
  CC      hw/usb/ccid-card-emulated.o
  CC      hw/usb/dev-mtp.o
  CC      hw/usb/host-stub.o
  CC      hw/virtio/virtio-rng.o
  CC      hw/virtio/virtio-pci.o
  CC      hw/virtio/virtio-bus.o
  CC      hw/virtio/virtio-mmio.o
  CC      hw/virtio/vhost-stub.o
  CC      hw/watchdog/watchdog.o
  CC      hw/watchdog/wdt_i6300esb.o
  CC      hw/watchdog/wdt_ib700.o
  CC      hw/watchdog/wdt_aspeed.o
  CC      hw/xen/xen_backend.o
  CC      hw/xen/xen_devconfig.o
  CC      hw/xen/xen_pvdev.o
  CC      hw/xen/xen-common.o
  CC      migration/migration.o
  CC      migration/socket.o
  CC      migration/fd.o
  CC      migration/exec.o
  CC      migration/tls.o
  CC      migration/channel.o
  CC      migration/savevm.o
  CC      migration/colo-comm.o
  CC      migration/colo.o
  CC      migration/colo-failover.o
  CC      migration/vmstate.o
  CC      migration/vmstate-types.o
  CC      migration/page_cache.o
  CC      migration/qemu-file.o
  CC      migration/global_state.o
  CC      migration/qemu-file-channel.o
  CC      migration/xbzrle.o
  CC      migration/postcopy-ram.o
  CC      migration/qjson.o
  CC      migration/block-dirty-bitmap.o
  CC      migration/block.o
  CC      net/net.o
  CC      net/queue.o
  CC      net/checksum.o
  CC      net/util.o
  CC      net/hub.o
  CC      net/socket.o
  CC      net/dump.o
  CC      net/eth.o
  CC      net/l2tpv3.o
  CC      net/vhost-user.o
  CC      net/slirp.o
  CC      net/filter.o
  CC      net/filter-buffer.o
  CC      net/filter-mirror.o
  CC      net/colo-compare.o
  CC      net/colo.o
  CC      net/filter-rewriter.o
  CC      net/filter-replay.o
  CC      net/tap.o
  CC      net/tap-linux.o
  CC      net/can/can_core.o
  CC      net/can/can_host.o
  CC      qom/cpu.o
  CC      net/can/can_socketcan.o
  CC      replay/replay.o
  CC      replay/replay-internal.o
  CC      replay/replay-events.o
  CC      replay/replay-time.o
  CC      replay/replay-input.o
  CC      replay/replay-char.o
  CC      replay/replay-snapshot.o
  CC      replay/replay-net.o
  CC      replay/replay-audio.o
  CC      slirp/cksum.o
  CC      slirp/if.o
  CC      slirp/ip6_icmp.o
  CC      slirp/ip_icmp.o
  CC      slirp/ip6_input.o
  CC      slirp/ip6_output.o
  CC      slirp/ip_input.o
  CC      slirp/ip_output.o
  CC      slirp/dhcpv6.o
  CC      slirp/dnssearch.o
  CC      slirp/slirp.o
  CC      slirp/mbuf.o
  CC      slirp/misc.o
  CC      slirp/sbuf.o
  CC      slirp/tcp_input.o
  CC      slirp/socket.o
  CC      slirp/tcp_output.o
  CC      slirp/tcp_subr.o
  CC      slirp/tcp_timer.o
  CC      slirp/udp.o
  CC      slirp/udp6.o
  CC      slirp/bootp.o
  CC      slirp/tftp.o
/tmp/qemu-test/src/slirp/tcp_input.c: In function 'tcp_input':
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_p' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_len' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_tos' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_id' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_off' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_ttl' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_sum' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_src.s_addr' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_dst.s_addr' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:220: warning: 'save_ip6.ip_nh' may be used uninitialized in this function
  CC      slirp/arp_table.o
  CC      slirp/ndp_table.o
  CC      slirp/ncsi.o
  CC      ui/keymaps.o
  CC      ui/console.o
  CC      ui/cursor.o
  CC      ui/qemu-pixman.o
  CC      ui/input.o
  CC      ui/input-keymap.o
  CC      ui/input-legacy.o
  CC      ui/input-linux.o
  CC      ui/spice-core.o
  CC      ui/spice-input.o
  CC      ui/spice-display.o
  CC      ui/vnc.o
  CC      ui/vnc-enc-zlib.o
  CC      ui/vnc-enc-hextile.o
  CC      ui/vnc-enc-tight.o
  CC      ui/vnc-palette.o
  CC      ui/vnc-enc-zrle.o
  CC      ui/vnc-auth-vencrypt.o
  CC      ui/vnc-ws.o
  CC      ui/vnc-jobs.o
  CC      ui/x_keymap.o
  VERT    ui/shader/texture-blit-vert.h
  VERT    ui/shader/texture-blit-flip-vert.h
  FRAG    ui/shader/texture-blit-frag.h
  CC      ui/console-gl.o
  CC      ui/egl-helpers.o
  CC      ui/egl-context.o
  CC      audio/ossaudio.o
  CC      ui/sdl.o
  CC      ui/sdl_zoom.o
  CC      ui/gtk.o
  CC      ui/gtk-egl.o
  CC      ui/curses.o
  CC      chardev/char.o
  CC      chardev/char-fd.o
  CC      chardev/char-fe.o
  CC      chardev/char-file.o
  CC      chardev/char-io.o
  CC      chardev/char-mux.o
  CC      chardev/char-null.o
  CC      chardev/char-parallel.o
  CC      chardev/char-pipe.o
  CC      chardev/char-pty.o
  CC      chardev/char-ringbuf.o
  CC      chardev/char-serial.o
  CC      chardev/char-socket.o
  CC      chardev/char-stdio.o
  CC      chardev/char-udp.o
  LINK    tests/qemu-iotests/socket_scm_helper
  CC      qga/commands.o
  CC      qga/guest-agent-command-state.o
  CC      qga/main.o
  AS      optionrom/multiboot.o
  AS      optionrom/linuxboot.o
  CC      optionrom/linuxboot_dma.o
cc: unrecognized option '-no-integrated-as'
cc: unrecognized option '-no-integrated-as'
  AS      optionrom/kvmvapic.o
In file included from /usr/include/gtk-2.0/gtk/gtk.h:235,
                 from /tmp/qemu-test/src/include/ui/gtk.h:10,
                 from /tmp/qemu-test/src/ui/gtk-egl.c:21:
/usr/include/gtk-2.0/gtk/gtkitemfactory.h:47: warning: function declaration isn't a prototype
  BUILD   optionrom/multiboot.img
  BUILD   optionrom/linuxboot.img
  BUILD   optionrom/linuxboot_dma.img
  BUILD   optionrom/kvmvapic.img
  CC      qga/commands-posix.o
  BUILD   optionrom/multiboot.raw
  BUILD   optionrom/linuxboot.raw
  BUILD   optionrom/linuxboot_dma.raw
  BUILD   optionrom/kvmvapic.raw
  CC      qga/channel-posix.o
  SIGN    optionrom/multiboot.bin
  CC      qga/qapi-generated/qga-qapi-types.o
  CC      qga/qapi-generated/qga-qapi-visit.o
  SIGN    optionrom/linuxboot.bin
  SIGN    optionrom/linuxboot_dma.bin
  SIGN    optionrom/kvmvapic.bin
  CC      qga/qapi-generated/qga-qapi-commands.o
  AR      libqemuutil.a
  CC      qemu-img.o
  CC      ui/shader.o
  LINK    ivshmem-client
  LINK    ivshmem-server
  LINK    qemu-nbd
  LINK    qemu-img
  LINK    qemu-io
  LINK    scsi/qemu-pr-helper
  LINK    qemu-bridge-helper
In file included from /usr/include/gtk-2.0/gtk/gtk.h:235,
                 from /tmp/qemu-test/src/include/ui/gtk.h:10,
                 from /tmp/qemu-test/src/ui/gtk.c:45:
/usr/include/gtk-2.0/gtk/gtkitemfactory.h:47: warning: function declaration isn't a prototype
  LINK    qemu-ga
  GEN     x86_64-softmmu/hmp-commands.h
  GEN     x86_64-softmmu/hmp-commands-info.h
  GEN     x86_64-softmmu/config-target.h
  GEN     aarch64-softmmu/hmp-commands.h
  GEN     aarch64-softmmu/hmp-commands-info.h
  GEN     aarch64-softmmu/config-target.h
  CC      x86_64-softmmu/tcg/tcg-op-vec.o
  CC      x86_64-softmmu/tcg/tcg-op.o
  CC      x86_64-softmmu/exec.o
  CC      x86_64-softmmu/tcg/tcg.o
  CC      x86_64-softmmu/tcg/tcg-op-gvec.o
  CC      x86_64-softmmu/tcg/tcg-common.o
  CC      x86_64-softmmu/tcg/optimize.o
  CC      aarch64-softmmu/exec.o
  CC      aarch64-softmmu/tcg/tcg.o
  CC      x86_64-softmmu/fpu/softfloat.o
  CC      aarch64-softmmu/tcg/tcg-op.o
  CC      x86_64-softmmu/disas.o
  GEN     x86_64-softmmu/gdbstub-xml.c
  CC      aarch64-softmmu/tcg/tcg-op-vec.o
/tmp/qemu-test/src/fpu/softfloat.c: In function 'int_to_float':
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.exp' may be used uninitialized in this function
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.frac' may be used uninitialized in this function
  CC      aarch64-softmmu/tcg/tcg-op-gvec.o
  CC      aarch64-softmmu/tcg/tcg-common.o
  CC      x86_64-softmmu/arch_init.o
  CC      aarch64-softmmu/tcg/optimize.o
  CC      aarch64-softmmu/fpu/softfloat.o
  CC      x86_64-softmmu/cpus.o
  CC      aarch64-softmmu/disas.o
  GEN     aarch64-softmmu/gdbstub-xml.c
/tmp/qemu-test/src/fpu/softfloat.c: In function 'int_to_float':
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.exp' may be used uninitialized in this function
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.frac' may be used uninitialized in this function
  CC      x86_64-softmmu/monitor.o
  CC      x86_64-softmmu/gdbstub.o
  CC      x86_64-softmmu/balloon.o
  CC      aarch64-softmmu/arch_init.o
  CC      x86_64-softmmu/ioport.o
  CC      x86_64-softmmu/numa.o
  CC      x86_64-softmmu/qtest.o
  CC      aarch64-softmmu/cpus.o
  CC      x86_64-softmmu/memory.o
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:36: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:45: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:54: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:63: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:74: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:85: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:95: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:104: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:113: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:122: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:131: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:142: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:153: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:164: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:174: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:185: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:195: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:204: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:213: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:222: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:231: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:240: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:249: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:258: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:267: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:276: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:286: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:296: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:305: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:314: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:324: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:334: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:343: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:352: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:361: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:370: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:379: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:388: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:397: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:406: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:416: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:462: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:480: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:489: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:520: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:529: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:538: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:547: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:557: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:567: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:35: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:44: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:53: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:64: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:73: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:82: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:91: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:100: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:109: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:118: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:128: error: unknown field 'async_cmd' specified in initializer
./hmp-commands.h:128: warning: initialization from incompatible pointer type
./hmp-commands.h:138: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:148: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:169: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:178: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:187: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:197: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:207: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:216: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:225: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:234: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:243: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:252: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:261: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:270: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:280: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:290: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:299: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:308: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:317: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:327: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:336: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:345: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:354: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:364: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:374: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:383: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:392: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:401: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:410: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:418: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:461: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:485: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:495: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:504: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:512: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:526: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:536: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:545: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:554: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:564: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:577: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:587: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:596: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:612: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:651: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:662: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:675: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:691: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:708: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:721: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:740: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:749: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:759: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:769: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:779: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:790: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:800: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:810: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:819: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:829: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:839: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:848: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:857: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:866: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:875: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:884: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:892: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:900: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:908: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:919: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:929: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:938: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:947: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:956: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:965: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:974: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:983: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:993: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1002: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1012: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1022: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1031: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1040: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1049: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1058: error: unknown field 'cmd' specified in initializer
  CC      aarch64-softmmu/monitor.o
make[1]: *** [monitor.o] Error 1
make[1]: *** Waiting for unfinished jobs....
  CC      aarch64-softmmu/gdbstub.o
  CC      aarch64-softmmu/balloon.o
  CC      aarch64-softmmu/ioport.o
  CC      aarch64-softmmu/numa.o
  CC      aarch64-softmmu/qtest.o
  CC      aarch64-softmmu/memory.o
  CC      aarch64-softmmu/memory_mapping.o
  CC      aarch64-softmmu/dump.o
  CC      aarch64-softmmu/migration/ram.o
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:36: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:45: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:54: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:63: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:95: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:104: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:113: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:122: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:131: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:164: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:174: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:185: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:195: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:204: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:213: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:222: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:231: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:240: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:249: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:258: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:267: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:276: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:286: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:296: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:305: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:314: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:324: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:334: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:343: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:352: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:361: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:370: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:379: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:388: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:397: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:406: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:416: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:462: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:480: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:489: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:520: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:529: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:538: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:547: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:557: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:35: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:44: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:53: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:64: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:73: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:82: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:91: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:100: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:109: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:118: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:128: error: unknown field 'async_cmd' specified in initializer
./hmp-commands.h:128: warning: initialization from incompatible pointer type
./hmp-commands.h:138: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:148: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:169: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:178: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:187: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:197: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:207: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:216: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:225: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:234: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:243: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:252: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:261: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:270: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:280: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:290: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:299: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:308: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:317: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:327: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:336: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:345: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:354: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:364: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:374: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:383: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:392: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:401: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:410: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:418: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:461: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:485: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:495: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:504: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:512: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:526: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:536: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:545: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:554: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:564: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:577: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:587: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:596: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:612: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:651: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:662: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:675: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:691: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:708: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:721: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:740: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:749: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:759: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:769: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:779: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:790: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:800: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:810: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:819: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:829: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:839: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:848: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:857: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:866: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:875: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:884: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:892: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:900: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:908: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:929: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:938: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:947: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:956: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:965: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:974: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:983: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:993: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1002: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1012: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1022: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1031: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1040: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1049: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1058: error: unknown field 'cmd' specified in initializer
make[1]: *** [monitor.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [subdir-aarch64-softmmu] Error 2
make: *** Waiting for unfinished jobs....
make: *** [subdir-x86_64-softmmu] Error 2
Traceback (most recent call last):
  File "./tests/docker/docker.py", line 407, in <module>
    sys.exit(main())
  File "./tests/docker/docker.py", line 404, in main
    return args.cmdobj.run(args, argv)
  File "./tests/docker/docker.py", line 261, in run
    return Docker().run(argv, args.keep, quiet=args.quiet)
  File "./tests/docker/docker.py", line 229, in run
    quiet=quiet)
  File "./tests/docker/docker.py", line 147, in _do_check
    return subprocess.check_call(self._command + cmd, **kwargs)
  File "/usr/lib64/python2.7/subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['docker', 'run', '--label', 'com.qemu.instance.uuid=f3fcb0fe311c11e8a88c52540069c830', '-u', '0', '--security-opt', 'seccomp=unconfined', '--rm', '--net=none', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=8', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/root/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-1pv572w4/src/docker-src.2018-03-26-13.41.28.30980:/var/tmp/qemu:z,ro', 'qemu:centos6', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2
make[1]: *** [tests/docker/Makefile.include:129: docker-run] Error 1
make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-1pv572w4/src'
make: *** [tests/docker/Makefile.include:163: docker-run-test-quick@centos6] Error 2

real	1m41.191s
user	0m4.389s
sys	0m3.736s
=== OUTPUT END ===

Test command exited with code: 2


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (39 preceding siblings ...)
  2018-03-26 17:43 ` no-reply
@ 2018-03-26 17:55 ` no-reply
  2018-04-04  9:34 ` Stefan Hajnoczi
                   ` (2 subsequent siblings)
  43 siblings, 0 replies; 61+ messages in thread
From: no-reply @ 2018-03-26 17:55 UTC (permalink / raw)
  To: marcandre.lureau
  Cc: famz, qemu-devel, ehabkost, quintela, armbru, dgilbert, kraxel,
	crosa, mdroth

Hi,

This series failed docker-build@min-glib build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

Type: series
Message-id: 20180326150916.9602-1-marcandre.lureau@redhat.com
Subject: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type

=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
export J=8
time make docker-test-build@min-glib
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
fd0470a9a5 hmp: call the asynchronous QMP screendump to fix outdated/glitches
51e20a57af monitor: teach HMP about asynchronous commands
1da4258136 monitor: start making qmp_human_monitor_command() asynchronous
4dc553eb62 console: make screendump asynchronous
37ce1da30f console: add graphic_hw_update_done()
e1b747ed7c console: graphic_hw_update return true if async
b97cbbac0d monitor: add qmp_return_get_monitor()
5d1e72cc83 qmp: add qmp_return_is_cancelled()
906373083b scripts: learn 'async' qapi commands
32594530ed qmp: introduce asynchronous command type
7436d3c044 QmpSession: return orderly
b5dcacb7b8 QmpSession: keep a queue of pending commands
2aec5b4175 qmp: fold do_qmp_dispatch() in qmp_dispatch()
82787d748a qmp: remove need for qobject_from_jsonf()
5118223e21 qmp: remove qmp_build_error_object()
59bd726436 QmpSession: introduce QmpReturn
123884b2b3 monitor: use QmpSession parsing and common dispatch code
99c8c44b05 QmpSession: add a dispatch callback
5c6561a277 QmpSession: add json parser and use it in qga
566650d56c QmpSession: add a return_cb
8d86248fef qmp: add QmpSession
9cd33a0c42 qmp: constify qmp_is_oob()
e7a01993d2 qmp: move 'id' copy to qmp_dispatch()
5a8e8359b0 qmp: pass and return a QDict to qmp_dispatch()
87de98918d monitor: simplify monitor_qmp_respond()
86a0247e95 qga: process_event() simplification
ba4ee2424c tests: add a qmp success-response test
5949924e12 tests: change /0.15/* tests to /qmp/*
fdeef976fd tests: add a few qemu-qmp tests
77cb805571 json: remove useless return value from lexer/parser
68d8588250 json-lexer: make it safe to call multiple times
4cf11d60e6 json-parser: always set an error if return NULL
7f5c39ac74 monitor: no need to remove desc before replacing it
fec6004793 monitor: further simplify previous patch
1887d35641 monitor: no need to save need_resume
af9f30ebb5 Revert "qmp: isolate responses into io thread"
b2cdd3c9c2 qmp-shell: learn to send commands with quoted arguments
b21608009a HACK: add back OOB

=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-p7moby5j/src/dtc'...
Submodule path 'dtc': checked out 'e54388015af1fb4bf04d0bca99caba1074d9cc42'
  BUILD   min-glib
make[1]: Entering directory '/var/tmp/patchew-tester-tmp-p7moby5j/src'
  GEN     /var/tmp/patchew-tester-tmp-p7moby5j/src/docker-src.2018-03-26-13.53.44.4674/qemu.tar
Cloning into '/var/tmp/patchew-tester-tmp-p7moby5j/src/docker-src.2018-03-26-13.53.44.4674/qemu.tar.vroot'...
done.
Checking out files:  46% (2792/6057)   
Checking out files:  47% (2847/6057)   
Checking out files:  48% (2908/6057)   
Checking out files:  49% (2968/6057)   
Checking out files:  50% (3029/6057)   
Checking out files:  51% (3090/6057)   
Checking out files:  52% (3150/6057)   
Checking out files:  53% (3211/6057)   
Checking out files:  54% (3271/6057)   
Checking out files:  55% (3332/6057)   
Checking out files:  56% (3392/6057)   
Checking out files:  57% (3453/6057)   
Checking out files:  58% (3514/6057)   
Checking out files:  59% (3574/6057)   
Checking out files:  60% (3635/6057)   
Checking out files:  61% (3695/6057)   
Checking out files:  62% (3756/6057)   
Checking out files:  63% (3816/6057)   
Checking out files:  64% (3877/6057)   
Checking out files:  65% (3938/6057)   
Checking out files:  66% (3998/6057)   
Checking out files:  67% (4059/6057)   
Checking out files:  68% (4119/6057)   
Checking out files:  69% (4180/6057)   
Checking out files:  70% (4240/6057)   
Checking out files:  71% (4301/6057)   
Checking out files:  72% (4362/6057)   
Checking out files:  73% (4422/6057)   
Checking out files:  74% (4483/6057)   
Checking out files:  75% (4543/6057)   
Checking out files:  76% (4604/6057)   
Checking out files:  77% (4664/6057)   
Checking out files:  78% (4725/6057)   
Checking out files:  79% (4786/6057)   
Checking out files:  80% (4846/6057)   
Checking out files:  81% (4907/6057)   
Checking out files:  82% (4967/6057)   
Checking out files:  83% (5028/6057)   
Checking out files:  84% (5088/6057)   
Checking out files:  85% (5149/6057)   
Checking out files:  86% (5210/6057)   
Checking out files:  87% (5270/6057)   
Checking out files:  88% (5331/6057)   
Checking out files:  89% (5391/6057)   
Checking out files:  90% (5452/6057)   
Checking out files:  91% (5512/6057)   
Checking out files:  92% (5573/6057)   
Checking out files:  93% (5634/6057)   
Checking out files:  94% (5694/6057)   
Checking out files:  95% (5755/6057)   
Checking out files:  96% (5815/6057)   
Checking out files:  97% (5876/6057)   
Checking out files:  97% (5934/6057)   
Checking out files:  98% (5936/6057)   
Checking out files:  99% (5997/6057)   
Checking out files: 100% (6057/6057)   
Checking out files: 100% (6057/6057), done.
Your branch is up-to-date with 'origin/test'.
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-p7moby5j/src/docker-src.2018-03-26-13.53.44.4674/qemu.tar.vroot/dtc'...
Submodule path 'dtc': checked out 'e54388015af1fb4bf04d0bca99caba1074d9cc42'
Submodule 'ui/keycodemapdb' (git://git.qemu.org/keycodemapdb.git) registered for path 'ui/keycodemapdb'
Cloning into '/var/tmp/patchew-tester-tmp-p7moby5j/src/docker-src.2018-03-26-13.53.44.4674/qemu.tar.vroot/ui/keycodemapdb'...
Submodule path 'ui/keycodemapdb': checked out '6b3d716e2b6472eb7189d3220552280ef3d832ce'
  COPY    RUNNER
    RUN test-build in qemu:min-glib 
Environment variables:
HOSTNAME=a291d059b84c
MAKEFLAGS= -j8
J=8
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
TARGET_LIST=
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
FEATURES= dtc
DEBUG=
_=/usr/bin/env

Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/tmp/qemu-test/install
No C++ compiler available; disabling C++ specific optional code
Install prefix    /tmp/qemu-test/install
BIOS directory    /tmp/qemu-test/install/share/qemu
firmware path     /tmp/qemu-test/install/share/qemu-firmware
binary directory  /tmp/qemu-test/install/bin
library directory /tmp/qemu-test/install/lib
module directory  /tmp/qemu-test/install/lib/qemu
libexec directory /tmp/qemu-test/install/libexec
include directory /tmp/qemu-test/install/include
config directory  /tmp/qemu-test/install/etc
local state directory   /tmp/qemu-test/install/var
Manual directory  /tmp/qemu-test/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /tmp/qemu-test/src
GIT binary        git
GIT submodules    
C compiler        cc
Host C compiler   cc
C++ compiler      
Objective-C compiler cc
ARFLAGS           rv
CFLAGS            -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g 
QEMU_CFLAGS       -I/usr/include/pixman-1   -I$(SRC_PATH)/dtc/libfdt -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -Wendif-labels -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all -Wno-missing-braces
LDFLAGS           -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g 
make              make
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          x86_64
host big endian   no
target list       x86_64-softmmu aarch64-softmmu
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
SDL support       yes (1.2.14)
GTK support       no 
GTK GL support    no
VTE support       no 
TLS priority      NORMAL
GNUTLS support    no
GNUTLS rnd        no
libgcrypt         no
libgcrypt kdf     no
nettle            no 
nettle kdf        no
libtasn1          no
curses support    no
virgl support     no
curl support      no
mingw32 support   no
Audio drivers     oss
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    no
Multipath support no
VNC support       yes
VNC SASL support  no
VNC JPEG support  no
VNC PNG support   no
xen support       no
brlapi support    no
bluez  support    no
Documentation     no
PIE               yes
vde support       no
netmap support    no
Linux AIO support no
ATTR/XATTR support yes
Install blobs     yes
KVM support       yes
HAX support       no
HVF support       no
WHPX support      no
TCG support       yes
TCG debug enabled no
TCG interpreter   no
malloc trim support yes
RDMA support      no
fdt support       yes
membarrier        no
preadv support    yes
fdatasync         yes
madvise           yes
posix_madvise     yes
posix_memalign    yes
libcap-ng support no
vhost-net support yes
vhost-crypto support yes
vhost-scsi support yes
vhost-vsock support yes
vhost-user support yes
Trace backends    log
spice support     no 
rbd support       no
xfsctl support    no
smartcard support no
libusb            no
usb net redir     no
OpenGL support    no
OpenGL dmabufs    no
libiscsi support  no
libnfs support    no
build guest agent yes
QGA VSS support   no
QGA w32 disk info no
QGA MSI support   no
seccomp support   no
coroutine backend ucontext
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   no
TPM passthrough   yes
TPM emulator      yes
QOM debugging     yes
Live block migration yes
lzo support       no
snappy support    no
bzip2 support     no
NUMA host support no
libxml2           no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
VxHS block device no
capstone          no

WARNING: Use of SDL 1.2 is deprecated and will be removed in
WARNING: future releases. Please switch to using SDL 2.0
mkdir -p dtc/libfdt
mkdir -p dtc/tests
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     aarch64-softmmu/config-devices.mak.tmp
  GEN     config-host.h
  GEN     qemu-options.def
  GEN     qapi-gen
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
  GEN     trace/generated-helpers.h
  GEN     trace/generated-helpers.c
  GEN     module_block.h
  GEN     x86_64-softmmu/config-devices.mak
  GEN     aarch64-softmmu/config-devices.mak
  GEN     ui/input-keymap-linux-to-qcode.c
  GEN     ui/input-keymap-qcode-to-atset1.c
  GEN     ui/input-keymap-atset1-to-qcode.c
  GEN     ui/input-keymap-qcode-to-atset2.c
  GEN     ui/input-keymap-qcode-to-atset3.c
  GEN     ui/input-keymap-qcode-to-linux.c
  GEN     ui/input-keymap-qcode-to-qnum.c
  GEN     ui/input-keymap-qcode-to-sun.c
  GEN     ui/input-keymap-qnum-to-qcode.c
  GEN     ui/input-keymap-usb-to-qcode.c
  GEN     ui/input-keymap-win32-to-qcode.c
  GEN     ui/input-keymap-x11-to-qcode.c
  GEN     ui/input-keymap-xorgevdev-to-qcode.c
  GEN     ui/input-keymap-xorgkbd-to-qcode.c
  GEN     ui/input-keymap-xorgxquartz-to-qcode.c
  GEN     ui/input-keymap-xorgxwin-to-qcode.c
  GEN     tests/test-qapi-gen
  GEN     trace-root.h
  GEN     util/trace.h
  GEN     crypto/trace.h
  GEN     io/trace.h
  GEN     migration/trace.h
  GEN     block/trace.h
  GEN     chardev/trace.h
  GEN     hw/block/trace.h
  GEN     hw/block/dataplane/trace.h
  GEN     hw/char/trace.h
  GEN     hw/intc/trace.h
  GEN     hw/net/trace.h
  GEN     hw/rdma/trace.h
  GEN     hw/rdma/vmw/trace.h
  GEN     hw/virtio/trace.h
  GEN     hw/audio/trace.h
  GEN     hw/misc/trace.h
  GEN     hw/misc/macio/trace.h
  GEN     hw/usb/trace.h
  GEN     hw/scsi/trace.h
  GEN     hw/nvram/trace.h
  GEN     hw/display/trace.h
  GEN     hw/input/trace.h
  GEN     hw/timer/trace.h
  GEN     hw/dma/trace.h
  GEN     hw/sparc/trace.h
  GEN     hw/sparc64/trace.h
  GEN     hw/sd/trace.h
  GEN     hw/isa/trace.h
  GEN     hw/mem/trace.h
  GEN     hw/i386/trace.h
  GEN     hw/i386/xen/trace.h
  GEN     hw/9pfs/trace.h
  GEN     hw/ppc/trace.h
  GEN     hw/pci/trace.h
  GEN     hw/pci-host/trace.h
  GEN     hw/s390x/trace.h
  GEN     hw/vfio/trace.h
  GEN     hw/acpi/trace.h
  GEN     hw/arm/trace.h
  GEN     hw/alpha/trace.h
  GEN     hw/hppa/trace.h
  GEN     hw/xen/trace.h
  GEN     hw/ide/trace.h
  GEN     hw/tpm/trace.h
  GEN     ui/trace.h
  GEN     audio/trace.h
  GEN     net/trace.h
  GEN     target/arm/trace.h
  GEN     target/i386/trace.h
  GEN     target/mips/trace.h
  GEN     target/sparc/trace.h
  GEN     target/s390x/trace.h
  GEN     target/ppc/trace.h
  GEN     qom/trace.h
  GEN     linux-user/trace.h
  GEN     qapi/trace.h
  GEN     accel/tcg/trace.h
  GEN     accel/kvm/trace.h
  GEN     nbd/trace.h
  GEN     trace-root.c
  GEN     scsi/trace.h
  GEN     util/trace.c
  GEN     crypto/trace.c
  GEN     io/trace.c
  GEN     migration/trace.c
  GEN     block/trace.c
  GEN     chardev/trace.c
  GEN     hw/block/trace.c
  GEN     hw/block/dataplane/trace.c
  GEN     hw/char/trace.c
  GEN     hw/intc/trace.c
  GEN     hw/net/trace.c
  GEN     hw/rdma/trace.c
  GEN     hw/rdma/vmw/trace.c
  GEN     hw/virtio/trace.c
  GEN     hw/audio/trace.c
  GEN     hw/misc/trace.c
  GEN     hw/misc/macio/trace.c
  GEN     hw/usb/trace.c
  GEN     hw/scsi/trace.c
  GEN     hw/nvram/trace.c
  GEN     hw/display/trace.c
  GEN     hw/input/trace.c
  GEN     hw/timer/trace.c
  GEN     hw/dma/trace.c
  GEN     hw/sparc/trace.c
  GEN     hw/sparc64/trace.c
  GEN     hw/sd/trace.c
  GEN     hw/isa/trace.c
  GEN     hw/mem/trace.c
  GEN     hw/i386/trace.c
  GEN     hw/i386/xen/trace.c
  GEN     hw/9pfs/trace.c
  GEN     hw/ppc/trace.c
  GEN     hw/pci/trace.c
  GEN     hw/pci-host/trace.c
  GEN     hw/s390x/trace.c
  GEN     hw/vfio/trace.c
  GEN     hw/acpi/trace.c
  GEN     hw/arm/trace.c
  GEN     hw/alpha/trace.c
  GEN     hw/hppa/trace.c
  GEN     hw/xen/trace.c
  GEN     hw/ide/trace.c
  GEN     hw/tpm/trace.c
  GEN     ui/trace.c
  GEN     audio/trace.c
  GEN     net/trace.c
  GEN     target/arm/trace.c
  GEN     target/i386/trace.c
  GEN     target/mips/trace.c
  GEN     target/sparc/trace.c
  GEN     target/s390x/trace.c
  GEN     target/ppc/trace.c
  GEN     qom/trace.c
  GEN     linux-user/trace.c
  GEN     qapi/trace.c
  GEN     accel/tcg/trace.c
  GEN     accel/kvm/trace.c
  GEN     nbd/trace.c
  GEN     scsi/trace.c
  GEN     config-all-devices.mak
	 DEP /tmp/qemu-test/src/dtc/tests/dumptrees.c
	 DEP /tmp/qemu-test/src/dtc/tests/trees.S
	 DEP /tmp/qemu-test/src/dtc/tests/testutils.c
	 DEP /tmp/qemu-test/src/dtc/tests/value-labels.c
	 DEP /tmp/qemu-test/src/dtc/tests/asm_tree_dump.c
	 DEP /tmp/qemu-test/src/dtc/tests/check_path.c
	 DEP /tmp/qemu-test/src/dtc/tests/truncated_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/overlay_bad_fixup.c
	 DEP /tmp/qemu-test/src/dtc/tests/overlay.c
	 DEP /tmp/qemu-test/src/dtc/tests/subnode_iterate.c
	 DEP /tmp/qemu-test/src/dtc/tests/property_iterate.c
	 DEP /tmp/qemu-test/src/dtc/tests/integer-expressions.c
	 DEP /tmp/qemu-test/src/dtc/tests/utilfdt_test.c
	 DEP /tmp/qemu-test/src/dtc/tests/path_offset_aliases.c
	 DEP /tmp/qemu-test/src/dtc/tests/add_subnode_with_nops.c
	 DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_unordered.c
	 DEP /tmp/qemu-test/src/dtc/tests/dtb_reverse.c
	 DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_ordered.c
	 DEP /tmp/qemu-test/src/dtc/tests/extra-terminating-null.c
	 DEP /tmp/qemu-test/src/dtc/tests/incbin.c
	 DEP /tmp/qemu-test/src/dtc/tests/phandle_format.c
	 DEP /tmp/qemu-test/src/dtc/tests/boot-cpuid.c
	 DEP /tmp/qemu-test/src/dtc/tests/path-references.c
	 DEP /tmp/qemu-test/src/dtc/tests/references.c
	 DEP /tmp/qemu-test/src/dtc/tests/string_escapes.c
	 DEP /tmp/qemu-test/src/dtc/tests/propname_escapes.c
	 DEP /tmp/qemu-test/src/dtc/tests/appendprop2.c
	 DEP /tmp/qemu-test/src/dtc/tests/appendprop1.c
	 DEP /tmp/qemu-test/src/dtc/tests/del_node.c
	 DEP /tmp/qemu-test/src/dtc/tests/del_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/setprop.c
	 DEP /tmp/qemu-test/src/dtc/tests/set_name.c
	 DEP /tmp/qemu-test/src/dtc/tests/rw_tree1.c
	 DEP /tmp/qemu-test/src/dtc/tests/open_pack.c
	 DEP /tmp/qemu-test/src/dtc/tests/nopulate.c
	 DEP /tmp/qemu-test/src/dtc/tests/mangle-layout.c
	 DEP /tmp/qemu-test/src/dtc/tests/move_and_save.c
	 DEP /tmp/qemu-test/src/dtc/tests/sw_tree1.c
	 DEP /tmp/qemu-test/src/dtc/tests/nop_node.c
	 DEP /tmp/qemu-test/src/dtc/tests/nop_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/setprop_inplace.c
	 DEP /tmp/qemu-test/src/dtc/tests/stringlist.c
	 DEP /tmp/qemu-test/src/dtc/tests/addr_size_cells.c
	 DEP /tmp/qemu-test/src/dtc/tests/notfound.c
	 DEP /tmp/qemu-test/src/dtc/tests/sized_cells.c
	 DEP /tmp/qemu-test/src/dtc/tests/char_literal.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_alias.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_compatible.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_check_compatible.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_phandle.c
	 DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_prop_value.c
	 DEP /tmp/qemu-test/src/dtc/tests/parent_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/supernode_atdepth_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_path.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_phandle.c
	 DEP /tmp/qemu-test/src/dtc/tests/getprop.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_name.c
	 DEP /tmp/qemu-test/src/dtc/tests/path_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/find_property.c
	 DEP /tmp/qemu-test/src/dtc/tests/subnode_offset.c
	 DEP /tmp/qemu-test/src/dtc/tests/root_node.c
	 DEP /tmp/qemu-test/src/dtc/tests/get_mem_rsv.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_overlay.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_addresses.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_empty_tree.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_strerror.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_rw.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_sw.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_wip.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt_ro.c
	 DEP /tmp/qemu-test/src/dtc/libfdt/fdt.c
	 DEP /tmp/qemu-test/src/dtc/util.c
	 DEP /tmp/qemu-test/src/dtc/fdtoverlay.c
	 DEP /tmp/qemu-test/src/dtc/fdtput.c
	 DEP /tmp/qemu-test/src/dtc/fdtget.c
	 DEP /tmp/qemu-test/src/dtc/fdtdump.c
	 LEX convert-dtsv0-lexer.lex.c
make[1]: flex: Command not found
	 DEP /tmp/qemu-test/src/dtc/srcpos.c
	 BISON dtc-parser.tab.c
	 LEX dtc-lexer.lex.c
make[1]: bison: Command not found
make[1]: flex: Command not found
	 DEP /tmp/qemu-test/src/dtc/treesource.c
	 DEP /tmp/qemu-test/src/dtc/fstree.c
	 DEP /tmp/qemu-test/src/dtc/livetree.c
	 DEP /tmp/qemu-test/src/dtc/flattree.c
	 DEP /tmp/qemu-test/src/dtc/dtc.c
	 DEP /tmp/qemu-test/src/dtc/data.c
	 DEP /tmp/qemu-test/src/dtc/checks.c
	CHK version_gen.h
	 LEX dtc-lexer.lex.c
make[1]: flex: Command not found
	 BISON dtc-parser.tab.c
	 LEX convert-dtsv0-lexer.lex.c
make[1]: bison: Command not found
make[1]: flex: Command not found
	UPD version_gen.h
	 DEP /tmp/qemu-test/src/dtc/util.c
	 BISON dtc-parser.tab.c
make[1]: bison: Command not found
	 LEX convert-dtsv0-lexer.lex.c
	 LEX dtc-lexer.lex.c
make[1]: flex: Command not found
make[1]: flex: Command not found
	 CC libfdt/fdt.o
	 CC libfdt/fdt_ro.o
	 CC libfdt/fdt_wip.o
	 CC libfdt/fdt_sw.o
	 CC libfdt/fdt_rw.o
	 CC libfdt/fdt_strerror.o
	 CC libfdt/fdt_empty_tree.o
	 CC libfdt/fdt_addresses.o
	 CC libfdt/fdt_overlay.o
	 AR libfdt/libfdt.a
ar: creating libfdt/libfdt.a
a - libfdt/fdt.o
a - libfdt/fdt_ro.o
a - libfdt/fdt_wip.o
a - libfdt/fdt_sw.o
a - libfdt/fdt_rw.o
a - libfdt/fdt_strerror.o
a - libfdt/fdt_empty_tree.o
a - libfdt/fdt_addresses.o
a - libfdt/fdt_overlay.o
mkdir -p dtc/libfdt
mkdir -p dtc/tests
	 LEX dtc-lexer.lex.c
	 LEX convert-dtsv0-lexer.lex.c
make[1]: flex: Command not found
make[1]: flex: Command not found
make[1]: bison: Command not found
	 BISON dtc-parser.tab.c
  CC      tests/qemu-iotests/socket_scm_helper.o
  GEN     qga/qapi-generated/qapi-gen
  CC      qapi/qapi-types-block.o
  CC      qapi/qapi-builtin-types.o
  CC      qapi/qapi-types-char.o
  CC      qapi/qapi-types-block-core.o
  CC      qapi/qapi-types-common.o
  CC      qapi/qapi-types.o
  CC      qapi/qapi-types-crypto.o
  CC      qapi/qapi-types-introspect.o
  CC      qapi/qapi-types-migration.o
  CC      qapi/qapi-types-misc.o
  CC      qapi/qapi-types-net.o
  CC      qapi/qapi-types-rocker.o
  CC      qapi/qapi-types-run-state.o
  CC      qapi/qapi-types-sockets.o
  CC      qapi/qapi-types-tpm.o
  CC      qapi/qapi-types-trace.o
  CC      qapi/qapi-types-transaction.o
  CC      qapi/qapi-types-ui.o
  CC      qapi/qapi-builtin-visit.o
  CC      qapi/qapi-visit.o
  CC      qapi/qapi-visit-block-core.o
  CC      qapi/qapi-visit-block.o
  CC      qapi/qapi-visit-char.o
  CC      qapi/qapi-visit-common.o
  CC      qapi/qapi-visit-crypto.o
  CC      qapi/qapi-visit-introspect.o
  CC      qapi/qapi-visit-migration.o
  CC      qapi/qapi-visit-misc.o
  CC      qapi/qapi-visit-rocker.o
  CC      qapi/qapi-visit-net.o
  CC      qapi/qapi-visit-run-state.o
  CC      qapi/qapi-visit-tpm.o
  CC      qapi/qapi-visit-trace.o
  CC      qapi/qapi-visit-sockets.o
  CC      qapi/qapi-visit-transaction.o
  CC      qapi/qapi-visit-ui.o
  CC      qapi/qapi-events.o
  CC      qapi/qapi-events-block-core.o
  CC      qapi/qapi-events-block.o
  CC      qapi/qapi-events-char.o
  CC      qapi/qapi-events-common.o
  CC      qapi/qapi-events-crypto.o
  CC      qapi/qapi-events-introspect.o
  CC      qapi/qapi-events-migration.o
  CC      qapi/qapi-events-misc.o
  CC      qapi/qapi-events-net.o
  CC      qapi/qapi-events-rocker.o
  CC      qapi/qapi-events-run-state.o
  CC      qapi/qapi-events-sockets.o
  CC      qapi/qapi-events-tpm.o
  CC      qapi/qapi-events-trace.o
  CC      qapi/qapi-events-transaction.o
  CC      qapi/qapi-events-ui.o
  CC      qapi/qapi-introspect.o
  CC      qapi/qapi-visit-core.o
  CC      qapi/qapi-dealloc-visitor.o
  CC      qapi/qobject-input-visitor.o
  CC      qapi/qobject-output-visitor.o
  CC      qapi/qmp-registry.o
  CC      qapi/qmp-dispatch.o
  CC      qapi/string-input-visitor.o
  CC      qapi/string-output-visitor.o
  CC      qapi/opts-visitor.o
  CC      qapi/qapi-clone-visitor.o
  CC      qapi/qmp-event.o
  CC      qapi/qapi-util.o
  CC      qobject/qnull.o
  CC      qobject/qnum.o
  CC      qobject/qstring.o
  CC      qobject/qdict.o
  CC      qobject/qlist.o
  CC      qobject/qbool.o
  CC      qobject/qlit.o
  CC      qobject/qjson.o
  CC      qobject/qobject.o
  CC      qobject/json-streamer.o
  CC      qobject/json-lexer.o
  CC      qobject/json-parser.o
  CC      trace/control.o
  CC      trace/qmp.o
  CC      util/osdep.o
  CC      util/cutils.o
  CC      util/unicode.o
  CC      util/qemu-timer-common.o
  CC      util/bufferiszero.o
  CC      util/lockcnt.o
  CC      util/aiocb.o
  CC      util/async.o
  CC      util/aio-wait.o
  CC      util/thread-pool.o
  CC      util/qemu-timer.o
  CC      util/main-loop.o
  CC      util/iohandler.o
  CC      util/aio-posix.o
  CC      util/compatfd.o
  CC      util/event_notifier-posix.o
  CC      util/mmap-alloc.o
  CC      util/oslib-posix.o
  CC      util/qemu-openpty.o
  CC      util/qemu-thread-posix.o
  CC      util/memfd.o
  CC      util/envlist.o
  CC      util/path.o
  CC      util/module.o
  CC      util/bitmap.o
  CC      util/bitops.o
  CC      util/host-utils.o
  CC      util/hbitmap.o
  CC      util/fifo8.o
  CC      util/acl.o
  CC      util/cacheinfo.o
  CC      util/error.o
  CC      util/qemu-error.o
  CC      util/id.o
  CC      util/iov.o
  CC      util/qemu-config.o
  CC      util/qemu-sockets.o
  CC      util/uri.o
  CC      util/notify.o
  CC      util/qemu-option.o
  CC      util/qemu-progress.o
  CC      util/keyval.o
  CC      util/hexdump.o
  CC      util/crc32c.o
  CC      util/uuid.o
  CC      util/throttle.o
  CC      util/getauxval.o
  CC      util/readline.o
  CC      util/rcu.o
  CC      util/qemu-coroutine.o
  CC      util/qemu-coroutine-lock.o
  CC      util/qemu-coroutine-io.o
  CC      util/qemu-coroutine-sleep.o
  CC      util/coroutine-ucontext.o
  CC      util/buffer.o
  CC      util/timed-average.o
  CC      util/base64.o
  CC      util/log.o
  CC      util/pagesize.o
  CC      util/qdist.o
  CC      util/qht.o
  CC      util/range.o
  CC      util/stats64.o
  CC      util/systemd.o
  CC      util/vfio-helpers.o
  CC      trace-root.o
  CC      util/trace.o
  CC      crypto/trace.o
  CC      io/trace.o
  CC      migration/trace.o
  CC      block/trace.o
  CC      chardev/trace.o
  CC      hw/block/trace.o
  CC      hw/block/dataplane/trace.o
  CC      hw/char/trace.o
  CC      hw/intc/trace.o
  CC      hw/net/trace.o
  CC      hw/rdma/trace.o
  CC      hw/rdma/vmw/trace.o
  CC      hw/virtio/trace.o
  CC      hw/audio/trace.o
  CC      hw/misc/trace.o
  CC      hw/misc/macio/trace.o
  CC      hw/usb/trace.o
  CC      hw/scsi/trace.o
  CC      hw/nvram/trace.o
  CC      hw/display/trace.o
  CC      hw/input/trace.o
  CC      hw/timer/trace.o
  CC      hw/dma/trace.o
  CC      hw/sparc/trace.o
  CC      hw/sparc64/trace.o
  CC      hw/sd/trace.o
  CC      hw/isa/trace.o
  CC      hw/mem/trace.o
  CC      hw/i386/trace.o
  CC      hw/i386/xen/trace.o
  CC      hw/9pfs/trace.o
  CC      hw/ppc/trace.o
  CC      hw/pci-host/trace.o
  CC      hw/pci/trace.o
  CC      hw/s390x/trace.o
  CC      hw/vfio/trace.o
  CC      hw/acpi/trace.o
  CC      hw/arm/trace.o
  CC      hw/alpha/trace.o
  CC      hw/hppa/trace.o
  CC      hw/xen/trace.o
  CC      hw/ide/trace.o
  CC      ui/trace.o
  CC      hw/tpm/trace.o
  CC      audio/trace.o
  CC      net/trace.o
  CC      target/arm/trace.o
  CC      target/mips/trace.o
  CC      target/i386/trace.o
  CC      target/sparc/trace.o
  CC      target/s390x/trace.o
  CC      target/ppc/trace.o
  CC      qom/trace.o
  CC      linux-user/trace.o
  CC      qapi/trace.o
  CC      accel/tcg/trace.o
  CC      accel/kvm/trace.o
  CC      nbd/trace.o
  CC      scsi/trace.o
  CC      stubs/arch-query-cpu-def.o
  CC      stubs/arch-query-cpu-model-comparison.o
  CC      stubs/arch-query-cpu-model-expansion.o
  CC      crypto/pbkdf-stub.o
  CC      stubs/arch-query-cpu-model-baseline.o
  CC      stubs/bdrv-next-monitor-owned.o
  CC      stubs/blk-commit-all.o
  CC      stubs/blockdev-close-all-bdrv-states.o
  CC      stubs/clock-warp.o
  CC      stubs/cpu-get-clock.o
  CC      stubs/dump.o
  CC      stubs/cpu-get-icount.o
  CC      stubs/error-printf.o
  CC      stubs/fdset.o
  CC      stubs/gdbstub.o
  CC      stubs/iothread-lock.o
  CC      stubs/iothread.o
  CC      stubs/get-vm-name.o
  CC      stubs/machine-init-done.o
  CC      stubs/is-daemonized.o
  CC      stubs/migr-blocker.o
  CC      stubs/monitor.o
  CC      stubs/change-state-handler.o
  CC      stubs/notify-event.o
  CC      stubs/qtest.o
  CC      stubs/replay.o
  CC      stubs/runstate-check.o
  CC      stubs/set-fd-handler.o
  CC      stubs/slirp.o
  CC      stubs/sysbus.o
  CC      stubs/tpm.o
  CC      stubs/trace-control.o
  CC      stubs/uuid.o
  CC      stubs/vm-stop.o
  CC      stubs/vmstate.o
  CC      stubs/qmp_pc_dimm.o
  CC      stubs/target-monitor-defs.o
  CC      stubs/target-get-monitor-def.o
  CC      stubs/vmgenid.o
  CC      stubs/pc_madt_cpu_entry.o
  CC      stubs/xen-common.o
  CC      stubs/xen-hvm.o
  CC      stubs/ram-block.o
  CC      stubs/pci-host-piix.o
  CC      contrib/ivshmem-client/ivshmem-client.o
  CC      contrib/ivshmem-client/main.o
  CC      contrib/ivshmem-server/ivshmem-server.o
  CC      contrib/ivshmem-server/main.o
  CC      qemu-nbd.o
  CC      block.o
  CC      blockjob.o
  CC      qemu-io-cmds.o
  CC      replication.o
  CC      block/raw-format.o
  CC      block/qcow.o
/tmp/qemu-test/src/blockjob.c: In function 'block_job_state_transition':
/tmp/qemu-test/src/blockjob.c:75: warning: comparison of unsigned expression >= 0 is always true
/tmp/qemu-test/src/blockjob.c: In function 'block_job_apply_verb':
/tmp/qemu-test/src/blockjob.c:88: warning: comparison of unsigned expression >= 0 is always true
  CC      block/vdi.o
  CC      block/vmdk.o
  CC      block/cloop.o
  CC      block/bochs.o
  CC      block/vpc.o
  CC      block/vvfat.o
  CC      block/dmg.o
  CC      block/qcow2.o
  CC      block/qcow2-refcount.o
  CC      block/qcow2-cluster.o
  CC      block/qcow2-snapshot.o
  CC      block/qcow2-cache.o
  CC      block/qcow2-bitmap.o
  CC      block/qed-l2-cache.o
  CC      block/qed.o
  CC      block/qed-table.o
  CC      block/qed-cluster.o
  CC      block/qed-check.o
  CC      block/vhdx.o
  CC      block/vhdx-endian.o
  CC      block/quorum.o
  CC      block/vhdx-log.o
  CC      block/parallels.o
  CC      block/blkdebug.o
  CC      block/blkverify.o
  CC      block/blkreplay.o
  CC      block/snapshot.o
  CC      block/block-backend.o
  CC      block/qapi.o
  CC      block/file-posix.o
  CC      block/null.o
  CC      block/mirror.o
  CC      block/commit.o
  CC      block/io.o
  CC      block/create.o
  CC      block/throttle-groups.o
  CC      block/nbd.o
  CC      block/nbd-client.o
  CC      block/nvme.o
  CC      block/sheepdog.o
  CC      block/accounting.o
  CC      block/dirty-bitmap.o
  CC      block/write-threshold.o
  CC      block/backup.o
  CC      block/replication.o
  CC      block/throttle.o
  CC      block/crypto.o
  CC      nbd/client.o
  CC      nbd/server.o
  CC      nbd/common.o
  CC      scsi/utils.o
  CC      scsi/pr-manager.o
  CC      scsi/pr-manager-helper.o
  CC      crypto/init.o
  CC      crypto/hash.o
  CC      crypto/hash-glib.o
  CC      crypto/hmac.o
  CC      crypto/hmac-glib.o
  CC      crypto/aes.o
  CC      crypto/desrfb.o
  CC      crypto/cipher.o
  CC      crypto/tlscreds.o
  CC      crypto/tlscredsanon.o
  CC      crypto/tlscredsx509.o
  CC      crypto/tlssession.o
  CC      crypto/secret.o
  CC      crypto/random-platform.o
  CC      crypto/ivgen-essiv.o
  CC      crypto/ivgen.o
  CC      crypto/pbkdf.o
  CC      crypto/ivgen-plain.o
  CC      crypto/ivgen-plain64.o
  CC      crypto/afsplit.o
  CC      crypto/xts.o
  CC      crypto/block.o
  CC      crypto/block-qcow.o
  CC      crypto/block-luks.o
  CC      io/channel.o
  CC      io/channel-buffer.o
  CC      io/channel-command.o
  CC      io/channel-file.o
  CC      io/channel-socket.o
  CC      io/channel-tls.o
  CC      io/channel-watch.o
  CC      io/channel-websock.o
  CC      io/channel-util.o
  CC      io/dns-resolver.o
  CC      io/net-listener.o
  CC      io/task.o
  CC      qom/object.o
  CC      qom/qom-qobject.o
  CC      qom/container.o
  CC      qom/object_interfaces.o
  GEN     qemu-img-cmds.h
  CC      qemu-io.o
  CC      scsi/qemu-pr-helper.o
  CC      qemu-bridge-helper.o
  CC      blockdev-nbd.o
  CC      blockdev.o
  CC      bootdevice.o
  CC      iothread.o
  CC      qdev-monitor.o
  CC      device-hotplug.o
  CC      os-posix.o
  CC      bt-host.o
  CC      bt-vhci.o
  CC      vl.o
  CC      dma-helpers.o
  CC      tpm.o
  CC      device_tree.o
  CC      qapi/qapi-commands.o
  CC      qapi/qapi-commands-block-core.o
  CC      qapi/qapi-commands-block.o
  CC      qapi/qapi-commands-char.o
  CC      qapi/qapi-commands-common.o
  CC      qapi/qapi-commands-crypto.o
  CC      qapi/qapi-commands-introspect.o
  CC      qapi/qapi-commands-migration.o
  CC      qapi/qapi-commands-misc.o
  CC      qapi/qapi-commands-net.o
  CC      qapi/qapi-commands-rocker.o
  CC      qapi/qapi-commands-run-state.o
  CC      qapi/qapi-commands-sockets.o
  CC      qapi/qapi-commands-tpm.o
  CC      qapi/qapi-commands-trace.o
  CC      qapi/qapi-commands-transaction.o
  CC      qapi/qapi-commands-ui.o
  CC      qmp.o
  CC      hmp.o
  CC      cpus-common.o
  CC      audio/audio.o
  CC      audio/noaudio.o
  CC      audio/wavaudio.o
  CC      audio/mixeng.o
  CC      audio/wavcapture.o
  CC      backends/rng.o
  CC      backends/rng-egd.o
  CC      backends/rng-random.o
  CC      backends/tpm.o
  CC      backends/hostmem.o
  CC      backends/hostmem-ram.o
  CC      backends/hostmem-file.o
  CC      backends/cryptodev-builtin.o
  CC      backends/cryptodev.o
  CC      backends/cryptodev-vhost.o
  CC      backends/cryptodev-vhost-user.o
  CC      backends/hostmem-memfd.o
  CC      block/stream.o
  CC      chardev/msmouse.o
  CC      chardev/wctablet.o
  CC      chardev/testdev.o
  CC      disas/arm.o
  CC      disas/i386.o
  CC      fsdev/qemu-fsdev-dummy.o
  CC      fsdev/qemu-fsdev-opts.o
  CC      fsdev/qemu-fsdev-throttle.o
  CC      hw/acpi/core.o
  CC      hw/acpi/piix4.o
  CC      hw/acpi/pcihp.o
  CC      hw/acpi/ich9.o
  CC      hw/acpi/tco.o
  CC      hw/acpi/cpu_hotplug.o
  CC      hw/acpi/memory_hotplug.o
  CC      hw/acpi/nvdimm.o
  CC      hw/acpi/cpu.o
  CC      hw/acpi/vmgenid.o
  CC      hw/acpi/acpi_interface.o
  CC      hw/acpi/bios-linker-loader.o
  CC      hw/acpi/aml-build.o
  CC      hw/acpi/ipmi.o
  CC      hw/acpi/acpi-stub.o
  CC      hw/acpi/ipmi-stub.o
  CC      hw/audio/sb16.o
  CC      hw/audio/es1370.o
  CC      hw/audio/ac97.o
  CC      hw/audio/adlib.o
  CC      hw/audio/fmopl.o
  CC      hw/audio/gus.o
  CC      hw/audio/gusemu_hal.o
  CC      hw/audio/gusemu_mixer.o
  CC      hw/audio/cs4231a.o
  CC      hw/audio/intel-hda.o
  CC      hw/audio/hda-codec.o
  CC      hw/audio/pcspk.o
  CC      hw/audio/wm8750.o
  CC      hw/audio/pl041.o
  CC      hw/audio/lm4549.o
  CC      hw/audio/marvell_88w8618.o
  CC      hw/audio/soundhw.o
  CC      hw/block/block.o
  CC      hw/block/cdrom.o
  CC      hw/block/hd-geometry.o
  CC      hw/block/fdc.o
  CC      hw/block/m25p80.o
  CC      hw/block/nand.o
  CC      hw/block/pflash_cfi01.o
  CC      hw/block/pflash_cfi02.o
  CC      hw/block/ecc.o
  CC      hw/block/onenand.o
  CC      hw/block/nvme.o
  CC      hw/bt/core.o
  CC      hw/bt/l2cap.o
  CC      hw/bt/sdp.o
  CC      hw/bt/hci.o
  CC      hw/bt/hid.o
  CC      hw/bt/hci-csr.o
  CC      hw/char/ipoctal232.o
  CC      hw/char/parallel.o
  CC      hw/char/parallel-isa.o
  CC      hw/char/pl011.o
  CC      hw/char/serial.o
  CC      hw/char/serial-isa.o
  CC      hw/char/serial-pci.o
  CC      hw/char/virtio-console.o
  CC      hw/char/cadence_uart.o
  CC      hw/char/cmsdk-apb-uart.o
  CC      hw/char/debugcon.o
  CC      hw/char/imx_serial.o
  CC      hw/core/qdev.o
  CC      hw/core/qdev-properties.o
  CC      hw/core/bus.o
  CC      hw/core/reset.o
  CC      hw/core/qdev-fw.o
  CC      hw/core/fw-path-provider.o
  CC      hw/core/hotplug.o
  CC      hw/core/irq.o
  CC      hw/core/nmi.o
  CC      hw/core/stream.o
  CC      hw/core/ptimer.o
  CC      hw/core/sysbus.o
  CC      hw/core/machine.o
  CC      hw/core/loader.o
  CC      hw/core/qdev-properties-system.o
  CC      hw/core/register.o
  CC      hw/core/or-irq.o
  CC      hw/core/split-irq.o
  CC      hw/core/platform-bus.o
  CC      hw/cpu/core.o
  CC      hw/display/ads7846.o
  CC      hw/display/cirrus_vga.o
  CC      hw/display/pl110.o
  CC      hw/display/sii9022.o
  CC      hw/display/ssd0303.o
  CC      hw/display/ssd0323.o
  CC      hw/display/vga-pci.o
  CC      hw/display/vga-isa.o
  CC      hw/display/vmware_vga.o
  CC      hw/display/blizzard.o
  CC      hw/display/exynos4210_fimd.o
  CC      hw/display/framebuffer.o
  CC      hw/display/tc6393xb.o
  CC      hw/dma/pl080.o
  CC      hw/dma/pl330.o
  CC      hw/dma/i8257.o
  CC      hw/dma/xilinx_axidma.o
  CC      hw/dma/xlnx-zynq-devcfg.o
  CC      hw/gpio/max7310.o
  CC      hw/gpio/pl061.o
  CC      hw/gpio/zaurus.o
  CC      hw/gpio/gpio_key.o
  CC      hw/i2c/core.o
  CC      hw/i2c/smbus.o
  CC      hw/i2c/smbus_eeprom.o
  CC      hw/i2c/i2c-ddc.o
  CC      hw/i2c/versatile_i2c.o
  CC      hw/i2c/smbus_ich9.o
  CC      hw/i2c/pm_smbus.o
  CC      hw/i2c/bitbang_i2c.o
  CC      hw/i2c/exynos4210_i2c.o
  CC      hw/i2c/imx_i2c.o
  CC      hw/i2c/aspeed_i2c.o
  CC      hw/ide/core.o
  CC      hw/ide/atapi.o
  CC      hw/ide/qdev.o
  CC      hw/ide/pci.o
  CC      hw/ide/isa.o
  CC      hw/ide/piix.o
  CC      hw/ide/microdrive.o
  CC      hw/ide/ahci.o
  CC      hw/ide/ich.o
  CC      hw/ide/ahci-allwinner.o
  CC      hw/input/hid.o
  CC      hw/input/lm832x.o
  CC      hw/input/pckbd.o
  CC      hw/input/pl050.o
  CC      hw/input/ps2.o
  CC      hw/input/stellaris_input.o
  CC      hw/input/tsc2005.o
  CC      hw/input/virtio-input.o
  CC      hw/input/virtio-input-hid.o
  CC      hw/input/virtio-input-host.o
  CC      hw/intc/i8259_common.o
  CC      hw/intc/i8259.o
  CC      hw/intc/pl190.o
  CC      hw/intc/xlnx-pmu-iomod-intc.o
  CC      hw/intc/xlnx-zynqmp-ipi.o
  CC      hw/intc/imx_avic.o
  CC      hw/intc/imx_gpcv2.o
  CC      hw/intc/realview_gic.o
  CC      hw/intc/ioapic_common.o
  CC      hw/intc/arm_gic_common.o
  CC      hw/intc/arm_gic.o
  CC      hw/intc/arm_gicv2m.o
  CC      hw/intc/arm_gicv3_common.o
  CC      hw/intc/arm_gicv3.o
  CC      hw/intc/arm_gicv3_dist.o
  CC      hw/intc/arm_gicv3_redist.o
  CC      hw/intc/arm_gicv3_its_common.o
  CC      hw/intc/intc.o
  CC      hw/ipack/ipack.o
  CC      hw/ipack/tpci200.o
  CC      hw/ipmi/ipmi.o
  CC      hw/ipmi/ipmi_bmc_sim.o
  CC      hw/ipmi/ipmi_bmc_extern.o
  CC      hw/ipmi/isa_ipmi_kcs.o
  CC      hw/ipmi/isa_ipmi_bt.o
  CC      hw/isa/isa-bus.o
  CC      hw/isa/isa-superio.o
  CC      hw/isa/smc37c669-superio.o
  CC      hw/isa/apm.o
  CC      hw/mem/pc-dimm.o
  CC      hw/mem/nvdimm.o
  CC      hw/misc/applesmc.o
  CC      hw/misc/max111x.o
  CC      hw/misc/tmp105.o
  CC      hw/misc/tmp421.o
  CC      hw/misc/debugexit.o
  CC      hw/misc/sga.o
  CC      hw/misc/pc-testdev.o
  CC      hw/misc/pci-testdev.o
  CC      hw/misc/edu.o
  CC      hw/misc/unimp.o
  CC      hw/misc/vmcoreinfo.o
  CC      hw/misc/arm_l2x0.o
  CC      hw/misc/arm_integrator_debug.o
  CC      hw/misc/a9scu.o
  CC      hw/misc/arm11scu.o
  CC      hw/net/ne2000.o
  CC      hw/net/eepro100.o
  CC      hw/net/pcnet-pci.o
  CC      hw/net/pcnet.o
  CC      hw/net/e1000.o
  CC      hw/net/e1000x_common.o
  CC      hw/net/net_tx_pkt.o
  CC      hw/net/net_rx_pkt.o
  CC      hw/net/e1000e.o
  CC      hw/net/e1000e_core.o
  CC      hw/net/rtl8139.o
  CC      hw/net/vmxnet3.o
  CC      hw/net/smc91c111.o
  CC      hw/net/lan9118.o
  CC      hw/net/ne2000-isa.o
  CC      hw/net/xgmac.o
  CC      hw/net/xilinx_axienet.o
  CC      hw/net/allwinner_emac.o
  CC      hw/net/imx_fec.o
  CC      hw/net/cadence_gem.o
  CC      hw/net/stellaris_enet.o
  CC      hw/net/ftgmac100.o
  CC      hw/net/rocker/rocker.o
  CC      hw/net/rocker/rocker_desc.o
  CC      hw/net/rocker/rocker_fp.o
  CC      hw/net/rocker/rocker_world.o
  CC      hw/net/rocker/rocker_of_dpa.o
  CC      hw/net/can/can_sja1000.o
  CC      hw/net/can/can_kvaser_pci.o
  CC      hw/net/can/can_pcm3680_pci.o
  CC      hw/net/can/can_mioe3680_pci.o
  CC      hw/nvram/eeprom93xx.o
  CC      hw/nvram/eeprom_at24c.o
  CC      hw/nvram/fw_cfg.o
  CC      hw/nvram/chrp_nvram.o
  CC      hw/pci-bridge/pci_bridge_dev.o
  CC      hw/pci-bridge/pcie_root_port.o
  CC      hw/pci-bridge/gen_pcie_root_port.o
  CC      hw/pci-bridge/pcie_pci_bridge.o
  CC      hw/pci-bridge/pci_expander_bridge.o
  CC      hw/pci-bridge/xio3130_upstream.o
  CC      hw/pci-bridge/xio3130_downstream.o
  CC      hw/pci-bridge/ioh3420.o
  CC      hw/pci-bridge/i82801b11.o
  CC      hw/pci-host/pam.o
  CC      hw/pci-host/versatile.o
  CC      hw/pci-host/piix.o
  CC      hw/pci-host/q35.o
  CC      hw/pci-host/gpex.o
  CC      hw/pci-host/designware.o
  CC      hw/pci/pci_bridge.o
  CC      hw/pci/pci.o
  CC      hw/pci/msix.o
  CC      hw/pci/msi.o
  CC      hw/pci/shpc.o
  CC      hw/pci/slotid_cap.o
  CC      hw/pci/pci_host.o
  CC      hw/pci/pcie_host.o
  CC      hw/pci/pcie.o
  CC      hw/pci/pcie_aer.o
  CC      hw/pci/pcie_port.o
  CC      hw/pci/pci-stub.o
  CC      hw/pcmcia/pcmcia.o
  CC      hw/scsi/scsi-disk.o
  CC      hw/scsi/scsi-generic.o
  CC      hw/scsi/scsi-bus.o
  CC      hw/scsi/lsi53c895a.o
  CC      hw/scsi/mptsas.o
  CC      hw/scsi/mptconfig.o
  CC      hw/scsi/mptendian.o
  CC      hw/scsi/megasas.o
  CC      hw/scsi/vmw_pvscsi.o
  CC      hw/scsi/esp.o
  CC      hw/sd/pl181.o
  CC      hw/scsi/esp-pci.o
  CC      hw/sd/ssi-sd.o
  CC      hw/sd/sd.o
  CC      hw/sd/core.o
  CC      hw/sd/sdmmc-internal.o
  CC      hw/sd/sdhci.o
  CC      hw/smbios/smbios.o
  CC      hw/smbios/smbios_type_38.o
  CC      hw/smbios/smbios-stub.o
  CC      hw/smbios/smbios_type_38-stub.o
  CC      hw/ssi/pl022.o
  CC      hw/ssi/ssi.o
  CC      hw/ssi/xilinx_spips.o
  CC      hw/ssi/aspeed_smc.o
  CC      hw/ssi/stm32f2xx_spi.o
  CC      hw/ssi/mss-spi.o
  CC      hw/timer/arm_timer.o
  CC      hw/timer/arm_mptimer.o
  CC      hw/timer/armv7m_systick.o
  CC      hw/timer/a9gtimer.o
  CC      hw/timer/cadence_ttc.o
  CC      hw/timer/ds1338.o
  CC      hw/timer/hpet.o
  CC      hw/timer/i8254_common.o
  CC      hw/timer/i8254.o
  CC      hw/timer/pl031.o
  CC      hw/timer/twl92230.o
  CC      hw/timer/imx_epit.o
  CC      hw/timer/imx_gpt.o
  CC      hw/timer/xlnx-zynqmp-rtc.o
  CC      hw/timer/stm32f2xx_timer.o
  CC      hw/timer/aspeed_timer.o
  CC      hw/timer/cmsdk-apb-timer.o
  CC      hw/timer/mss-timer.o
  CC      hw/tpm/tpm_util.o
  CC      hw/tpm/tpm_tis.o
  CC      hw/tpm/tpm_crb.o
  CC      hw/tpm/tpm_passthrough.o
  CC      hw/tpm/tpm_emulator.o
  CC      hw/usb/core.o
  CC      hw/usb/combined-packet.o
  CC      hw/usb/bus.o
  CC      hw/usb/libhw.o
  CC      hw/usb/desc-msos.o
  CC      hw/usb/desc.o
  CC      hw/usb/hcd-uhci.o
  CC      hw/usb/hcd-ohci.o
  CC      hw/usb/hcd-ehci.o
  CC      hw/usb/hcd-ehci-sysbus.o
  CC      hw/usb/hcd-ehci-pci.o
  CC      hw/usb/hcd-xhci.o
  CC      hw/usb/hcd-xhci-nec.o
  CC      hw/usb/hcd-musb.o
  CC      hw/usb/dev-hub.o
  CC      hw/usb/dev-hid.o
  CC      hw/usb/dev-wacom.o
  CC      hw/usb/dev-storage.o
  CC      hw/usb/dev-uas.o
  CC      hw/usb/dev-audio.o
  CC      hw/usb/dev-serial.o
  CC      hw/usb/dev-network.o
  CC      hw/usb/dev-bluetooth.o
  CC      hw/usb/dev-smartcard-reader.o
  CC      hw/usb/dev-mtp.o
  CC      hw/usb/host-stub.o
  CC      hw/virtio/virtio-rng.o
  CC      hw/virtio/virtio-pci.o
  CC      hw/virtio/virtio-bus.o
  CC      hw/virtio/virtio-mmio.o
  CC      hw/virtio/vhost-stub.o
  CC      hw/watchdog/watchdog.o
  CC      hw/watchdog/wdt_i6300esb.o
  CC      hw/watchdog/wdt_ib700.o
  CC      hw/watchdog/wdt_aspeed.o
  CC      migration/migration.o
  CC      migration/socket.o
  CC      migration/fd.o
  CC      migration/exec.o
  CC      migration/tls.o
  CC      migration/channel.o
  CC      migration/savevm.o
  CC      migration/colo-comm.o
  CC      migration/colo.o
  CC      migration/colo-failover.o
  CC      migration/vmstate.o
  CC      migration/vmstate-types.o
  CC      migration/page_cache.o
  CC      migration/qemu-file.o
  CC      migration/global_state.o
  CC      migration/qemu-file-channel.o
  CC      migration/xbzrle.o
  CC      migration/postcopy-ram.o
  CC      migration/qjson.o
  CC      migration/block-dirty-bitmap.o
  CC      migration/block.o
  CC      net/net.o
  CC      net/queue.o
  CC      net/checksum.o
  CC      net/util.o
  CC      net/hub.o
  CC      net/socket.o
  CC      net/dump.o
  CC      net/eth.o
  CC      net/l2tpv3.o
  CC      net/vhost-user.o
  CC      net/slirp.o
  CC      net/filter.o
  CC      net/filter-buffer.o
  CC      net/filter-mirror.o
  CC      net/colo-compare.o
  CC      net/colo.o
  CC      net/filter-rewriter.o
  CC      net/filter-replay.o
  CC      net/tap.o
  CC      net/tap-linux.o
  CC      net/can/can_core.o
  CC      net/can/can_host.o
  CC      net/can/can_socketcan.o
  CC      qom/cpu.o
  CC      replay/replay.o
  CC      replay/replay-internal.o
  CC      replay/replay-events.o
  CC      replay/replay-time.o
  CC      replay/replay-input.o
  CC      replay/replay-char.o
  CC      replay/replay-snapshot.o
  CC      replay/replay-net.o
  CC      replay/replay-audio.o
  CC      slirp/cksum.o
  CC      slirp/if.o
  CC      slirp/ip_icmp.o
  CC      slirp/ip6_icmp.o
  CC      slirp/ip6_input.o
  CC      slirp/ip6_output.o
  CC      slirp/ip_input.o
  CC      slirp/ip_output.o
  CC      slirp/dhcpv6.o
  CC      slirp/dnssearch.o
  CC      slirp/slirp.o
  CC      slirp/mbuf.o
  CC      slirp/misc.o
  CC      slirp/sbuf.o
  CC      slirp/socket.o
  CC      slirp/tcp_input.o
  CC      slirp/tcp_output.o
/tmp/qemu-test/src/slirp/tcp_input.c: In function 'tcp_input':
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_p' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_len' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_tos' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_id' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_off' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_ttl' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_sum' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_src.s_addr' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: 'save_ip.ip_dst.s_addr' may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:220: warning: 'save_ip6.ip_nh' may be used uninitialized in this function
  CC      slirp/tcp_subr.o
  CC      slirp/tcp_timer.o
  CC      slirp/udp.o
  CC      slirp/udp6.o
  CC      slirp/bootp.o
  CC      slirp/tftp.o
  CC      slirp/arp_table.o
  CC      slirp/ndp_table.o
  CC      slirp/ncsi.o
  CC      ui/keymaps.o
  CC      ui/console.o
  CC      ui/cursor.o
  CC      ui/qemu-pixman.o
  CC      ui/input.o
  CC      ui/input-keymap.o
  CC      ui/input-legacy.o
  CC      ui/input-linux.o
  CC      ui/vnc.o
  CC      ui/vnc-enc-zlib.o
  CC      ui/vnc-enc-hextile.o
  CC      ui/vnc-enc-tight.o
  CC      ui/vnc-palette.o
  CC      ui/vnc-enc-zrle.o
  CC      ui/vnc-auth-vencrypt.o
  CC      ui/vnc-ws.o
  CC      ui/vnc-jobs.o
  CC      ui/x_keymap.o
  CC      audio/ossaudio.o
  CC      ui/sdl.o
  CC      ui/sdl_zoom.o
  CC      chardev/char.o
  CC      chardev/char-fd.o
  CC      chardev/char-fe.o
  CC      chardev/char-file.o
  CC      chardev/char-io.o
  CC      chardev/char-mux.o
  CC      chardev/char-null.o
  CC      chardev/char-parallel.o
  CC      chardev/char-pipe.o
  CC      chardev/char-pty.o
  CC      chardev/char-ringbuf.o
  CC      chardev/char-serial.o
  CC      chardev/char-socket.o
  CC      chardev/char-stdio.o
  CC      chardev/char-udp.o
  LINK    tests/qemu-iotests/socket_scm_helper
  CC      qga/commands.o
  CC      qga/guest-agent-command-state.o
  AS      optionrom/multiboot.o
  AS      optionrom/linuxboot.o
  CC      optionrom/linuxboot_dma.o
cc: unrecognized option '-no-integrated-as'
cc: unrecognized option '-no-integrated-as'
  AS      optionrom/kvmvapic.o
  BUILD   optionrom/multiboot.img
  BUILD   optionrom/linuxboot.img
  BUILD   optionrom/linuxboot_dma.img
  CC      qga/main.o
  BUILD   optionrom/kvmvapic.img
  CC      qga/commands-posix.o
  BUILD   optionrom/multiboot.raw
  BUILD   optionrom/linuxboot.raw
  BUILD   optionrom/linuxboot_dma.raw
  BUILD   optionrom/kvmvapic.raw
  SIGN    optionrom/multiboot.bin
  SIGN    optionrom/linuxboot.bin
  SIGN    optionrom/linuxboot_dma.bin
  SIGN    optionrom/kvmvapic.bin
  CC      qga/channel-posix.o
  CC      qga/qapi-generated/qga-qapi-types.o
  CC      qga/qapi-generated/qga-qapi-visit.o
  CC      qga/qapi-generated/qga-qapi-commands.o
  AR      libqemuutil.a
  CC      qemu-img.o
  LINK    ivshmem-client
  LINK    ivshmem-server
  LINK    qemu-nbd
  LINK    qemu-img
  LINK    qemu-io
  LINK    scsi/qemu-pr-helper
  LINK    qemu-bridge-helper
  LINK    qemu-ga
  GEN     x86_64-softmmu/hmp-commands.h
  GEN     x86_64-softmmu/hmp-commands-info.h
  GEN     x86_64-softmmu/config-target.h
  CC      x86_64-softmmu/exec.o
  CC      x86_64-softmmu/tcg/tcg-common.o
  CC      x86_64-softmmu/tcg/tcg.o
  CC      x86_64-softmmu/tcg/tcg-op-vec.o
  CC      x86_64-softmmu/tcg/tcg-op.o
  CC      x86_64-softmmu/tcg/tcg-op-gvec.o
  CC      x86_64-softmmu/tcg/optimize.o
  CC      x86_64-softmmu/fpu/softfloat.o
/tmp/qemu-test/src/fpu/softfloat.c: In function 'int_to_float':
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.exp' may be used uninitialized in this function
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.frac' may be used uninitialized in this function
  CC      x86_64-softmmu/disas.o
  GEN     x86_64-softmmu/gdbstub-xml.c
  CC      x86_64-softmmu/arch_init.o
  CC      x86_64-softmmu/cpus.o
  CC      x86_64-softmmu/monitor.o
  CC      x86_64-softmmu/gdbstub.o
  CC      x86_64-softmmu/balloon.o
  GEN     aarch64-softmmu/hmp-commands.h
  GEN     aarch64-softmmu/hmp-commands-info.h
  GEN     aarch64-softmmu/config-target.h
  CC      aarch64-softmmu/exec.o
  CC      x86_64-softmmu/ioport.o
  CC      x86_64-softmmu/numa.o
  CC      x86_64-softmmu/qtest.o
  CC      x86_64-softmmu/memory.o
  CC      x86_64-softmmu/memory_mapping.o
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:36: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:45: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:54: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:63: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:74: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:85: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:95: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:104: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:113: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:122: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:131: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:142: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:153: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:164: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:174: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:185: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:195: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:204: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:213: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:222: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:231: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:240: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:249: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:258: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:267: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:276: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:296: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:305: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:314: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:324: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:334: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:343: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:352: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:361: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:370: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:379: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:388: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:397: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:406: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:416: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:462: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:480: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:489: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:520: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:529: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:538: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:547: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:557: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:567: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:35: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:44: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:53: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:64: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:73: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:82: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:91: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:100: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:109: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:118: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:128: error: unknown field 'async_cmd' specified in initializer
./hmp-commands.h:128: warning: initialization from incompatible pointer type
./hmp-commands.h:138: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:148: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:169: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:178: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:187: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:197: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:207: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:216: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:225: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:234: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:243: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:252: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:261: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:270: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:280: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:290: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:299: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:308: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:317: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:327: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:336: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:345: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:354: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:364: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:374: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:383: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:392: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:401: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:410: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:418: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:461: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:485: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:495: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:504: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:512: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:526: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:536: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:545: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:554: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:564: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:577: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:587: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:596: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:612: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:651: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:662: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:675: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:691: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:708: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:721: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:740: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:749: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:759: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:769: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:779: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:790: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:800: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:810: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:819: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:829: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:839: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:848: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:857: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:866: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:875: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:884: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:892: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:900: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:908: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:919: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:929: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:938: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:947: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:956: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:965: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:974: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:983: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:993: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1002: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1012: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1022: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1031: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1040: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1049: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1058: error: unknown field 'cmd' specified in initializer
  CC      aarch64-softmmu/tcg/tcg.o
  CC      x86_64-softmmu/dump.o
make[1]: *** [monitor.o] Error 1
make[1]: *** Waiting for unfinished jobs....
  CC      aarch64-softmmu/tcg/tcg-op.o
  CC      aarch64-softmmu/tcg/tcg-op-vec.o
  CC      aarch64-softmmu/tcg/tcg-op-gvec.o
  CC      aarch64-softmmu/tcg/tcg-common.o
  CC      aarch64-softmmu/tcg/optimize.o
  CC      aarch64-softmmu/fpu/softfloat.o
  CC      aarch64-softmmu/disas.o
/tmp/qemu-test/src/fpu/softfloat.c: In function 'int_to_float':
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.exp' may be used uninitialized in this function
/tmp/qemu-test/src/fpu/softfloat.c:1517: warning: 'r.frac' may be used uninitialized in this function
  GEN     aarch64-softmmu/gdbstub-xml.c
  CC      aarch64-softmmu/arch_init.o
  CC      aarch64-softmmu/cpus.o
  CC      aarch64-softmmu/monitor.o
  CC      aarch64-softmmu/gdbstub.o
  CC      aarch64-softmmu/balloon.o
  CC      aarch64-softmmu/ioport.o
  CC      aarch64-softmmu/numa.o
  CC      aarch64-softmmu/qtest.o
  CC      aarch64-softmmu/memory.o
  CC      aarch64-softmmu/memory_mapping.o
  CC      aarch64-softmmu/dump.o
  CC      aarch64-softmmu/migration/ram.o
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:36: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:45: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:54: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:63: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:95: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:104: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:113: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:122: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:131: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:164: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:174: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:185: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:195: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:204: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:213: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:222: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:231: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:240: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:249: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:258: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:267: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:276: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:296: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:305: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:314: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:324: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:334: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:343: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:352: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:361: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:370: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:379: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:388: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:397: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:406: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:416: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:462: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:480: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:489: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2519:
./hmp-commands-info.h:520: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:529: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:538: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:547: error: unknown field 'cmd' specified in initializer
./hmp-commands-info.h:557: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:8: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:17: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:26: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:35: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:44: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:53: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:64: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:73: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:82: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:91: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:100: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:109: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:118: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:128: error: unknown field 'async_cmd' specified in initializer
./hmp-commands.h:128: warning: initialization from incompatible pointer type
./hmp-commands.h:138: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:148: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:169: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:178: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:187: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:197: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:207: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:216: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:225: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:234: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:243: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:252: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:261: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:270: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:280: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:290: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:299: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:308: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:317: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:327: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:336: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:345: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:354: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:364: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:374: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:383: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:392: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:401: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:410: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:418: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:426: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:435: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:444: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:453: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:461: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:471: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:485: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:495: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:504: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:512: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:526: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:536: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:545: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:554: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:564: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:577: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:587: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:596: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:612: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:651: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:662: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:675: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:691: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:708: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:721: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:740: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:749: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:759: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:769: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:779: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:790: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:800: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:810: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:819: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:829: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:839: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:848: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:857: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:866: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:875: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:884: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:892: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:900: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:908: error: unknown field 'cmd' specified in initializer
In file included from /tmp/qemu-test/src/monitor.c:2525:
./hmp-commands.h:929: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:938: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:947: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:956: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:965: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:974: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:983: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:993: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1002: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1012: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1022: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1031: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1040: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1049: error: unknown field 'cmd' specified in initializer
./hmp-commands.h:1058: error: unknown field 'cmd' specified in initializer
make[1]: *** [monitor.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [subdir-x86_64-softmmu] Error 2
make: *** Waiting for unfinished jobs....
make: *** [subdir-aarch64-softmmu] Error 2
Traceback (most recent call last):
  File "./tests/docker/docker.py", line 407, in <module>
    sys.exit(main())
  File "./tests/docker/docker.py", line 404, in main
    return args.cmdobj.run(args, argv)
  File "./tests/docker/docker.py", line 261, in run
    return Docker().run(argv, args.keep, quiet=args.quiet)
  File "./tests/docker/docker.py", line 229, in run
    quiet=quiet)
  File "./tests/docker/docker.py", line 147, in _do_check
    return subprocess.check_call(self._command + cmd, **kwargs)
  File "/usr/lib64/python2.7/subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['docker', 'run', '--label', 'com.qemu.instance.uuid=a9cd356a311e11e89d5952540069c830', '-u', '0', '--security-opt', 'seccomp=unconfined', '--rm', '--net=none', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=8', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/root/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-p7moby5j/src/docker-src.2018-03-26-13.53.44.4674:/var/tmp/qemu:z,ro', 'qemu:min-glib', '/var/tmp/qemu/run', 'test-build']' returned non-zero exit status 2
make[1]: *** [tests/docker/Makefile.include:129: docker-run] Error 1
make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-p7moby5j/src'
make: *** [tests/docker/Makefile.include:163: docker-run-test-build@min-glib] Error 2

real	1m33.127s
user	0m4.114s
sys	0m3.799s
=== OUTPUT END ===

Test command exited with code: 2


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

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

* Re: [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments Marc-André Lureau
@ 2018-03-26 18:26   ` Eduardo Habkost
  0 siblings, 0 replies; 61+ messages in thread
From: Eduardo Habkost @ 2018-03-26 18:26 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Juan Quintela, Dr. David Alan Gilbert, Eric Blake,
	Cleber Rosa, Markus Armbruster, Gerd Hoffmann, Michael Roth

On Mon, Mar 26, 2018 at 05:08:40PM +0200, Marc-André Lureau wrote:
> Use shlex to split the CLI command, respecting quoted arguments, and
> also comments. This allows to call for ex:
> 
> (QEMU) human-monitor-command command-line="screendump /dev/null"
> {"execute": "human-monitor-command", "arguments": {"command-line": "screendump /dev/null"}}
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Wonderful.

Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>

-- 
Eduardo

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

* Re: [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it Marc-André Lureau
@ 2018-03-26 19:31   ` Eric Blake
  0 siblings, 0 replies; 61+ messages in thread
From: Eric Blake @ 2018-03-26 19:31 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Cleber Rosa, Markus Armbruster, Gerd Hoffmann, Michael Roth

On 03/26/2018 10:08 AM, Marc-André Lureau wrote:
> The following qdict_put() line does replace the value, as the
> documentation says.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   monitor.c | 1 -
>   1 file changed, 1 deletion(-)

This patch is unneeded once Peter's change lands:
https://lists.gnu.org/archive/html/qemu-devel/2018-03/msg06513.html
as that patch also deletes the line in question.

It may be worth waiting for the OOB stuff to settle and then rebase the 
remaining cleanups as a separate series from the async command addition, 
especially if some of the cleanups are still relevant as minor bug fixes 
for 2.12.

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

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (40 preceding siblings ...)
  2018-03-26 17:55 ` no-reply
@ 2018-04-04  9:34 ` Stefan Hajnoczi
  2018-04-04 10:01   ` Marc-André Lureau
  2018-04-04 13:45 ` Eric Blake
  2018-07-05 13:05 ` Markus Armbruster
  43 siblings, 1 reply; 61+ messages in thread
From: Stefan Hajnoczi @ 2018-04-04  9:34 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela, Markus Armbruster,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 1789 bytes --]

On Mon, Mar 26, 2018 at 05:08:38PM +0200, Marc-André Lureau wrote:
> One of initial design goals of QMP was to have "asynchronous command
> completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
> goal was not fully achieved, and some broken bits left were removed
> progressively until commit 65207c59d that removed async command
> support.
> 
> Yet there are clear benefits allowing the command handler to re-enter
> the main loop if the command cannot be handled synchronously, or if it
> is long-lasting. This is currently not possible and make some bugs
> such as rhbz#1230527 difficult to solve.  Furthermore, many QMP
> commands do IO and could be considered 'slow' and blocking the main
> loop today. The unwritten solution so far is to use a pair of
> command+event. But this approach has a number of issues, in particular
> to fix existing commands, and inadequacy since the event is
> broadcasted and may thus have command 'id' conflict, beside being
> rather inefficient and incorrect.

This paragraph implies changing the command+event QMP idiom but none of
the patches touch docs/interop/qmp-spec.txt.  So I guess this new
revision doesn't modify the QMP protocol anymore and this paragraph is
outdated?  This revision simply implements async command handlers but
QMP clients see no protocol change?

For more complex commands a coroutine would be cleaner than hand-written
async code.  The handler would look something like:

  QDict * coroutine_fn (*co_cmd)(Monitor *mon,
                                 const QDict *qdict,
                                 Error **errp)

The monitor invokes it from coroutine context.  The coroutine just needs
to return a QDict or set errp - no explicit QmpReturn API is needed.

Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-04-04  9:34 ` Stefan Hajnoczi
@ 2018-04-04 10:01   ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-04-04 10:01 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: Eduardo Habkost, Juan Quintela, Markus Armbruster, QEMU,
	Gerd Hoffmann, Cleber Rosa, Michael Roth, Dr. David Alan Gilbert

Hi

On Wed, Apr 4, 2018 at 11:34 AM, Stefan Hajnoczi <stefanha@gmail.com> wrote:
> On Mon, Mar 26, 2018 at 05:08:38PM +0200, Marc-André Lureau wrote:
>> One of initial design goals of QMP was to have "asynchronous command
>> completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
>> goal was not fully achieved, and some broken bits left were removed
>> progressively until commit 65207c59d that removed async command
>> support.
>>
>> Yet there are clear benefits allowing the command handler to re-enter
>> the main loop if the command cannot be handled synchronously, or if it
>> is long-lasting. This is currently not possible and make some bugs
>> such as rhbz#1230527 difficult to solve.  Furthermore, many QMP
>> commands do IO and could be considered 'slow' and blocking the main
>> loop today. The unwritten solution so far is to use a pair of
>> command+event. But this approach has a number of issues, in particular
>> to fix existing commands, and inadequacy since the event is
>> broadcasted and may thus have command 'id' conflict, beside being
>> rather inefficient and incorrect.
>
> This paragraph implies changing the command+event QMP idiom but none of
> the patches touch docs/interop/qmp-spec.txt.  So I guess this new
> revision doesn't modify the QMP protocol anymore and this paragraph is
> outdated?  This revision simply implements async command handlers but
> QMP clients see no protocol change?

Yes, that version of the patch series doesn't provide asynchronous
protocol. The protocol is unchanged. With asynchronous handler, you
don't have to use the cmd+event idiom, unless you want some kind of
asynchronous protocol, with concurrent commands/events - you may still
use oob anyway. I think having a better asynchronous protocol has
merits that would simplify the commands/events&oob situation, but this
is left for another series, when there will be clearer benefits.

> For more complex commands a coroutine would be cleaner than hand-written
> async code.  The handler would look something like:
>
>   QDict * coroutine_fn (*co_cmd)(Monitor *mon,
>                                  const QDict *qdict,
>                                  Error **errp)
>
> The monitor invokes it from coroutine context.  The coroutine just needs
> to return a QDict or set errp - no explicit QmpReturn API is needed.

Right, that would be nice. It should probably be built on top of the
non-coroutine version.

-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (41 preceding siblings ...)
  2018-04-04  9:34 ` Stefan Hajnoczi
@ 2018-04-04 13:45 ` Eric Blake
  2018-04-04 13:57   ` Marc-André Lureau
  2018-07-05 13:05 ` Markus Armbruster
  43 siblings, 1 reply; 61+ messages in thread
From: Eric Blake @ 2018-04-04 13:45 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Dr. David Alan Gilbert,
	Cleber Rosa, Markus Armbruster, Gerd Hoffmann, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 778 bytes --]

On 03/26/2018 10:08 AM, Marc-André Lureau wrote:
> Hi,
> 
> One of initial design goals of QMP was to have "asynchronous command
> completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
> goal was not fully achieved, and some broken bits left were removed
> progressively until commit 65207c59d that removed async command
> support.
> 

> v3:
> - complete rework, dropping the asynchronous commands visibility from
>   the protocol side entirely (until there is a real need for it)
> - rebased, with a few preliminary cleanup patches

Are any of the preliminary cleanup patches appropriate for 2.12 as bug
fixes?

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


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

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-04-04 13:45 ` Eric Blake
@ 2018-04-04 13:57   ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-04-04 13:57 UTC (permalink / raw)
  To: Eric Blake
  Cc: QEMU, Eduardo Habkost, Juan Quintela, Markus Armbruster,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Hi

On Wed, Apr 4, 2018 at 3:45 PM, Eric Blake <eblake@redhat.com> wrote:
> On 03/26/2018 10:08 AM, Marc-André Lureau wrote:
>> Hi,
>>
>> One of initial design goals of QMP was to have "asynchronous command
>> completion" (http://wiki.qemu.org/Features/QAPI). Unfortunately, that
>> goal was not fully achieved, and some broken bits left were removed
>> progressively until commit 65207c59d that removed async command
>> support.
>>
>
>> v3:
>> - complete rework, dropping the asynchronous commands visibility from
>>   the protocol side entirely (until there is a real need for it)
>> - rebased, with a few preliminary cleanup patches
>
> Are any of the preliminary cleanup patches appropriate for 2.12 as bug
> fixes?

Nothing urgent, just a few cleanups (I'll need to rebase).

Btw, the conditional series ( [Qemu-devel] [PATCH v3 00/49] qapi: add
#if pre-processor conditions to generated code ) is of higher priority
I think.

Thanks

-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous
  2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous Marc-André Lureau
@ 2018-04-12 14:48   ` Dr. David Alan Gilbert
  2018-04-19 16:05     ` Marc-André Lureau
  2019-04-09 14:06       ` Marc-André Lureau
  0 siblings, 2 replies; 61+ messages in thread
From: Dr. David Alan Gilbert @ 2018-04-12 14:48 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela, Eric Blake,
	Cleber Rosa, Markus Armbruster, Gerd Hoffmann, Michael Roth

* Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
> Make screendump asynchronous to provide correct screendumps.
> 
> HMP doesn't have async support, so it has to remain synchronous and
> potentially incorrect to avoid potential races.
> 
> Fixes:
> https://bugzilla.redhat.com/show_bug.cgi?id=1230527
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Hi,
  Looking at this and the previous pair of patches, I think we'd be
better if we defined that async commands took a callback function
pointer and data that they call.

  Here we've got 'graphic_hw_update_done' that explicitly walks qmp
lists; but I think it's better just to pass graphic_hw_update() the
completion data together with a callback function and it calls that when
it's done.

(Also isn't it a little bit of a race, calling graphic_hw_update() and
*then* adding the entry to the list? Can't it end up calling the _done()
before we've added it to the list).

Also, do we need a list of outstanding screendumps, or should we just
have a list of async commands.

It wouldn't seem hard to use the async-QMP command from the HMP
and then just provide a way to tell whether it had finished.

Dave

> ---
>  qapi/ui.json         |  3 +-
>  include/ui/console.h |  3 ++
>  hmp.c                |  2 +-
>  ui/console.c         | 99 ++++++++++++++++++++++++++++++++++++++++----
>  4 files changed, 96 insertions(+), 11 deletions(-)
> 
> diff --git a/qapi/ui.json b/qapi/ui.json
> index 5d01ad4304..4d2c326fb9 100644
> --- a/qapi/ui.json
> +++ b/qapi/ui.json
> @@ -96,7 +96,8 @@
>  #
>  ##
>  { 'command': 'screendump',
> -  'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
> +  'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
> +  'async': true }
>  
>  ##
>  # == Spice
> diff --git a/include/ui/console.h b/include/ui/console.h
> index fc21621656..0c02190963 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -74,6 +74,9 @@ struct MouseTransformInfo {
>  };
>  
>  void hmp_mouse_set(Monitor *mon, const QDict *qdict);
> +void hmp_screendump_sync(const char *filename,
> +                         bool has_device, const char *device,
> +                         bool has_head, int64_t head, Error **errp);
>  
>  /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
>     constants) */
> diff --git a/hmp.c b/hmp.c
> index 679467d85a..da9008fe63 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -2144,7 +2144,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
>      int64_t head = qdict_get_try_int(qdict, "head", 0);
>      Error *err = NULL;
>  
> -    qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
> +    hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err);
>      hmp_handle_error(mon, &err);
>  }
>  
> diff --git a/ui/console.c b/ui/console.c
> index 29234605a7..da51861191 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -32,6 +32,7 @@
>  #include "chardev/char-fe.h"
>  #include "trace.h"
>  #include "exec/memory.h"
> +#include "monitor/monitor.h"
>  
>  #define DEFAULT_BACKSCROLL 512
>  #define CONSOLE_CURSOR_PERIOD 500
> @@ -116,6 +117,12 @@ typedef enum {
>      TEXT_CONSOLE_FIXED_SIZE
>  } console_type_t;
>  
> +struct qmp_screendump {
> +    gchar *filename;
> +    QmpReturn *ret;
> +    QLIST_ENTRY(qmp_screendump) link;
> +};
> +
>  struct QemuConsole {
>      Object parent;
>  
> @@ -165,6 +172,8 @@ struct QemuConsole {
>      QEMUFIFO out_fifo;
>      uint8_t out_fifo_buf[16];
>      QEMUTimer *kbd_timer;
> +
> +    QLIST_HEAD(, qmp_screendump) qmp_screendumps;
>  };
>  
>  struct DisplayState {
> @@ -190,6 +199,8 @@ static void dpy_refresh(DisplayState *s);
>  static DisplayState *get_alloc_displaystate(void);
>  static void text_console_update_cursor_timer(void);
>  static void text_console_update_cursor(void *opaque);
> +static void ppm_save(const char *filename, DisplaySurface *ds,
> +                     Error **errp);
>  
>  static void gui_update(void *opaque)
>  {
> @@ -256,8 +267,42 @@ static void gui_setup_refresh(DisplayState *ds)
>      ds->have_text = have_text;
>  }
>  
> +static void qmp_screendump_finish(QemuConsole *con, const char *filename,
> +                                  QmpReturn *ret)
> +{
> +    Error *err = NULL;
> +    DisplaySurface *surface;
> +    Monitor *prev_mon = cur_mon;
> +
> +    if (qmp_return_is_cancelled(ret)) {
> +        return;
> +    }
> +
> +    cur_mon = qmp_return_get_monitor(ret);
> +    surface = qemu_console_surface(con);
> +
> +    /* FIXME: async save with coroutine? it would have to copy or lock
> +     * the surface. */
> +    ppm_save(filename, surface, &err);
> +
> +    if (err) {
> +        qmp_return_error(ret, err);
> +    } else {
> +        qmp_screendump_return(ret);
> +    }
> +    cur_mon = prev_mon;
> +}
> +
>  void graphic_hw_update_done(QemuConsole *con)
>  {
> +    struct qmp_screendump *dump, *next;
> +
> +    QLIST_FOREACH_SAFE(dump, &con->qmp_screendumps, link, next) {
> +        qmp_screendump_finish(con, dump->filename, dump->ret);
> +        g_free(dump->filename);
> +        QLIST_REMOVE(dump, link);
> +        g_free(dump);
> +    }
>  }
>  
>  bool graphic_hw_update(QemuConsole *con)
> @@ -358,35 +403,70 @@ write_err:
>      goto out;
>  }
>  
> -void qmp_screendump(const char *filename, bool has_device, const char *device,
> -                    bool has_head, int64_t head, Error **errp)
> +
> +static QemuConsole *get_console(bool has_device, const char *device,
> +                                bool has_head, int64_t head, Error **errp)
>  {
> -    QemuConsole *con;
> -    DisplaySurface *surface;
> +    QemuConsole *con = NULL;
>  
>      if (has_device) {
>          con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
>                                                   errp);
> -        if (!con) {
> -            return;
> -        }
>      } else {
>          if (has_head) {
>              error_setg(errp, "'head' must be specified together with 'device'");
> -            return;
> +            return NULL;
>          }
>          con = qemu_console_lookup_by_index(0);
>          if (!con) {
>              error_setg(errp, "There is no console to take a screendump from");
> -            return;
>          }
>      }
>  
> +    return con;
> +}
> +
> +void hmp_screendump_sync(const char *filename,
> +                         bool has_device, const char *device,
> +                         bool has_head, int64_t head, Error **errp)
> +{
> +    DisplaySurface *surface;
> +    QemuConsole *con = get_console(has_device, device, has_head, head, errp);
> +
> +    if (!con) {
> +        return;
> +    }
> +    /* This may not complete the drawing with Spice, you may have
> +     * glitches or outdated dumps, use qmp instead! */
>      graphic_hw_update(con);
>      surface = qemu_console_surface(con);
>      ppm_save(filename, surface, errp);
>  }
>  
> +void qmp_screendump(const char *filename,
> +                    bool has_device, const char *device,
> +                    bool has_head, int64_t head,
> +                    QmpReturn *qret)
> +{
> +    Error *err = NULL;
> +    bool async;
> +    QemuConsole *con = get_console(has_device, device, has_head, head, &err);
> +
> +    if (!con) {
> +        qmp_return_error(qret, err);
> +        return;
> +    }
> +    async = graphic_hw_update(con);
> +    if (async) {
> +        struct qmp_screendump *dump = g_new(struct qmp_screendump, 1);
> +        dump->filename = g_strdup(filename);
> +        dump->ret = qret;
> +        QLIST_INSERT_HEAD(&con->qmp_screendumps, dump, link);
> +    } else {
> +        qmp_screendump_finish(con, filename, qret);
> +    }
> +}
> +
>  void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
>  {
>      if (!con) {
> @@ -1280,6 +1360,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
>      obj = object_new(TYPE_QEMU_CONSOLE);
>      s = QEMU_CONSOLE(obj);
>      s->head = head;
> +    QLIST_INIT(&s->qmp_screendumps);
>      object_property_add_link(obj, "device", TYPE_DEVICE,
>                               (Object **)&s->device,
>                               object_property_allow_set_link,
> -- 
> 2.17.0.rc1.1.g4c4f2b46a3
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous
  2018-04-12 14:48   ` Dr. David Alan Gilbert
@ 2018-04-19 16:05     ` Marc-André Lureau
  2019-04-09 14:06       ` Marc-André Lureau
  1 sibling, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-04-19 16:05 UTC (permalink / raw)
  To: Dr. David Alan Gilbert
  Cc: Eduardo Habkost, Juan Quintela, Markus Armbruster, QEMU,
	Gerd Hoffmann, Cleber Rosa, Michael Roth

Hi

On Thu, Apr 12, 2018 at 4:48 PM, Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
> * Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
>> Make screendump asynchronous to provide correct screendumps.
>>
>> HMP doesn't have async support, so it has to remain synchronous and
>> potentially incorrect to avoid potential races.
>>
>> Fixes:
>> https://bugzilla.redhat.com/show_bug.cgi?id=1230527
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Hi,
>   Looking at this and the previous pair of patches, I think we'd be
> better if we defined that async commands took a callback function
> pointer and data that they call.
>
>   Here we've got 'graphic_hw_update_done' that explicitly walks qmp
> lists; but I think it's better just to pass graphic_hw_update() the
> completion data together with a callback function and it calls that when
> it's done.
>
> (Also isn't it a little bit of a race, calling graphic_hw_update() and
> *then* adding the entry to the list? Can't it end up calling the _done()
> before we've added it to the list).
>
> Also, do we need a list of outstanding screendumps, or should we just
> have a list of async commands.
>
> It wouldn't seem hard to use the async-QMP command from the HMP
> and then just provide a way to tell whether it had finished.
>

I should have updated the commit message, but the following patches do
introduce async-QMP support for HMP (by suspending HMP monitor, just
like QMP).

> Dave
>
>> ---
>>  qapi/ui.json         |  3 +-
>>  include/ui/console.h |  3 ++
>>  hmp.c                |  2 +-
>>  ui/console.c         | 99 ++++++++++++++++++++++++++++++++++++++++----
>>  4 files changed, 96 insertions(+), 11 deletions(-)
>>
>> diff --git a/qapi/ui.json b/qapi/ui.json
>> index 5d01ad4304..4d2c326fb9 100644
>> --- a/qapi/ui.json
>> +++ b/qapi/ui.json
>> @@ -96,7 +96,8 @@
>>  #
>>  ##
>>  { 'command': 'screendump',
>> -  'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
>> +  'data': {'filename': 'str', '*device': 'str', '*head': 'int'},
>> +  'async': true }
>>
>>  ##
>>  # == Spice
>> diff --git a/include/ui/console.h b/include/ui/console.h
>> index fc21621656..0c02190963 100644
>> --- a/include/ui/console.h
>> +++ b/include/ui/console.h
>> @@ -74,6 +74,9 @@ struct MouseTransformInfo {
>>  };
>>
>>  void hmp_mouse_set(Monitor *mon, const QDict *qdict);
>> +void hmp_screendump_sync(const char *filename,
>> +                         bool has_device, const char *device,
>> +                         bool has_head, int64_t head, Error **errp);
>>
>>  /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
>>     constants) */
>> diff --git a/hmp.c b/hmp.c
>> index 679467d85a..da9008fe63 100644
>> --- a/hmp.c
>> +++ b/hmp.c
>> @@ -2144,7 +2144,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
>>      int64_t head = qdict_get_try_int(qdict, "head", 0);
>>      Error *err = NULL;
>>
>> -    qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
>> +    hmp_screendump_sync(filename, id != NULL, id, id != NULL, head, &err);
>>      hmp_handle_error(mon, &err);
>>  }
>>
>> diff --git a/ui/console.c b/ui/console.c
>> index 29234605a7..da51861191 100644
>> --- a/ui/console.c
>> +++ b/ui/console.c
>> @@ -32,6 +32,7 @@
>>  #include "chardev/char-fe.h"
>>  #include "trace.h"
>>  #include "exec/memory.h"
>> +#include "monitor/monitor.h"
>>
>>  #define DEFAULT_BACKSCROLL 512
>>  #define CONSOLE_CURSOR_PERIOD 500
>> @@ -116,6 +117,12 @@ typedef enum {
>>      TEXT_CONSOLE_FIXED_SIZE
>>  } console_type_t;
>>
>> +struct qmp_screendump {
>> +    gchar *filename;
>> +    QmpReturn *ret;
>> +    QLIST_ENTRY(qmp_screendump) link;
>> +};
>> +
>>  struct QemuConsole {
>>      Object parent;
>>
>> @@ -165,6 +172,8 @@ struct QemuConsole {
>>      QEMUFIFO out_fifo;
>>      uint8_t out_fifo_buf[16];
>>      QEMUTimer *kbd_timer;
>> +
>> +    QLIST_HEAD(, qmp_screendump) qmp_screendumps;
>>  };
>>
>>  struct DisplayState {
>> @@ -190,6 +199,8 @@ static void dpy_refresh(DisplayState *s);
>>  static DisplayState *get_alloc_displaystate(void);
>>  static void text_console_update_cursor_timer(void);
>>  static void text_console_update_cursor(void *opaque);
>> +static void ppm_save(const char *filename, DisplaySurface *ds,
>> +                     Error **errp);
>>
>>  static void gui_update(void *opaque)
>>  {
>> @@ -256,8 +267,42 @@ static void gui_setup_refresh(DisplayState *ds)
>>      ds->have_text = have_text;
>>  }
>>
>> +static void qmp_screendump_finish(QemuConsole *con, const char *filename,
>> +                                  QmpReturn *ret)
>> +{
>> +    Error *err = NULL;
>> +    DisplaySurface *surface;
>> +    Monitor *prev_mon = cur_mon;
>> +
>> +    if (qmp_return_is_cancelled(ret)) {
>> +        return;
>> +    }
>> +
>> +    cur_mon = qmp_return_get_monitor(ret);
>> +    surface = qemu_console_surface(con);
>> +
>> +    /* FIXME: async save with coroutine? it would have to copy or lock
>> +     * the surface. */
>> +    ppm_save(filename, surface, &err);
>> +
>> +    if (err) {
>> +        qmp_return_error(ret, err);
>> +    } else {
>> +        qmp_screendump_return(ret);
>> +    }
>> +    cur_mon = prev_mon;
>> +}
>> +
>>  void graphic_hw_update_done(QemuConsole *con)
>>  {
>> +    struct qmp_screendump *dump, *next;
>> +
>> +    QLIST_FOREACH_SAFE(dump, &con->qmp_screendumps, link, next) {
>> +        qmp_screendump_finish(con, dump->filename, dump->ret);
>> +        g_free(dump->filename);
>> +        QLIST_REMOVE(dump, link);
>> +        g_free(dump);
>> +    }
>>  }
>>
>>  bool graphic_hw_update(QemuConsole *con)
>> @@ -358,35 +403,70 @@ write_err:
>>      goto out;
>>  }
>>
>> -void qmp_screendump(const char *filename, bool has_device, const char *device,
>> -                    bool has_head, int64_t head, Error **errp)
>> +
>> +static QemuConsole *get_console(bool has_device, const char *device,
>> +                                bool has_head, int64_t head, Error **errp)
>>  {
>> -    QemuConsole *con;
>> -    DisplaySurface *surface;
>> +    QemuConsole *con = NULL;
>>
>>      if (has_device) {
>>          con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
>>                                                   errp);
>> -        if (!con) {
>> -            return;
>> -        }
>>      } else {
>>          if (has_head) {
>>              error_setg(errp, "'head' must be specified together with 'device'");
>> -            return;
>> +            return NULL;
>>          }
>>          con = qemu_console_lookup_by_index(0);
>>          if (!con) {
>>              error_setg(errp, "There is no console to take a screendump from");
>> -            return;
>>          }
>>      }
>>
>> +    return con;
>> +}
>> +
>> +void hmp_screendump_sync(const char *filename,
>> +                         bool has_device, const char *device,
>> +                         bool has_head, int64_t head, Error **errp)
>> +{
>> +    DisplaySurface *surface;
>> +    QemuConsole *con = get_console(has_device, device, has_head, head, errp);
>> +
>> +    if (!con) {
>> +        return;
>> +    }
>> +    /* This may not complete the drawing with Spice, you may have
>> +     * glitches or outdated dumps, use qmp instead! */
>>      graphic_hw_update(con);
>>      surface = qemu_console_surface(con);
>>      ppm_save(filename, surface, errp);
>>  }
>>
>> +void qmp_screendump(const char *filename,
>> +                    bool has_device, const char *device,
>> +                    bool has_head, int64_t head,
>> +                    QmpReturn *qret)
>> +{
>> +    Error *err = NULL;
>> +    bool async;
>> +    QemuConsole *con = get_console(has_device, device, has_head, head, &err);
>> +
>> +    if (!con) {
>> +        qmp_return_error(qret, err);
>> +        return;
>> +    }
>> +    async = graphic_hw_update(con);
>> +    if (async) {
>> +        struct qmp_screendump *dump = g_new(struct qmp_screendump, 1);
>> +        dump->filename = g_strdup(filename);
>> +        dump->ret = qret;
>> +        QLIST_INSERT_HEAD(&con->qmp_screendumps, dump, link);
>> +    } else {
>> +        qmp_screendump_finish(con, filename, qret);
>> +    }
>> +}
>> +
>>  void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
>>  {
>>      if (!con) {
>> @@ -1280,6 +1360,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
>>      obj = object_new(TYPE_QEMU_CONSOLE);
>>      s = QEMU_CONSOLE(obj);
>>      s->head = head;
>> +    QLIST_INIT(&s->qmp_screendumps);
>>      object_property_add_link(obj, "device", TYPE_DEVICE,
>>                               (Object **)&s->device,
>>                               object_property_allow_set_link,
>> --
>> 2.17.0.rc1.1.g4c4f2b46a3
>>
> --
> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
>



-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL Marc-André Lureau
@ 2018-07-05 11:35   ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 11:35 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Let's make json_parser_parse_err() suck less, and simplify caller
> error handling.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  monitor.c             | 4 ----
>  qobject/json-parser.c | 7 ++++++-
>  2 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index 5889a32231..e9d0c4d172 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -4053,10 +4053,6 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
>      QMPRequest *req_obj;
>  
>      req = json_parser_parse_err(tokens, NULL, &err);
> -    if (!req && !err) {
> -        /* json_parser_parse_err() sucks: can fail without setting @err */
> -        error_setg(&err, QERR_JSON_PARSING);
> -    }
>      if (err) {
>          goto err;
>      }
> diff --git a/qobject/json-parser.c b/qobject/json-parser.c
> index 769b960c9f..c39cd8e4d7 100644
> --- a/qobject/json-parser.c
> +++ b/qobject/json-parser.c
> @@ -591,7 +591,12 @@ QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp)
>  
>      result = parse_value(ctxt, ap);
>  
> -    error_propagate(errp, ctxt->err);
> +    if (!result && !ctxt->err) {
> +        /* TODO: improve error reporting */
> +        error_setg(errp, "Failed to parse JSON");
> +    } else {
> +        error_propagate(errp, ctxt->err);
> +    }
>  
>      parser_context_free(ctxt);

I'd be tempted to put more colorful language in that comment ;)

You update just one caller.  Let's review the other ones:

* qga/main.c process_event()

    qdict = qobject_to(QDict, json_parser_parse_err(tokens, NULL, &err));
    if (err || !qdict) {
        qobject_unref(qdict);
        qdict = qdict_new();
        if (!err) {
            g_warning("failed to parse event: unknown error");
            error_setg(&err, QERR_JSON_PARSING);
        } else {
            g_warning("failed to parse event: %s", error_get_pretty(err));
        }
        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
        error_free(err);
    }

  The if (!err) conditional is now dead.  Please drop it.

* qobject/json-parser.c json_parser_parse()

  Ignores the error.  Okay.

* qobject/qjson.c qobject_from_jsonv() via parse_json()

  - qobject_from_json()

    ~ block.c parse_json_filename()

        options_obj = qobject_from_json(filename, errp);
        if (!options_obj) {
            /* Work around qobject_from_json() lossage TODO fix that */
            if (errp && !*errp) {
                error_setg(errp, "Could not parse the JSON options");
                return NULL;
            }
            error_prepend(errp, "Could not parse the JSON options: ");
            return NULL;
        }

      The work-around is now dead.  Please drop it.

    ~ More callers, please review them.

  - qobject_from_jsonf()

        va_start(ap, string);
        obj = qobject_from_jsonv(string, &ap, &error_abort);
        va_end(ap);

        assert(obj != NULL);

    Now dies in error_handle_fatal() instead of the assertion.  Okay.

  - tests/libqtest.c qmp_fd_sendv()

    Passes &error_abort, does nothing when qobject_from_jsonv() returns
    null.  Your fix makes this catch invalid JSON instead of silently
    ignoring it.  Good, but please mention it in the commit message.

  - tests/test-qobject-input-visitor.c
    visitor_input_test_init_internal()

    Like qobject_from_jsonf().  Okay.

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

* Re: [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times Marc-André Lureau
@ 2018-07-05 11:42   ` Markus Armbruster
  2018-07-05 12:17     ` Marc-André Lureau
  0 siblings, 1 reply; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 11:42 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> We can easily avoid the burden of checking if the lexer was
> initialized prior to calling destroy by the caller, let's do it.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qobject/json-lexer.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
> index 980ba159d6..0eaba43a2c 100644
> --- a/qobject/json-lexer.c
> +++ b/qobject/json-lexer.c
> @@ -386,5 +386,8 @@ int json_lexer_flush(JSONLexer *lexer)
>  
>  void json_lexer_destroy(JSONLexer *lexer)
>  {
> -    g_string_free(lexer->token, true);
> +    if (lexer->token) {
> +        g_string_free(lexer->token, true);
> +        lexer->token = NULL;
> +    }
>  }

Is this just on general principles[*], or does it enable simplifactions
later in this series?


[*] Write the destructor so that it just works on uninitialized,
all-zeroes objects, on partly initialized objects (constructor failed),
and on completely initialized objects (constructor succeeded).

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

* Re: [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser Marc-André Lureau
@ 2018-07-05 11:49   ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 11:49 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The lexer always returns 0 when char feeding. Furthermore, none of the
> caller care about the return value.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

My intuitive reaction was "how come the lexer can't fail?"  It can, but
it communicates failure by pushing JSON_ERROR to the streamer, not by
having the feed function return an error.

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

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

* Re: [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests Marc-André Lureau
@ 2018-07-05 11:55   ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 11:55 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> These 2 tests exhibited two qmp bugs that were fixed in 2.7
> (series from commit e64c75a9752c5d0fd64eb2e684c656a5ea7d03c6 to
> commit 1382d4abdf9619985e4078e37e49e487cea9935e)
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Thanks for holding on to the test cases :)

Needs a rebase.

> ---
>  tests/qmp-test.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 49 insertions(+)
>
> diff --git a/tests/qmp-test.c b/tests/qmp-test.c
> index 07c0b87e27..642f46a332 100644
> --- a/tests/qmp-test.c
> +++ b/tests/qmp-test.c
> @@ -224,7 +224,50 @@ static void test_qmp_oob(void)
>          }
>          QDECREF(resp);
>      }
> +    qtest_end();
> +}
> +
> +static void test_object_add_without_props(void)
> +{
> +    QDict *ret, *error;
> +    const gchar *klass, *desc;
> +
> +    qtest_start("-machine none");
>  
> +    ret = qmp("{'execute': 'object-add',"
> +              " 'arguments': { 'qom-type': 'memory-backend-ram', 'id': 'ram1' } }");
> +    g_assert_nonnull(ret);
> +
> +    error = qdict_get_qdict(ret, "error");
> +    klass = qdict_get_try_str(error, "class");
> +    desc = qdict_get_try_str(error, "desc");
> +
> +    g_assert_cmpstr(klass, ==, "GenericError");
> +    g_assert_cmpstr(desc, ==, "can't create backend with size 0");

Sure checking "desc" is worthwhile?  We don't do that elsewhere in this
test program, and only rarely in other test programs.

> +
> +    QDECREF(ret);
> +    qtest_end();
> +}
> +
> +static void test_qom_set_without_value(void)
> +{
> +    QDict *ret, *error;
> +    const gchar *klass, *desc;
> +
> +    qtest_start("-machine none");
> +
> +    ret = qmp("{'execute': 'qom-set',"
> +              " 'arguments': { 'path': '/machine', 'property': 'rtc-time' } }");
> +    g_assert_nonnull(ret);
> +
> +    error = qdict_get_qdict(ret, "error");
> +    klass = qdict_get_try_str(error, "class");
> +    desc = qdict_get_try_str(error, "desc");
> +
> +    g_assert_cmpstr(klass, ==, "GenericError");
> +    g_assert_cmpstr(desc, ==, "Parameter 'value' is missing");

Likewise.

> +
> +    QDECREF(ret);
>      qtest_end();
>  }
>  
> @@ -411,13 +454,19 @@ int main(int argc, char *argv[])
>  
>      g_test_init(&argc, &argv, NULL);
>  
> +    qtest_add_func("qmp/object-add-without-props",
> +                   test_object_add_without_props);
> +    qtest_add_func("qmp/qom-set-without-value",
> +                   test_qom_set_without_value);
>      qtest_add_func("qmp/protocol", test_qmp_protocol);
>      qtest_add_func("qmp/oob", test_qmp_oob);
> +
>      qmp_schema_init(&schema);
>      add_query_tests(&schema);
>  
>      ret = g_test_run();
>  
>      qmp_schema_cleanup(&schema);
> +
>      return ret;
>  }

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

* Re: [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/*
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
@ 2018-07-05 11:56   ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 11:56 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela, Markus Armbruster,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Presumably 0.15 was the version it was first introduced, but
> qmp keeps evolving. There is no point in having that version
> as test prefix, 'qmp' makes more sense here.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  tests/test-qmp-cmds.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
> index 93fbbb1b73..b49e9dd029 100644
> --- a/tests/test-qmp-cmds.c
> +++ b/tests/test-qmp-cmds.c
> @@ -273,11 +273,11 @@ int main(int argc, char **argv)
>  {
>      g_test_init(&argc, &argv, NULL);
>  
> -    g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
> -    g_test_add_func("/0.15/dispatch_cmd_failure", test_dispatch_cmd_failure);
> -    g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
> -    g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
> -    g_test_add_func("/0.15/dealloc_partial", test_dealloc_partial);
> +    g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd);
> +    g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure);
> +    g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
> +    g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
> +    g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
>  
>      test_qmp_init_marshal(&qmp_commands);
>      g_test_run();

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

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

* Re: [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test
  2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test Marc-André Lureau
@ 2018-07-05 11:59   ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 11:59 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Verify the usage of this schema feature and the API behaviour.  This
> should be the only case where qmp_dispatch() returns NULL without
> error.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Needs a rebase.  Looks good otherwise.

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

* Re: [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times
  2018-07-05 11:42   ` Markus Armbruster
@ 2018-07-05 12:17     ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2018-07-05 12:17 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Eduardo Habkost, Juan Quintela, QEMU, Dr. David Alan Gilbert,
	Gerd Hoffmann, Cleber Rosa, Michael Roth

Hi

On Thu, Jul 5, 2018 at 1:42 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> We can easily avoid the burden of checking if the lexer was
>> initialized prior to calling destroy by the caller, let's do it.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  qobject/json-lexer.c | 5 ++++-
>>  1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
>> index 980ba159d6..0eaba43a2c 100644
>> --- a/qobject/json-lexer.c
>> +++ b/qobject/json-lexer.c
>> @@ -386,5 +386,8 @@ int json_lexer_flush(JSONLexer *lexer)
>>
>>  void json_lexer_destroy(JSONLexer *lexer)
>>  {
>> -    g_string_free(lexer->token, true);
>> +    if (lexer->token) {
>> +        g_string_free(lexer->token, true);
>> +        lexer->token = NULL;
>> +    }
>>  }
>
> Is this just on general principles[*], or does it enable simplifactions
> later in this series?
>
>

It allowed further simplification later in the series. I don't know if
this is still necessary after the rebase and other changes, feel free
to delay it.

thanks



-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type
  2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
                   ` (42 preceding siblings ...)
  2018-04-04 13:45 ` Eric Blake
@ 2018-07-05 13:05 ` Markus Armbruster
  43 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2018-07-05 13:05 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Juan Quintela,
	Dr. David Alan Gilbert, Gerd Hoffmann, Cleber Rosa, Michael Roth

PATCH 02+09+11 applied to qapi-next.  Thanks!

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

* Re: [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous
@ 2019-04-09 14:06       ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2019-04-09 14:06 UTC (permalink / raw)
  To: Dr. David Alan Gilbert
  Cc: Eduardo Habkost, Juan Quintela, Markus Armbruster, QEMU,
	Gerd Hoffmann, Cleber Rosa, Michael Roth

Hi

On Thu, Apr 12, 2018 at 4:49 PM Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
>
> * Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
> > Make screendump asynchronous to provide correct screendumps.
> >
> > HMP doesn't have async support, so it has to remain synchronous and
> > potentially incorrect to avoid potential races.
> >
> > Fixes:
> > https://bugzilla.redhat.com/show_bug.cgi?id=1230527
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Hi,
>   Looking at this and the previous pair of patches, I think we'd be
> better if we defined that async commands took a callback function
> pointer and data that they call.
>
>   Here we've got 'graphic_hw_update_done' that explicitly walks qmp
> lists; but I think it's better just to pass graphic_hw_update() the
> completion data together with a callback function and it calls that when
> it's done.

The calling context is in QmpReturn: it will handle further dispatch
on the associated session (it has the associated cb+data, if you
will).

gfx_update_async() doesn't have cb+data to associate the call with a
finish handler. Further down, spice doesn't keep the request "context"
either. All it does is call graphic_hw_update_done() when update is
finished, that's why we walk the list of pending screendumps here.

We could move the pending list of async screendumps down to spice (and
other console renderers), but that would make the code more
complicated & duplicated for no strong reason.

>
> (Also isn't it a little bit of a race, calling graphic_hw_update() and
> *then* adding the entry to the list? Can't it end up calling the _done()
> before we've added it to the list).

Yes, in theory it could. In practice that won't happen today, but we
may change things later and not realize we "broke" screendump. So I
will rearrange the code to add it to the pending list before calling
graphic_hw_update().


>
> Also, do we need a list of outstanding screendumps, or should we just
> have a list of async commands.

We have both, mostly for simplicity and flexibility reasons. If we
removed the outstanding screendump list, we would have to query it
from the session.

Thanks for the review, I'll send an update revision.


--
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous
@ 2019-04-09 14:06       ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2019-04-09 14:06 UTC (permalink / raw)
  To: Dr. David Alan Gilbert
  Cc: Eduardo Habkost, Juan Quintela, QEMU, Markus Armbruster,
	Gerd Hoffmann, Cleber Rosa, Michael Roth

Hi

On Thu, Apr 12, 2018 at 4:49 PM Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
>
> * Marc-André Lureau (marcandre.lureau@redhat.com) wrote:
> > Make screendump asynchronous to provide correct screendumps.
> >
> > HMP doesn't have async support, so it has to remain synchronous and
> > potentially incorrect to avoid potential races.
> >
> > Fixes:
> > https://bugzilla.redhat.com/show_bug.cgi?id=1230527
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Hi,
>   Looking at this and the previous pair of patches, I think we'd be
> better if we defined that async commands took a callback function
> pointer and data that they call.
>
>   Here we've got 'graphic_hw_update_done' that explicitly walks qmp
> lists; but I think it's better just to pass graphic_hw_update() the
> completion data together with a callback function and it calls that when
> it's done.

The calling context is in QmpReturn: it will handle further dispatch
on the associated session (it has the associated cb+data, if you
will).

gfx_update_async() doesn't have cb+data to associate the call with a
finish handler. Further down, spice doesn't keep the request "context"
either. All it does is call graphic_hw_update_done() when update is
finished, that's why we walk the list of pending screendumps here.

We could move the pending list of async screendumps down to spice (and
other console renderers), but that would make the code more
complicated & duplicated for no strong reason.

>
> (Also isn't it a little bit of a race, calling graphic_hw_update() and
> *then* adding the entry to the list? Can't it end up calling the _done()
> before we've added it to the list).

Yes, in theory it could. In practice that won't happen today, but we
may change things later and not realize we "broke" screendump. So I
will rearrange the code to add it to the pending list before calling
graphic_hw_update().


>
> Also, do we need a list of outstanding screendumps, or should we just
> have a list of async commands.

We have both, mostly for simplicity and flexibility reasons. If we
removed the outstanding screendump list, we would have to query it
from the session.

Thanks for the review, I'll send an update revision.


--
Marc-André Lureau


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

end of thread, other threads:[~2019-04-09 14:08 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-26 15:08 [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 01/38] HACK: add back OOB Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 02/38] qmp-shell: learn to send commands with quoted arguments Marc-André Lureau
2018-03-26 18:26   ` Eduardo Habkost
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 03/38] Revert "qmp: isolate responses into io thread" Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 04/38] monitor: no need to save need_resume Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 05/38] monitor: further simplify previous patch Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 06/38] monitor: no need to remove desc before replacing it Marc-André Lureau
2018-03-26 19:31   ` Eric Blake
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 07/38] json-parser: always set an error if return NULL Marc-André Lureau
2018-07-05 11:35   ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 08/38] json-lexer: make it safe to call multiple times Marc-André Lureau
2018-07-05 11:42   ` Markus Armbruster
2018-07-05 12:17     ` Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 09/38] json: remove useless return value from lexer/parser Marc-André Lureau
2018-07-05 11:49   ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 10/38] tests: add a few qemu-qmp tests Marc-André Lureau
2018-07-05 11:55   ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 11/38] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
2018-07-05 11:56   ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 12/38] tests: add a qmp success-response test Marc-André Lureau
2018-07-05 11:59   ` Markus Armbruster
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 13/38] qga: process_event() simplification Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 14/38] monitor: simplify monitor_qmp_respond() Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 15/38] qmp: pass and return a QDict to qmp_dispatch() Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 16/38] qmp: move 'id' copy " Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 17/38] qmp: constify qmp_is_oob() Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 18/38] qmp: add QmpSession Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 19/38] QmpSession: add a return_cb Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 20/38] QmpSession: add json parser and use it in qga Marc-André Lureau
2018-03-26 15:08 ` [Qemu-devel] [PATCH v3 21/38] QmpSession: add a dispatch callback Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 22/38] monitor: use QmpSession parsing and common dispatch code Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 23/38] QmpSession: introduce QmpReturn Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 24/38] qmp: remove qmp_build_error_object() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 25/38] qmp: remove need for qobject_from_jsonf() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 26/38] qmp: fold do_qmp_dispatch() in qmp_dispatch() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 27/38] QmpSession: keep a queue of pending commands Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 28/38] QmpSession: return orderly Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 29/38] qmp: introduce asynchronous command type Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 30/38] scripts: learn 'async' qapi commands Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 31/38] qmp: add qmp_return_is_cancelled() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 32/38] monitor: add qmp_return_get_monitor() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 33/38] console: graphic_hw_update return true if async Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 34/38] console: add graphic_hw_update_done() Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 35/38] console: make screendump asynchronous Marc-André Lureau
2018-04-12 14:48   ` Dr. David Alan Gilbert
2018-04-19 16:05     ` Marc-André Lureau
2019-04-09 14:06     ` Marc-André Lureau
2019-04-09 14:06       ` Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 36/38] monitor: start making qmp_human_monitor_command() asynchronous Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 37/38] monitor: teach HMP about asynchronous commands Marc-André Lureau
2018-03-26 15:09 ` [Qemu-devel] [PATCH v3 38/38] hmp: call the asynchronous QMP screendump to fix outdated/glitches Marc-André Lureau
2018-03-26 17:24 ` [Qemu-devel] [PATCH v3 00/38] RFC: monitor: add asynchronous command type Dr. David Alan Gilbert
2018-03-26 17:30   ` Marc-André Lureau
2018-03-26 17:43 ` no-reply
2018-03-26 17:55 ` no-reply
2018-04-04  9:34 ` Stefan Hajnoczi
2018-04-04 10:01   ` Marc-André Lureau
2018-04-04 13:45 ` Eric Blake
2018-04-04 13:57   ` Marc-André Lureau
2018-07-05 13:05 ` Markus Armbruster

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