All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
@ 2017-01-18 16:03 Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests Marc-André Lureau
                   ` (28 more replies)
  0 siblings, 29 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, 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.

Note that qmp events are asynchronous messages, and must be handled
appropriately by the client: dispatch both reply and events after a
command is sent for example.

The benefits of async commands that can be trade-off depending on the
requirements are:

1) allow 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 tricky
(see below) to solve.  Furthermore, many QMP commands do IO and could
be considered 'slow' and blocking today.

2) allow concurrent commands and events. This mainly implies hanlding
concurrency in qemu and out-of-order replies for the client. As noted
earlier, a good qmp client already has to handle dispatching of
received messages (reply and events).

The traditional approach to solving the above in qemu is the following
scheme:
-> { "execute": "do-foo" }
<- { "return": {} }
<- { "event": "FOO_DONE" }

It has several flaws:
- FOO_DONE event has no semantic link with do-foo in the qapi
  schema. It is not simple to generalize that pattern when writing
  qmp clients. It makes documentation and usage harder.
- the FOO_DONE event has no clear association with the command that
  triggered it: commands/events have to come up with additional
  specific association schemes (ids, path etc)
- FOO_DONE is broadcasted to all clients, but they may have no way to
  interprete it or interest in it, or worse it may conflict with their
  own commands.
- the arguably useless empty reply return

For some cases, it makes sense to use that scheme, or a more complete
one: to have an "handler" associated with an on-going operation, that
can be queried, modified, cancelled etc (block jobs etc). Also, some
operations have a global side-effect, in which case that cmd+event
scheme is right, as all clients are listening for global events.

However, for the simple case where a client want to perform a "local
context" operation (dump, query etc), QAPI can easily do better
without resorting to this pattern: it can send the reply when the
operation is done. That would make QAPI schema, usage and
documentation more obvious.

The following series implements an async solution, by introducing a
context associated with a command, it can:
- defer the return
- return only to the caller (no broadcasted event)
- return with the 'id' associated with the call (as originally intended)
- optionnally allow cancellation when the client is gone
- track on-going qapi command(s) per client

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

2) allow concurrent commands when 'async' is negotiated. If the client
doesn't support 'async', then the monitor is suspended during command
execution (events are still sent). Effectively, async commands behave
like normal commands from client POV in this case, giving full
backward compatibility.

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). HMP remains sync, but it would be worth to make
it possible to call async:true qapi commands.

The last patch cleans up qmp_dispatch usage to have consistant checks
between qga & qemu, and simplify QmpClient/parser_feed usage.

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 (25):
  tests: start generic qemu-qmp tests
  tests: change /0.15/* tests to /qmp/*
  qmp: teach qmp_dispatch() to take a pre-filled QDict
  qmp: use a return callback for the command reply
  qmp: add QmpClient
  qmp: add qmp_return_is_cancelled()
  qmp: introduce async command type
  qapi: ignore top-level 'id' field
  qmp: take 'id' from request
  qmp: check that async command have an 'id'
  scripts: learn 'async' qapi commands
  tests: add dispatch async tests
  monitor: add 'async' capability
  monitor: add !qmp pre-conditions
  monitor: suspend when running async and client has no async
  qmp: update qmp-spec about async capability
  qtest: add qtest-timeout
  qtest: add qtest_init_qmp_caps()
  tests: add tests for async and non-async clients
  qapi: improve 'screendump' documentation
  console: graphic_hw_update return true if async
  console: add graphic_hw_update_done()
  console: make screendump async
  qtest: add /qemu-qmp/screendump test
  qmp: move json-message-parser and check to QmpClient

 qapi-schema.json                        |  45 +++++-
 qapi/introspect.json                    |   2 +-
 scripts/qapi.py                         |  14 +-
 scripts/qapi-commands.py                | 139 ++++++++++++++---
 scripts/qapi-introspect.py              |   7 +-
 hw/display/qxl.h                        |   2 +-
 include/qapi/qmp/dispatch.h             |  66 +++++++-
 include/ui/console.h                    |   5 +-
 tests/libqtest.h                        |   9 ++
 hmp.c                                   |   2 +-
 hw/display/qxl-render.c                 |  14 +-
 hw/display/qxl.c                        |   8 +-
 monitor.c                               | 213 +++++++++++++-------------
 qapi/qmp-dispatch.c                     | 260 +++++++++++++++++++++++++++++---
 qapi/qmp-registry.c                     |  25 ++-
 qga/main.c                              |  73 ++-------
 qobject/json-lexer.c                    |   4 +-
 qtest.c                                 |  48 ++++++
 tests/libqtest.c                        |  13 +-
 tests/qmp-test.c                        | 191 +++++++++++++++++++++++
 tests/test-qmp-commands.c               | 211 ++++++++++++++++++++++----
 ui/console.c                            |  86 ++++++++++-
 MAINTAINERS                             |   1 +
 docs/qmp-spec.txt                       |  48 +++++-
 tests/Makefile.include                  |   3 +
 tests/qapi-schema/async.err             |   0
 tests/qapi-schema/async.exit            |   1 +
 tests/qapi-schema/async.json            |   6 +
 tests/qapi-schema/async.out             |  10 ++
 tests/qapi-schema/qapi-schema-test.json |   6 +
 tests/qapi-schema/qapi-schema-test.out  |   6 +
 tests/qapi-schema/test-qapi.py          |   7 +-
 32 files changed, 1236 insertions(+), 289 deletions(-)
 create mode 100644 tests/qmp-test.c
 create mode 100644 tests/qapi-schema/async.err
 create mode 100644 tests/qapi-schema/async.exit
 create mode 100644 tests/qapi-schema/async.json
 create mode 100644 tests/qapi-schema/async.out

-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:14   ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 02/25] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
                   ` (27 subsequent siblings)
  28 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, 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>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/qmp-test.c       | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++
 MAINTAINERS            |  1 +
 tests/Makefile.include |  2 ++
 3 files changed, 82 insertions(+)
 create mode 100644 tests/qmp-test.c

diff --git a/tests/qmp-test.c b/tests/qmp-test.c
new file mode 100644
index 0000000000..480ff28339
--- /dev/null
+++ b/tests/qmp-test.c
@@ -0,0 +1,79 @@
+/*
+ * QTest testcase for QMP
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * This program tests QMP commands maintained with the QMP core.
+ * These are defined in qmp.c.  Tests for QMP commands defined in
+ * another subsystem should go into a test program maintained with
+ * that subsystem.
+ *
+ * TODO Actually cover the commands.  The tests we got so far only
+ * demonstrate specific bugs we've fixed.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+static void test_object_add_without_props(void)
+{
+    QDict *ret, *error;
+    const gchar *klass, *desc;
+
+    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);
+}
+
+static void test_qom_set_without_value(void)
+{
+    QDict *ret, *error;
+    const gchar *klass, *desc;
+
+    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);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_start("-machine none");
+
+    qtest_add_func("/qemu-qmp/object-add-without-props",
+                   test_object_add_without_props);
+    qtest_add_func("/qemu-qmp/qom-set-without-value",
+                   test_qom_set_without_value);
+
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index 1444b26dc0..0c94a1ce27 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1368,6 +1368,7 @@ F: qmp.c
 F: monitor.c
 F: docs/*qmp-*
 F: scripts/qmp/
+F: tests/qmp-test.c
 T: git git://repo.or.cz/qemu/armbru.git qapi-next
 
 Register API
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 96f59703a1..152655d086 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -316,6 +316,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
 check-qtest-s390x-y = tests/boot-serial-test$(EXESUF)
 
 check-qtest-generic-y += tests/qom-test$(EXESUF)
+check-qtest-generic-y += tests/qmp-test$(EXESUF)
 
 qapi-schema += alternate-any.json
 qapi-schema += alternate-array.json
@@ -687,6 +688,7 @@ tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
 tests/qom-test$(EXESUF): tests/qom-test.o
+tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-pc-obj-y)
 tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
 tests/nvme-test$(EXESUF): tests/nvme-test.o
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 02/25] tests: change /0.15/* tests to /qmp/*
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 03/25] qmp: teach qmp_dispatch() to take a pre-filled QDict Marc-André Lureau
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, 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-commands.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index ff944811e8..e46981eb1e 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -267,11 +267,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);
 
     module_call_init(MODULE_INIT_QAPI);
     g_test_run();
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 03/25] qmp: teach qmp_dispatch() to take a pre-filled QDict
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 02/25] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 04/25] qmp: use a return callback for the command reply Marc-André Lureau
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Give an optional qdict for the dispatch call to be used for the
reply. The qemu monitor has the request "id" pre-filled, simplifying the
code a bit.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 include/qapi/qmp/dispatch.h |  2 +-
 monitor.c                   | 26 +++++++++++---------------
 qapi/qmp-dispatch.c         |  5 ++---
 qga/main.c                  |  2 +-
 tests/test-qmp-commands.c   |  8 ++++----
 5 files changed, 19 insertions(+), 24 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 57651ea955..db483481b0 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -38,7 +38,7 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn,
                           QmpCommandOptions options);
 void qmp_unregister_command(const char *name);
 QmpCommand *qmp_find_command(const char *name);
-QObject *qmp_dispatch(QObject *request);
+QObject *qmp_dispatch(QObject *request, QDict *rsp);
 void qmp_disable_command(const char *name);
 void qmp_enable_command(const char *name);
 bool qmp_command_is_enabled(const QmpCommand *cmd);
diff --git a/monitor.c b/monitor.c
index 0841d436b0..edd30e4d8f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3725,12 +3725,13 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
 
 static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
 {
-    QObject *req, *rsp = NULL, *id = NULL;
-    QDict *qdict = NULL;
+    QObject *req, *rsp, *id = NULL;
+    QDict *qdict, *rqdict = qdict_new();
     const char *cmd_name;
     Monitor *mon = cur_mon;
     Error *err = NULL;
 
+    rsp = QOBJECT(rqdict);
     req = json_parser_parse_err(tokens, NULL, &err);
     if (err || !req || qobject_type(req) != QTYPE_QDICT) {
         if (!err) {
@@ -3745,8 +3746,11 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     }
 
     id = qdict_get(qdict, "id");
-    qobject_incref(id);
-    qdict_del(qdict, "id");
+    if (id) {
+        qobject_incref(id);
+        qdict_del(qdict, "id");
+        qdict_put_obj(rqdict, "id", id);
+    }
 
     cmd_name = qdict_get_str(qdict, "execute");
     trace_handle_qmp_command(mon, cmd_name);
@@ -3755,27 +3759,19 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
         goto err_out;
     }
 
-    rsp = qmp_dispatch(req);
+    rsp = qmp_dispatch(req, rqdict);
 
 err_out:
     if (err) {
-        qdict = qdict_new();
-        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
+        qdict_put_obj(rqdict, "error", qmp_build_error_object(err));
         error_free(err);
-        rsp = QOBJECT(qdict);
     }
 
     if (rsp) {
-        if (id) {
-            qdict_put_obj(qobject_to_qdict(rsp), "id", id);
-            id = NULL;
-        }
-
         monitor_json_emitter(mon, rsp);
     }
 
-    qobject_decref(id);
-    qobject_decref(rsp);
+    QDECREF(rqdict);
     qobject_decref(req);
 }
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 505eb418ac..dbf2e5b655 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -116,15 +116,14 @@ QObject *qmp_build_error_object(Error *err)
                               error_get_pretty(err));
 }
 
-QObject *qmp_dispatch(QObject *request)
+QObject *qmp_dispatch(QObject *request, QDict *rsp)
 {
     Error *err = NULL;
     QObject *ret;
-    QDict *rsp;
 
     ret = do_qmp_dispatch(request, &err);
 
-    rsp = qdict_new();
+    rsp = rsp ?: qdict_new();
     if (err) {
         qdict_put_obj(rsp, "error", qmp_build_error_object(err));
         error_free(err);
diff --git a/qga/main.c b/qga/main.c
index 6caf215575..442990c869 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -555,7 +555,7 @@ static void process_command(GAState *s, QDict *req)
 
     g_assert(req);
     g_debug("processing command");
-    rsp = qmp_dispatch(QOBJECT(req));
+    rsp = qmp_dispatch(QOBJECT(req), NULL);
     if (rsp) {
         ret = send_response(s, rsp);
         if (ret) {
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index e46981eb1e..a6d8e4b141 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -94,7 +94,7 @@ static void test_dispatch_cmd(void)
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
-    resp = qmp_dispatch(QOBJECT(req));
+    resp = qmp_dispatch(QOBJECT(req), NULL);
     assert(resp != NULL);
     assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
 
@@ -111,7 +111,7 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
 
-    resp = qmp_dispatch(QOBJECT(req));
+    resp = qmp_dispatch(QOBJECT(req), NULL);
     assert(resp != NULL);
     assert(qdict_haskey(qobject_to_qdict(resp), "error"));
 
@@ -125,7 +125,7 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
-    resp = qmp_dispatch(QOBJECT(req));
+    resp = qmp_dispatch(QOBJECT(req), NULL);
     assert(resp != NULL);
     assert(qdict_haskey(qobject_to_qdict(resp), "error"));
 
@@ -139,7 +139,7 @@ static QObject *test_qmp_dispatch(QDict *req)
     QDict *resp;
     QObject *ret;
 
-    resp_obj = qmp_dispatch(QOBJECT(req));
+    resp_obj = qmp_dispatch(QOBJECT(req), NULL);
     assert(resp_obj);
     resp = qobject_to_qdict(resp_obj);
     assert(resp && !qdict_haskey(resp, "error"));
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 04/25] qmp: use a return callback for the command reply
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (2 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 03/25] qmp: teach qmp_dispatch() to take a pre-filled QDict Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 05/25] qmp: add QmpClient Marc-André Lureau
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Introduce QmpDispatchReturn, a callback called when a command reply is
ready to be sent. Future patches will extend the context to enable async
replies. Currently, all qmp commands reply in the calling context (they
are all sync).

QmpReturn and associated functions are used internally for the sync
dispatch, but will be the basis of the following async context, that's
the reason why they are exported.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h | 22 ++++++++++++++++-
 monitor.c                   | 19 +++++++++------
 qapi/qmp-dispatch.c         | 58 +++++++++++++++++++++++++++++++++++----------
 qga/main.c                  | 22 ++++++++---------
 tests/test-qmp-commands.c   | 54 ++++++++++++++++++++++-------------------
 5 files changed, 119 insertions(+), 56 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index db483481b0..780b3e2a09 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -17,6 +17,14 @@
 #include "qapi/qmp/qobject.h"
 #include "qapi/qmp/qdict.h"
 
+typedef void (QmpDispatchReturn) (QObject *rsp, void *opaque);
+
+typedef struct QmpReturn {
+    QDict *rsp;
+    QmpDispatchReturn *return_cb;
+    void *opaque;
+} QmpReturn;
+
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
 typedef enum QmpCommandOptions
@@ -38,7 +46,8 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn,
                           QmpCommandOptions options);
 void qmp_unregister_command(const char *name);
 QmpCommand *qmp_find_command(const char *name);
-QObject *qmp_dispatch(QObject *request, QDict *rsp);
+void qmp_dispatch(QObject *request, QDict *rsp,
+                  QmpDispatchReturn *return_cb, void *opaque);
 void qmp_disable_command(const char *name);
 void qmp_enable_command(const char *name);
 bool qmp_command_is_enabled(const QmpCommand *cmd);
@@ -48,4 +57,15 @@ QObject *qmp_build_error_object(Error *err);
 typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
 void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque);
 
+/*
+ * qmp_return{_error}:
+ *
+ * Construct the command reply, and call the
+ * return_cb() associated with the dispatch.
+ *
+ * Finally, free the QmpReturn.
+ */
+void qmp_return(QmpReturn *qret, QObject *cmd_rsp);
+void qmp_return_error(QmpReturn *qret, Error *err);
+
 #endif
diff --git a/monitor.c b/monitor.c
index edd30e4d8f..462ee127b4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3723,15 +3723,21 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
     return input_dict;
 }
 
+static void qmp_dispatch_return(QObject *rsp, void *opaque)
+{
+    Monitor *mon = opaque;
+
+    monitor_json_emitter(mon, rsp);
+}
+
 static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
 {
-    QObject *req, *rsp, *id = NULL;
+    QObject *req, *id = NULL;
     QDict *qdict, *rqdict = qdict_new();
     const char *cmd_name;
     Monitor *mon = cur_mon;
     Error *err = NULL;
 
-    rsp = QOBJECT(rqdict);
     req = json_parser_parse_err(tokens, NULL, &err);
     if (err || !req || qobject_type(req) != QTYPE_QDICT) {
         if (!err) {
@@ -3759,16 +3765,15 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
         goto err_out;
     }
 
-    rsp = qmp_dispatch(req, rqdict);
+    qmp_dispatch(req, rqdict, qmp_dispatch_return, mon);
+    qobject_decref(req);
+    return;
 
 err_out:
     if (err) {
         qdict_put_obj(rqdict, "error", qmp_build_error_object(err));
         error_free(err);
-    }
-
-    if (rsp) {
-        monitor_json_emitter(mon, rsp);
+        monitor_json_emitter(mon, QOBJECT(rqdict));
     }
 
     QDECREF(rqdict);
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index dbf2e5b655..7e9d03f262 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -62,7 +62,7 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
     return dict;
 }
 
-static QObject *do_qmp_dispatch(QObject *request, Error **errp)
+static QObject *do_qmp_dispatch(QObject *request, QmpReturn *qret, Error **errp)
 {
     Error *local_err = NULL;
     const char *command;
@@ -116,23 +116,57 @@ QObject *qmp_build_error_object(Error *err)
                               error_get_pretty(err));
 }
 
-QObject *qmp_dispatch(QObject *request, QDict *rsp)
+static void qmp_return_free(QmpReturn *qret)
+{
+    QDict *rsp = qret->rsp;
+
+    qobject_decref(QOBJECT(rsp));
+    g_free(qret);
+}
+
+static void do_qmp_return(QmpReturn *qret)
+{
+    QDict *rsp = qret->rsp;
+
+    qret->return_cb(QOBJECT(rsp), qret->opaque);
+
+    qmp_return_free(qret);
+}
+
+void qmp_return(QmpReturn *qret, QObject *cmd_rsp)
+{
+    qdict_put_obj(qret->rsp, "return", cmd_rsp ?: QOBJECT(qdict_new()));
+
+    do_qmp_return(qret);
+}
+
+void qmp_return_error(QmpReturn *qret, Error *err)
+{
+    qdict_put_obj(qret->rsp, "error", qmp_build_error_object(err));
+    error_free(err);
+
+    do_qmp_return(qret);
+}
+
+void qmp_dispatch(QObject *request, QDict *rsp,
+                  QmpDispatchReturn *return_cb, void *opaque)
 {
     Error *err = NULL;
+    QmpReturn *qret = g_new0(QmpReturn, 1);
     QObject *ret;
 
-    ret = do_qmp_dispatch(request, &err);
+    assert(return_cb);
+
+    qret->rsp = rsp ?: qdict_new();
+    qret->return_cb = return_cb;
+    qret->opaque = opaque;
+
+    ret = do_qmp_dispatch(request, qret, &err);
 
-    rsp = rsp ?: qdict_new();
     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 NULL;
+        qmp_return(qret, ret);
     }
-
-    return QOBJECT(rsp);
 }
diff --git a/qga/main.c b/qga/main.c
index 442990c869..a50acf27a5 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -548,21 +548,21 @@ static int send_response(GAState *s, QObject *payload)
     return 0;
 }
 
-static void process_command(GAState *s, QDict *req)
+static void dispatch_return_cb(QObject *rsp, void *opaque)
 {
-    QObject *rsp = NULL;
-    int ret;
+    GAState *s = opaque;
+    int ret = send_response(s, rsp);
+
+    if (ret) {
+        g_warning("error sending response: %s", strerror(ret));
+    }
+}
 
+static void process_command(GAState *s, QDict *req)
+{
     g_assert(req);
     g_debug("processing command");
-    rsp = qmp_dispatch(QOBJECT(req), NULL);
-    if (rsp) {
-        ret = send_response(s, rsp);
-        if (ret) {
-            g_warning("error sending response: %s", strerror(ret));
-        }
-        qobject_decref(rsp);
-    }
+    qmp_dispatch(QOBJECT(req), NULL, dispatch_return_cb, s);
 }
 
 /* handle requests/control events coming in over the channel */
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index a6d8e4b141..6510245b4f 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -85,23 +85,30 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
     return ret;
 }
 
+static void dispatch_cmd_return(QObject *resp, void *opaque)
+{
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+}
 
 /* test commands with no input and no return value */
 static void test_dispatch_cmd(void)
 {
     QDict *req = qdict_new();
-    QObject *resp;
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
-    resp = qmp_dispatch(QOBJECT(req), NULL);
-    assert(resp != NULL);
-    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_return, NULL);
 
-    qobject_decref(resp);
     QDECREF(req);
 }
 
+static void dispatch_cmd_error_return(QObject *resp, void *opaque)
+{
+    assert(resp != NULL);
+    assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+}
+
 /* test commands that return an error due to invalid parameters */
 static void test_dispatch_cmd_failure(void)
 {
@@ -111,11 +118,7 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
 
-    resp = qmp_dispatch(QOBJECT(req), NULL);
-    assert(resp != NULL);
-    assert(qdict_haskey(qobject_to_qdict(resp), "error"));
-
-    qobject_decref(resp);
+    qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_error_return, NULL);
     QDECREF(req);
 
     /* check that with extra arguments it throws an error */
@@ -125,28 +128,29 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
-    resp = qmp_dispatch(QOBJECT(req), NULL);
-    assert(resp != NULL);
-    assert(qdict_haskey(qobject_to_qdict(resp), "error"));
-
-    qobject_decref(resp);
+    qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_error_return, NULL);
     QDECREF(req);
 }
 
+static QObject *dispatch_ret;
+
+static void qmp_dispatch_return(QObject *resp_obj, void *opaque)
+{
+    QDict *resp = qobject_to_qdict(resp_obj);
+    assert(resp && !qdict_haskey(resp, "error"));
+    dispatch_ret = qdict_get(resp, "return");
+    assert(dispatch_ret);
+    qobject_incref(dispatch_ret);
+}
+
 static QObject *test_qmp_dispatch(QDict *req)
 {
-    QObject *resp_obj;
-    QDict *resp;
     QObject *ret;
 
-    resp_obj = qmp_dispatch(QOBJECT(req), NULL);
-    assert(resp_obj);
-    resp = qobject_to_qdict(resp_obj);
-    assert(resp && !qdict_haskey(resp, "error"));
-    ret = qdict_get(resp, "return");
-    assert(ret);
-    qobject_incref(ret);
-    qobject_decref(resp_obj);
+    qmp_dispatch(QOBJECT(req), NULL, qmp_dispatch_return, NULL);
+    ret = dispatch_ret;
+    dispatch_ret = NULL;
+
     return ret;
 }
 
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 05/25] qmp: add QmpClient
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (3 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 04/25] qmp: use a return callback for the command reply Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 06/25] qmp: add qmp_return_is_cancelled() Marc-André Lureau
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Add a new QmpClient structure holding the dispatch return callback
and the list of pending QmpReturns.

When a client disconnects, call qmp_client_destroy(). This will remove
all pending returns from the client list, and prevent a reply from being
sent later: new clients will only receive reply they expect, and not one
from a previous client.

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

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 780b3e2a09..32876764f3 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -17,14 +17,23 @@
 #include "qapi/qmp/qobject.h"
 #include "qapi/qmp/qdict.h"
 
-typedef void (QmpDispatchReturn) (QObject *rsp, void *opaque);
+typedef struct QmpClient QmpClient;
+
+typedef void (QmpDispatchReturn) (QmpClient *client, QObject *rsp);
 
 typedef struct QmpReturn {
     QDict *rsp;
-    QmpDispatchReturn *return_cb;
-    void *opaque;
+    QmpClient *client;
+
+    QLIST_ENTRY(QmpReturn) link;
 } QmpReturn;
 
+struct QmpClient {
+    QmpDispatchReturn *return_cb;
+
+    QLIST_HEAD(, QmpReturn) pending;
+};
+
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
 typedef enum QmpCommandOptions
@@ -46,8 +55,9 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn,
                           QmpCommandOptions options);
 void qmp_unregister_command(const char *name);
 QmpCommand *qmp_find_command(const char *name);
-void qmp_dispatch(QObject *request, QDict *rsp,
-                  QmpDispatchReturn *return_cb, void *opaque);
+void qmp_client_init(QmpClient *client, QmpDispatchReturn *return_cb);
+void qmp_client_destroy(QmpClient *client);
+void qmp_dispatch(QmpClient *client, QObject *request, QDict *rsp);
 void qmp_disable_command(const char *name);
 void qmp_enable_command(const char *name);
 bool qmp_command_is_enabled(const QmpCommand *cmd);
@@ -61,7 +71,7 @@ void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque);
  * qmp_return{_error}:
  *
  * Construct the command reply, and call the
- * return_cb() associated with the dispatch.
+ * return_cb() associated with the QmpClient.
  *
  * Finally, free the QmpReturn.
  */
diff --git a/monitor.c b/monitor.c
index 462ee127b4..98ba40b573 100644
--- a/monitor.c
+++ b/monitor.c
@@ -165,6 +165,7 @@ typedef struct {
      * mode.
      */
     bool in_command_mode;       /* are we in command mode? */
+    QmpClient client;
 } MonitorQMP;
 
 /*
@@ -584,6 +585,7 @@ static void monitor_data_destroy(Monitor *mon)
     if (monitor_is_qmp(mon)) {
         json_message_parser_destroy(&mon->qmp.parser);
     }
+    qmp_client_destroy(&mon->qmp.client);
     g_free(mon->rs);
     QDECREF(mon->outbuf);
     qemu_mutex_destroy(&mon->out_lock);
@@ -3723,9 +3725,9 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
     return input_dict;
 }
 
-static void qmp_dispatch_return(QObject *rsp, void *opaque)
+static void qmp_dispatch_return(QmpClient *client, QObject *rsp)
 {
-    Monitor *mon = opaque;
+    Monitor *mon = container_of(client, Monitor, qmp.client);
 
     monitor_json_emitter(mon, rsp);
 }
@@ -3765,7 +3767,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
         goto err_out;
     }
 
-    qmp_dispatch(req, rqdict, qmp_dispatch_return, mon);
+    qmp_dispatch(&mon->qmp.client, req, rqdict);
     qobject_decref(req);
     return;
 
@@ -3854,6 +3856,7 @@ static void monitor_qmp_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_OPENED:
+        qmp_client_init(&mon->qmp.client, qmp_dispatch_return);
         mon->qmp.in_command_mode = false;
         data = get_qmp_greeting();
         monitor_json_emitter(mon, data);
@@ -3863,6 +3866,7 @@ static void monitor_qmp_event(void *opaque, int event)
     case CHR_EVENT_CLOSED:
         json_message_parser_destroy(&mon->qmp.parser);
         json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
+        qmp_client_destroy(&mon->qmp.client);
         mon_refcount--;
         monitor_fdsets_cleanup();
         break;
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 7e9d03f262..31227ce6e9 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -120,6 +120,10 @@ static void qmp_return_free(QmpReturn *qret)
 {
     QDict *rsp = qret->rsp;
 
+    if (qret->client) {
+        QLIST_REMOVE(qret, link);
+    }
+
     qobject_decref(QOBJECT(rsp));
     g_free(qret);
 }
@@ -127,8 +131,11 @@ static void qmp_return_free(QmpReturn *qret)
 static void do_qmp_return(QmpReturn *qret)
 {
     QDict *rsp = qret->rsp;
+    QmpClient *client = qret->client;
 
-    qret->return_cb(QOBJECT(rsp), qret->opaque);
+    if (client) {
+        client->return_cb(client, QOBJECT(rsp));
+    }
 
     qmp_return_free(qret);
 }
@@ -148,25 +155,50 @@ void qmp_return_error(QmpReturn *qret, Error *err)
     do_qmp_return(qret);
 }
 
-void qmp_dispatch(QObject *request, QDict *rsp,
-                  QmpDispatchReturn *return_cb, void *opaque)
+void qmp_client_init(QmpClient *client, QmpDispatchReturn *return_cb)
+{
+    assert(!client->return_cb);
+
+    client->return_cb = return_cb;
+    QLIST_INIT(&client->pending);
+}
+
+void qmp_client_destroy(QmpClient *client)
+{
+    QmpReturn *ret, *next;
+
+    client->return_cb = NULL;
+    /* Remove the weak references to the pending returns. The
+     * dispatched function is the owner of QmpReturn, and will have to
+     * qmp_return(). (it might be interesting to have a way to notify
+     * that the client disconnected to cancel an on-going
+     * operation) */
+    QLIST_FOREACH_SAFE(ret, &client->pending, link, next) {
+        ret->client = NULL;
+        QLIST_REMOVE(ret, link);
+    }
+}
+
+void qmp_dispatch(QmpClient *client, QObject *request, QDict *rsp)
 {
     Error *err = NULL;
     QmpReturn *qret = g_new0(QmpReturn, 1);
     QObject *ret;
 
-    assert(return_cb);
+    assert(client);
 
     qret->rsp = rsp ?: qdict_new();
-    qret->return_cb = return_cb;
-    qret->opaque = opaque;
+    qret->client = client;
+    QLIST_INSERT_HEAD(&client->pending, qret, link);
 
     ret = do_qmp_dispatch(request, qret, &err);
 
     if (err) {
         assert(!ret);
         qmp_return_error(qret, err);
+        return;
     } else if (ret) {
         qmp_return(qret, ret);
+        return;
     }
 }
diff --git a/qga/main.c b/qga/main.c
index a50acf27a5..a75544ed7a 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -89,6 +89,7 @@ struct GAState {
 #endif
     gchar *pstate_filepath;
     GAPersistentState pstate;
+    QmpClient client;
 };
 
 struct GAState *ga_state;
@@ -548,9 +549,9 @@ static int send_response(GAState *s, QObject *payload)
     return 0;
 }
 
-static void dispatch_return_cb(QObject *rsp, void *opaque)
+static void dispatch_return_cb(QmpClient *client, QObject *rsp)
 {
-    GAState *s = opaque;
+    GAState *s = container_of(client, GAState, client);
     int ret = send_response(s, rsp);
 
     if (ret) {
@@ -562,7 +563,7 @@ static void process_command(GAState *s, QDict *req)
 {
     g_assert(req);
     g_debug("processing command");
-    qmp_dispatch(QOBJECT(req), NULL, dispatch_return_cb, s);
+    qmp_dispatch(&ga_state->client, QOBJECT(req), NULL);
 }
 
 /* handle requests/control events coming in over the channel */
@@ -1286,6 +1287,7 @@ static int run_agent(GAState *s, GAConfig *config)
     ga_command_state_init_all(s->command_state);
     json_message_parser_init(&s->parser, process_event);
     ga_state = s;
+    qmp_client_init(&s->client, dispatch_return_cb);
 #ifndef _WIN32
     if (!register_signal_handlers()) {
         g_critical("failed to register signal handlers");
@@ -1381,7 +1383,7 @@ end:
     }
     g_free(s->pstate_filepath);
     g_free(s->state_filepath_isfrozen);
-
+    qmp_client_destroy(&s->client);
     if (config->daemonize) {
         unlink(config->pid_filepath);
     }
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 6510245b4f..a3c7c590d1 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -85,7 +85,7 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
     return ret;
 }
 
-static void dispatch_cmd_return(QObject *resp, void *opaque)
+static void dispatch_cmd_return(QmpClient *client, QObject *resp)
 {
     assert(resp != NULL);
     assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
@@ -94,16 +94,20 @@ static void dispatch_cmd_return(QObject *resp, void *opaque)
 /* test commands with no input and no return value */
 static void test_dispatch_cmd(void)
 {
+    QmpClient client = { 0, };
     QDict *req = qdict_new();
 
-    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+    qmp_client_init(&client, dispatch_cmd_return);
 
-    qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_return, NULL);
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
+    qmp_dispatch(&client, QOBJECT(req), NULL);
     QDECREF(req);
+
+    qmp_client_destroy(&client);
 }
 
-static void dispatch_cmd_error_return(QObject *resp, void *opaque)
+static void dispatch_cmd_error_return(QmpClient *client, QObject *resp)
 {
     assert(resp != NULL);
     assert(qdict_haskey(qobject_to_qdict(resp), "error"));
@@ -112,13 +116,15 @@ static void dispatch_cmd_error_return(QObject *resp, void *opaque)
 /* test commands that return an error due to invalid parameters */
 static void test_dispatch_cmd_failure(void)
 {
+    QmpClient client = { 0, };
     QDict *req = qdict_new();
     QDict *args = qdict_new();
-    QObject *resp;
+
+    qmp_client_init(&client, dispatch_cmd_error_return);
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
 
-    qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_error_return, NULL);
+    qmp_dispatch(&client, QOBJECT(req), NULL);
     QDECREF(req);
 
     /* check that with extra arguments it throws an error */
@@ -128,13 +134,16 @@ static void test_dispatch_cmd_failure(void)
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
-    qmp_dispatch(QOBJECT(req), NULL, dispatch_cmd_error_return, NULL);
+    qmp_dispatch(&client, QOBJECT(req), NULL);
+
     QDECREF(req);
+
+    qmp_client_destroy(&client);
 }
 
 static QObject *dispatch_ret;
 
-static void qmp_dispatch_return(QObject *resp_obj, void *opaque)
+static void qmp_dispatch_return(QmpClient *client, QObject *resp_obj)
 {
     QDict *resp = qobject_to_qdict(resp_obj);
     assert(resp && !qdict_haskey(resp, "error"));
@@ -146,8 +155,12 @@ static void qmp_dispatch_return(QObject *resp_obj, void *opaque)
 static QObject *test_qmp_dispatch(QDict *req)
 {
     QObject *ret;
+    QmpClient client = { 0, };
+
+    qmp_client_init(&client, qmp_dispatch_return);
+    qmp_dispatch(&client, QOBJECT(req), NULL);
+    qmp_client_destroy(&client);
 
-    qmp_dispatch(QOBJECT(req), NULL, qmp_dispatch_return, NULL);
     ret = dispatch_ret;
     dispatch_ret = NULL;
 
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 06/25] qmp: add qmp_return_is_cancelled()
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (4 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 05/25] qmp: add QmpClient Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 07/25] qmp: introduce async command type Marc-André Lureau
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

If the client is gone, 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 32876764f3..bc64d4ed15 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -78,4 +78,12 @@ void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque);
 void qmp_return(QmpReturn *qret, QObject *cmd_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);
+
 #endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 31227ce6e9..6ceece5ef0 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -155,6 +155,16 @@ void qmp_return_error(QmpReturn *qret, Error *err)
     do_qmp_return(qret);
 }
 
+bool qmp_return_is_cancelled(QmpReturn *qret)
+{
+    if (!qret->client) {
+        qmp_return_free(qret);
+        return true;
+    }
+
+    return false;
+}
+
 void qmp_client_init(QmpClient *client, QmpDispatchReturn *return_cb)
 {
     assert(!client->return_cb);
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 07/25] qmp: introduce async command type
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (5 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 06/25] qmp: add qmp_return_is_cancelled() Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 08/25] qapi: ignore top-level 'id' field Marc-André Lureau
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Qemu used to have command types, but it was removed in
42a502a7a60632234f0dd5028924926a7eac6c94. Add it back, and add a new
type of command, QmpCommandFuncAsync: they can return later thanks to
QmpReturn. This commit introduces the new types and register functions.

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

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index bc64d4ed15..e13e381834 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -35,6 +35,12 @@ struct QmpClient {
 };
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+typedef void (QmpCommandFuncAsync)(QDict *, QmpReturn *);
+
+typedef enum QmpCommandType {
+    QCT_NORMAL,
+    QCT_ASYNC,
+} QmpCommandType;
 
 typedef enum QmpCommandOptions
 {
@@ -44,8 +50,12 @@ typedef enum QmpCommandOptions
 
 typedef struct QmpCommand
 {
+    QmpCommandType type;
     const char *name;
-    QmpCommandFunc *fn;
+    union {
+        QmpCommandFunc *fn;
+        QmpCommandFuncAsync *fn_async;
+    };
     QmpCommandOptions options;
     QTAILQ_ENTRY(QmpCommand) node;
     bool enabled;
@@ -53,6 +63,8 @@ typedef struct QmpCommand
 
 void qmp_register_command(const char *name, QmpCommandFunc *fn,
                           QmpCommandOptions options);
+void qmp_register_async_command(const char *name, QmpCommandFuncAsync *fn,
+                                QmpCommandOptions options);
 void qmp_unregister_command(const char *name);
 QmpCommand *qmp_find_command(const char *name);
 void qmp_client_init(QmpClient *client, QmpDispatchReturn *return_cb);
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 6ceece5ef0..26f0a674ae 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -95,13 +95,20 @@ static QObject *do_qmp_dispatch(QObject *request, QmpReturn *qret, Error **errp)
         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());
+    switch (cmd->type) {
+    case QCT_NORMAL:
+        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());
+        }
+        break;
+    case QCT_ASYNC:
+        cmd->fn_async(args, qret);
+        break;
     }
 
     QDECREF(args);
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index e8053686f3..52b5f4cba0 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -18,16 +18,35 @@
 static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands =
     QTAILQ_HEAD_INITIALIZER(qmp_commands);
 
-void qmp_register_command(const char *name, QmpCommandFunc *fn,
-                          QmpCommandOptions options)
+static QmpCommand *qmp_command_new(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(&qmp_commands, cmd, node);
+
+    return cmd;
+}
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn,
+                          QmpCommandOptions options)
+{
+    QmpCommand *cmd = qmp_command_new(name, options);
+
+    cmd->type = QCT_NORMAL;
+    cmd->fn = fn;
+}
+
+void qmp_register_async_command(const char *name, QmpCommandFuncAsync *fn,
+                                QmpCommandOptions options)
+{
+    QmpCommand *cmd = qmp_command_new(name, options);
+
+    cmd->type = QCT_ASYNC;
+    cmd->fn_async = fn;
 }
 
 void qmp_unregister_command(const char *name)
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 08/25] qapi: ignore top-level 'id' field
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (6 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 07/25] qmp: introduce async command type Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 09/25] qmp: take 'id' from request Marc-André Lureau
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

'id' is documented as part of qmp-spec, it is valid at top-level entry.

The following patch copies the 'id' to the reply, without touching the
original request (which should eventually be const later) so it must
pass the check function without error.

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

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 26f0a674ae..d5c8670a4f 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -48,6 +48,8 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
                 return NULL;
             }
             has_exec_key = true;
+        } else if (!strcmp(arg_name, "id")) {
+            /* top-level 'id' is accepted */
         } else if (strcmp(arg_name, "arguments")) {
             error_setg(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
             return NULL;
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 09/25] qmp: take 'id' from request
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (7 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 08/25] qapi: ignore top-level 'id' field Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 10/25] qmp: check that async command have an 'id' Marc-André Lureau
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Copy 'id' from request to reply dict. This can be done earlier, such as
done currently by the monitor (because the qemu monitor.c may reply
directly without qmp_dispatch), but is now done as well in
qmp_dispatch() as convenience for other users such as QGA and
tests. Later patches will remove "id" manipulation from monitor.c.

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

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index d5c8670a4f..b6b0aed1b8 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -202,7 +202,8 @@ void qmp_dispatch(QmpClient *client, QObject *request, QDict *rsp)
 {
     Error *err = NULL;
     QmpReturn *qret = g_new0(QmpReturn, 1);
-    QObject *ret;
+    QObject *ret, *id;
+    QDict *req;
 
     assert(client);
 
@@ -210,6 +211,13 @@ void qmp_dispatch(QmpClient *client, QObject *request, QDict *rsp)
     qret->client = client;
     QLIST_INSERT_HEAD(&client->pending, qret, link);
 
+    req = qobject_to_qdict(request);
+    id = qdict_get(req, "id");
+    if (id) {
+        qobject_incref(id);
+        qdict_put_obj(qret->rsp, "id", id);
+    }
+
     ret = do_qmp_dispatch(request, qret, &err);
 
     if (err) {
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 10/25] qmp: check that async command have an 'id'
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (8 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 09/25] qmp: take 'id' from request Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 11/25] scripts: learn 'async' qapi commands Marc-André Lureau
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

The async support mandates that request have an 'id' (see documentation
in following patch).

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

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index b6b0aed1b8..76c7402ac8 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -109,6 +109,11 @@ static QObject *do_qmp_dispatch(QObject *request, QmpReturn *qret, Error **errp)
         }
         break;
     case QCT_ASYNC:
+        if (!qdict_haskey(qret->rsp, "id")) {
+            error_setg(errp, "An async command requires an 'id'");
+            break;
+        }
+
         cmd->fn_async(args, qret);
         break;
     }
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 11/25] scripts: learn 'async' qapi commands
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (9 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 10/25] qmp: check that async command have an 'id' Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 12/25] tests: add dispatch async tests Marc-André Lureau
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, 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>
---
 qapi/introspect.json           |   2 +-
 scripts/qapi.py                |  14 +++--
 scripts/qapi-commands.py       | 139 +++++++++++++++++++++++++++++++++--------
 scripts/qapi-introspect.py     |   7 ++-
 tests/Makefile.include         |   1 +
 tests/qapi-schema/async.err    |   0
 tests/qapi-schema/async.exit   |   1 +
 tests/qapi-schema/async.json   |   6 ++
 tests/qapi-schema/async.out    |  10 +++
 tests/qapi-schema/test-qapi.py |   7 ++-
 10 files changed, 151 insertions(+), 36 deletions(-)
 create mode 100644 tests/qapi-schema/async.err
 create mode 100644 tests/qapi-schema/async.exit
 create mode 100644 tests/qapi-schema/async.json
 create mode 100644 tests/qapi-schema/async.out

diff --git a/qapi/introspect.json b/qapi/introspect.json
index f6adc439bb..fd6a9e98a4 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -262,7 +262,7 @@
 # Since: 2.5
 ##
 { 'struct': 'SchemaInfoCommand',
-  'data': { 'arg-type': 'str', 'ret-type': 'str' } }
+  'data': { 'arg-type': 'str', 'ret-type': 'str', 'async': 'bool' } }
 
 ##
 # @SchemaInfoEvent:
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 53a44779d0..066b97a7fb 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -881,7 +881,8 @@ def check_exprs(exprs):
             add_struct(expr, info)
         elif 'command' in expr:
             check_keys(expr_elem, 'command', [],
-                       ['data', 'returns', 'gen', 'success-response', 'boxed'])
+                       ['data', 'returns', 'gen', 'success-response', 'boxed',
+                        'async'])
             add_name(expr['command'], info, 'command')
         elif 'event' in expr:
             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1064,7 +1065,7 @@ class QAPISchemaVisitor(object):
         pass
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, async):
         pass
 
     def visit_event(self, name, info, arg_type, boxed):
@@ -1406,7 +1407,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
 
 class QAPISchemaCommand(QAPISchemaEntity):
     def __init__(self, name, info, arg_type, ret_type, gen, success_response,
-                 boxed):
+                 boxed, async):
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -1417,6 +1418,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.gen = gen
         self.success_response = success_response
         self.boxed = boxed
+        self.async = async
 
     def check(self, schema):
         if self._arg_type_name:
@@ -1440,7 +1442,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
     def visit(self, visitor):
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
-                              self.gen, self.success_response, self.boxed)
+                              self.gen, self.success_response, self.boxed,
+                              self.async)
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
@@ -1645,6 +1648,7 @@ class QAPISchema(object):
         data = expr.get('data')
         rets = expr.get('returns')
         gen = expr.get('gen', True)
+        async = expr.get('async', False)
         success_response = expr.get('success-response', True)
         boxed = expr.get('boxed', False)
         if isinstance(data, OrderedDict):
@@ -1654,7 +1658,7 @@ class QAPISchema(object):
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
-                                           success_response, boxed))
+                                           success_response, boxed, async))
 
     def _def_event(self, expr, info):
         name = expr['event']
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 09e8467d90..8c6a281b7f 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -16,18 +16,30 @@ from qapi import *
 import re
 
 
-def gen_command_decl(name, arg_type, boxed, ret_type):
-    return mcgen('''
+def gen_command_decl(name, arg_type, boxed, ret_type, async):
+    if async:
+        extra = "QmpReturn *qret"
+    else:
+        extra = 'Error **errp'
+
+    if async:
+        return mcgen('''
+void qmp_%(name)s(%(params)s);
+void qmp_%(name)s_return(QmpReturn *qret%(c_type)s);
+''',
+                     c_type=(", " + ret_type.c_type() if ret_type else ""),
+                     name=c_name(name),
+                     params=gen_params(arg_type, boxed, extra))
+    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=gen_params(arg_type, boxed, 'Error **errp'))
+                     c_type=(ret_type and ret_type.c_type()) or 'void',
+                     c_name=c_name(name),
+                     params=gen_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 +51,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 +79,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,18 +146,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 gen_marshal_proto(name):
-    return 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
+def gen_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=gen_marshal_proto(name))
+                 proto=gen_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('''
@@ -103,9 +170,9 @@ def gen_marshal(name, arg_type, boxed, ret_type):
 {
     Error *err = NULL;
 ''',
-                proto=gen_marshal_proto(name))
+                proto=gen_marshal_proto(name, async))
 
-    if ret_type:
+    if ret_type and not async:
         ret += mcgen('''
     %(c_type)s retval;
 ''',
@@ -152,12 +219,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);
 ''')
 
@@ -192,15 +275,17 @@ out:
     return ret
 
 
-def gen_register_command(name, success_response):
+def gen_register_command(name, success_response, async):
     options = 'QCO_NO_OPTIONS'
     if not success_response:
         options = 'QCO_NO_SUCCESS_RESP'
-
+    func = 'qmp_register_command'
+    if async:
+        func = 'qmp_register_async_command'
     ret = mcgen('''
-    qmp_register_command("%(name)s", qmp_marshal_%(c_name)s, %(opts)s);
+    %(func)s("%(name)s", qmp_marshal_%(c_name)s, %(opts)s);
 ''',
-                name=name, c_name=c_name(name),
+                func=func, name=name, c_name=c_name(name),
                 opts=options)
     return ret
 
@@ -239,16 +324,19 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self._visited_ret_types = None
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, async):
         if not gen:
             return
-        self.decl += gen_command_decl(name, arg_type, boxed, ret_type)
+        self.decl += gen_command_decl(name, arg_type, boxed,
+                                      ret_type, async)
         if ret_type and ret_type not in self._visited_ret_types:
             self._visited_ret_types.add(ret_type)
             self.defn += gen_marshal_output(ret_type)
-        self.decl += gen_marshal_decl(name)
-        self.defn += gen_marshal(name, arg_type, boxed, ret_type)
-        self._regy += gen_register_command(name, success_response)
+        if async:
+            self.defn += gen_async_return(name, ret_type)
+        self.decl += gen_marshal_decl(name, async)
+        self.defn += gen_marshal(name, arg_type, boxed, ret_type, async)
+        self._regy += gen_register_command(name, success_response, async)
 
 
 (input_file, output_dir, do_c, do_h, prefix, opts) = parse_command_line()
@@ -306,6 +394,7 @@ fdef.write(mcgen('''
 fdecl.write(mcgen('''
 #include "%(prefix)sqapi-types.h"
 #include "qapi/qmp/qdict.h"
+#include "qapi/qmp/dispatch.h"
 #include "qapi/error.h"
 
 ''',
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 541644e350..f8a854dd0f 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -28,6 +28,8 @@ def to_json(obj, level=0):
                               to_json(obj[key], level + 1))
                 for key in sorted(obj.keys())]
         ret = '{' + ', '.join(elts) + '}'
+    elif isinstance(obj, bool):
+        ret = 'true' if obj else 'false'
     else:
         assert False                # not implemented
     if level == 1:
@@ -154,12 +156,13 @@ const char %(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):
+                      gen, success_response, boxed, 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_json(name, 'command',
                        {'arg-type': self._use_type(arg_type),
-                        'ret-type': self._use_type(ret_type)})
+                        'ret-type': self._use_type(ret_type),
+                        'async': async})
 
     def visit_event(self, name, info, arg_type, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 152655d086..d9b575e657 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -343,6 +343,7 @@ qapi-schema += args-member-unknown.json
 qapi-schema += args-name-clash.json
 qapi-schema += args-union.json
 qapi-schema += args-unknown.json
+qapi-schema += async.json
 qapi-schema += bad-base.json
 qapi-schema += bad-data.json
 qapi-schema += bad-ident.json
diff --git a/tests/qapi-schema/async.err b/tests/qapi-schema/async.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/async.exit b/tests/qapi-schema/async.exit
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/qapi-schema/async.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/async.json b/tests/qapi-schema/async.json
new file mode 100644
index 0000000000..2073349d39
--- /dev/null
+++ b/tests/qapi-schema/async.json
@@ -0,0 +1,6 @@
+##
+# @screendump-async:
+#
+# @filename: foo
+##
+{ 'command': 'screendump-async', 'data': {'filename': 'str'}, 'async': true }
diff --git a/tests/qapi-schema/async.out b/tests/qapi-schema/async.out
new file mode 100644
index 0000000000..bcb5a400d7
--- /dev/null
+++ b/tests/qapi-schema/async.out
@@ -0,0 +1,10 @@
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+    prefix QTYPE
+object q_empty
+object q_obj_screendump-async-arg
+    member filename: str optional=False
+command screendump-async q_obj_screendump-async-arg -> None
+   gen=True success_response=True boxed=False async=True
+doc symbol=screendump-async expr=('command', 'screendump-async')
+    arg=filename
+foo
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index b4cde4ff4f..608c304995 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -36,11 +36,12 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         self._print_variants(variants)
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, 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.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 12/25] tests: add dispatch async tests
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (10 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 11/25] scripts: learn 'async' qapi commands Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 13/25] monitor: add 'async' capability Marc-André Lureau
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Add a few tests to check:
- async dispatch
- async command without "id" failure
- destroying the client with pending requests

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

diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index a3c7c590d1..4613a9a4c8 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -85,6 +85,36 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
     return ret;
 }
 
+static GMainLoop *loop;
+
+typedef struct AsyncRet {
+    QmpReturn *qret;
+    UserDefB *ret;
+} AsyncRet;
+
+static gboolean qmp_user_async_idle(gpointer data)
+{
+    struct AsyncRet *async = (struct AsyncRet *)data;
+
+    qmp_user_async_return(async->qret, async->ret);
+    g_free(async);
+
+    g_main_loop_quit(loop);
+
+    return FALSE;
+}
+
+void qmp_user_async(int64_t a, bool has_b, int64_t b, QmpReturn *qret)
+{
+    AsyncRet *async = g_new0(AsyncRet, 1);
+
+    async->ret = g_new0(UserDefB, 1);
+    async->ret->intb = a + (has_b ? b : 0);
+    async->qret = qret;
+
+    g_idle_add(qmp_user_async_idle, async);
+}
+
 static void dispatch_cmd_return(QmpClient *client, QObject *resp)
 {
     assert(resp != NULL);
@@ -142,14 +172,19 @@ static void test_dispatch_cmd_failure(void)
 }
 
 static QObject *dispatch_ret;
+static char *ret_id;
 
 static void qmp_dispatch_return(QmpClient *client, QObject *resp_obj)
 {
     QDict *resp = qobject_to_qdict(resp_obj);
+
     assert(resp && !qdict_haskey(resp, "error"));
     dispatch_ret = qdict_get(resp, "return");
     assert(dispatch_ret);
     qobject_incref(dispatch_ret);
+
+    g_free(ret_id);
+    ret_id = g_strdup(qdict_get_try_str(resp, "id"));
 }
 
 static QObject *test_qmp_dispatch(QDict *req)
@@ -216,6 +251,97 @@ static void test_dispatch_cmd_io(void)
     QDECREF(req);
 }
 
+static void test_dispatch_cmd_async(void)
+{
+    QmpClient client = { .has_async = true };
+    QDict *dret, *req = qdict_new();
+    QDict *args = qdict_new();
+
+    loop = g_main_loop_new(NULL, FALSE);
+    qmp_client_init(&client, qmp_dispatch_return);
+
+    qdict_put(args, "a", qint_from_int(99));
+    qdict_put(req, "arguments", args);
+    qdict_put(req, "id", qstring_from_str("foo99"));
+    qdict_put(req, "execute", qstring_from_str("user-async"));
+
+    qmp_dispatch(&client, QOBJECT(req), NULL);
+    assert(!dispatch_ret);
+
+    g_main_loop_run(loop);
+    g_main_loop_unref(loop);
+
+    g_assert_cmpstr(ret_id, ==, "foo99");
+    dret = qobject_to_qdict(dispatch_ret);
+    assert(qdict_get_int(dret, "intb") == 99);
+    QDECREF(dret);
+    dispatch_ret = NULL;
+
+    qmp_client_destroy(&client);
+    QDECREF(req);
+}
+
+static void test_dispatch_cmd_async_no_id(void)
+{
+    QmpClient client = { .has_async = true };
+    QDict *req = qdict_new();
+    QDict *args = qdict_new();
+
+    qmp_client_init(&client, dispatch_cmd_error_return);
+
+    qdict_put(args, "a", qint_from_int(99));
+    qdict_put(req, "arguments", args);
+    qdict_put(req, "execute", qstring_from_str("user-async"));
+
+    qmp_dispatch(&client, QOBJECT(req), NULL);
+
+    assert(!dispatch_ret);
+    assert(QLIST_EMPTY(&client.pending));
+
+    qmp_client_destroy(&client);
+    QDECREF(req);
+}
+
+static void test_destroy_pending_async(void)
+{
+    QmpClient client = { .has_async = true };
+    QDict *req = qdict_new();
+    QDict *args = qdict_new();
+    QmpReturn *r;
+    int npending = 0;
+
+    loop = g_main_loop_new(NULL, FALSE);
+    qmp_client_init(&client, qmp_dispatch_return);
+
+    qdict_put(args, "a", qint_from_int(99));
+    qdict_put(req, "arguments", args);
+    qdict_put(req, "id", qstring_from_str("foo99"));
+    qdict_put(req, "execute", qstring_from_str("user-async"));
+
+    qmp_dispatch(&client, QOBJECT(req), NULL);
+    qmp_dispatch(&client, QOBJECT(req), NULL);
+    assert(!dispatch_ret);
+    QDECREF(req);
+
+    npending = 0;
+    QLIST_FOREACH(r, &client.pending, link) {
+        npending++;
+    }
+
+    g_assert_cmpint(npending, ==, 2);
+
+    /* destroy with pending async */
+    qmp_client_destroy(&client);
+
+    while (g_main_context_pending(NULL)) {
+        g_main_loop_run(loop);
+        /* no return since the client is gone */
+        assert(!dispatch_ret);
+    }
+
+    g_main_loop_unref(loop);
+}
+
 /* test generated dealloc functions for generated types */
 static void test_dealloc_types(void)
 {
@@ -287,11 +413,17 @@ 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_async", test_dispatch_cmd_async);
+    g_test_add_func("/qmp/dispatch_cmd_async_no_id",
+                    test_dispatch_cmd_async_no_id);
+    g_test_add_func("/qmp/destroy_pending_async", test_destroy_pending_async);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
     g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 
     module_call_init(MODULE_INIT_QAPI);
     g_test_run();
 
+    g_free(ret_id);
+
     return 0;
 }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index f4d8cc4230..6fe35bae77 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -292,6 +292,12 @@
 { 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true }
 
 ##
+# @user-async:
+##
+{ 'command': 'user-async', 'data': { 'a': 'int', '*b': 'int' },
+  'returns': 'UserDefB', 'async': true  }
+
+##
 # @UserDefOptions:
 #
 # For testing integer range flattening in opts-visitor. The following schema
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index bc8d496ff4..5b97906aae 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -219,11 +219,16 @@ object q_obj_uint64List-wrapper
     member data: uint64List optional=False
 object q_obj_uint8List-wrapper
     member data: uint8List optional=False
+object q_obj_user-async-arg
+    member a: int optional=False
+    member b: int optional=True
 object q_obj_user_def_cmd1-arg
     member ud1a: UserDefOne optional=False
 object q_obj_user_def_cmd2-arg
     member ud1a: UserDefOne optional=False
     member ud1b: UserDefOne optional=True
+command user-async q_obj_user-async-arg -> UserDefB
+   gen=True success_response=True boxed=False async=True
 command user_def_cmd None -> None
    gen=True success_response=True boxed=False
 command user_def_cmd0 Empty2 -> Empty2
@@ -337,6 +342,7 @@ returns something
 doc symbol=guest-sync expr=('command', 'guest-sync')
 doc symbol=boxed-struct expr=('command', 'boxed-struct')
 doc symbol=boxed-union expr=('command', 'boxed-union')
+doc symbol=user-async expr=('command', 'user-async')
 doc symbol=UserDefOptions expr=('struct', 'UserDefOptions')
     body=
 For testing integer range flattening in opts-visitor. The following schema
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 13/25] monitor: add 'async' capability
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (11 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 12/25] tests: add dispatch async tests Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 14/25] monitor: add !qmp pre-conditions Marc-André Lureau
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Declare that the server supports async.

Check if the client supports it: the following patch will suspend the
qmp monitor if an async command is ongoing but the client doesn't
support async.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json            | 16 ++++++++++++++--
 include/qapi/qmp/dispatch.h |  1 +
 monitor.c                   | 19 ++++++++++++++++---
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index ddc878390e..8366206415 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -72,11 +72,23 @@
 ##
 
 ##
+# @QMPCapability:
+#
+# QMP protocol capabilities
+#
+# @async: enables async messages
+#
+# Since: 2.9
+##
+{ 'enum': 'QMPCapability',
+  'data': ['async'] }
+
+##
 # @qmp_capabilities:
 #
 # Enable QMP capabilities.
 #
-# Arguments: None.
+# @capabilities: #optional an array of @QMPCapability (since 2.9)
 #
 # Example:
 #
@@ -90,7 +102,7 @@
 # Since: 0.13
 #
 ##
-{ 'command': 'qmp_capabilities' }
+{ 'command': 'qmp_capabilities', 'data': { '*capabilities': ['QMPCapability'] } }
 
 ##
 # @LostTickPolicy:
diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index e13e381834..4dd6de5ab2 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -32,6 +32,7 @@ struct QmpClient {
     QmpDispatchReturn *return_cb;
 
     QLIST_HEAD(, QmpReturn) pending;
+    bool has_async;             /* the client has async capability */
 };
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
diff --git a/monitor.c b/monitor.c
index 98ba40b573..585f7b6a1a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -563,9 +563,22 @@ static void monitor_qapi_event_init(void)
     qmp_event_set_func_emit(monitor_qapi_event_queue);
 }
 
-void qmp_qmp_capabilities(Error **errp)
+void qmp_qmp_capabilities(bool has_capabilities,
+                          QMPCapabilityList *capabilities, Error **errp)
 {
+    bool has_async = false;
+
+    if (has_capabilities) {
+        while (capabilities) {
+            if (capabilities->value == QMP_CAPABILITY_ASYNC) {
+                has_async = true;
+            }
+            capabilities = capabilities->next;
+        }
+    }
+
     cur_mon->qmp.in_command_mode = true;
+    cur_mon->qmp.client.has_async = has_async;
 }
 
 static void handle_hmp_command(Monitor *mon, const char *cmdline);
@@ -3845,8 +3858,8 @@ static QObject *get_qmp_greeting(void)
 
     qmp_marshal_query_version(NULL, &ver, NULL);
 
-    return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': []}}",
-                              ver);
+    return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': ["
+                              "'async']}}", ver);
 }
 
 static void monitor_qmp_event(void *opaque, int event)
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 14/25] monitor: add !qmp pre-conditions
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (12 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 13/25] monitor: add 'async' capability Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 15/25] monitor: suspend when running async and client has no async Marc-André Lureau
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

It's not always obvious whether a function is meant to be used only with
HMP or QMP. Add a few pre-conditions to document this aspect and
eventually catch run-time bugs.

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

diff --git a/monitor.c b/monitor.c
index 585f7b6a1a..c5c70d7e17 100644
--- a/monitor.c
+++ b/monitor.c
@@ -246,6 +246,8 @@ bool monitor_cur_is_qmp(void)
 
 void monitor_read_command(Monitor *mon, int show_prompt)
 {
+    assert(!monitor_is_qmp(mon));
+
     if (!mon->rs)
         return;
 
@@ -257,6 +259,8 @@ void monitor_read_command(Monitor *mon, int show_prompt)
 int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
                           void *opaque)
 {
+    assert(!monitor_is_qmp(mon));
+
     if (mon->rs) {
         readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
         /* prompt is printed on return from the command handler */
@@ -2548,6 +2552,8 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
     const mon_cmd_t *cmd;
     char cmdname[256];
 
+    assert(!monitor_is_qmp(mon));
+
     /* extract the command name */
     p = get_command_name(*cmdp, cmdname, sizeof(cmdname));
     if (!p)
@@ -2592,6 +2598,8 @@ static QDict *monitor_parse_arguments(Monitor *mon,
     char buf[1024];
     QDict *qdict = qdict_new();
 
+    assert(!monitor_is_qmp(mon));
+
     /* parse the parameters */
     typestr = cmd->args_type;
     for(;;) {
@@ -2971,6 +2979,8 @@ static void cmd_completion(Monitor *mon, const char *name, const char *list)
     char cmd[128];
     int len;
 
+    assert(!monitor_is_qmp(mon));
+
     p = list;
     for(;;) {
         pstart = p;
@@ -3000,6 +3010,8 @@ static void file_completion(Monitor *mon, const char *input)
     int input_path_len;
     const char *p;
 
+    assert(!monitor_is_qmp(mon));
+
     p = strrchr(input, '/');
     if (!p) {
         input_path_len = 0;
@@ -3552,6 +3564,8 @@ static void monitor_find_completion_by_table(Monitor *mon,
     const mon_cmd_t *cmd;
     BlockBackend *blk = NULL;
 
+    assert(!monitor_is_qmp(mon));
+
     if (nb_args <= 1) {
         /* command completion */
         if (nb_args == 0)
@@ -3633,6 +3647,8 @@ static void monitor_find_completion(void *opaque,
     char *args[MAX_ARGS];
     int nb_args, len;
 
+    assert(!monitor_is_qmp(mon));
+
     /* 1. parse the cmdline */
     if (parse_cmdline(cmdline, &nb_args, args) < 0) {
         return;
@@ -3801,6 +3817,8 @@ static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
 
     cur_mon = opaque;
 
+    assert(monitor_is_qmp(cur_mon));
+
     json_message_parser_feed(&cur_mon->qmp.parser, (const char *) buf, size);
 
     cur_mon = old_mon;
@@ -3812,6 +3830,7 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size)
     int i;
 
     cur_mon = opaque;
+    assert(!monitor_is_qmp(cur_mon));
 
     if (cur_mon->rs) {
         for (i = 0; i < size; i++)
@@ -3831,6 +3850,8 @@ static void monitor_command_cb(void *opaque, const char *cmdline,
 {
     Monitor *mon = opaque;
 
+    assert(!monitor_is_qmp(mon));
+
     monitor_suspend(mon);
     handle_hmp_command(mon, cmdline);
     monitor_resume(mon);
@@ -3838,6 +3859,8 @@ static void monitor_command_cb(void *opaque, const char *cmdline,
 
 int monitor_suspend(Monitor *mon)
 {
+    assert(!monitor_is_qmp(mon));
+
     if (!mon->rs)
         return -ENOTTY;
     mon->suspend_cnt++;
@@ -3846,6 +3869,8 @@ int monitor_suspend(Monitor *mon)
 
 void monitor_resume(Monitor *mon)
 {
+    assert(!monitor_is_qmp(mon));
+
     if (!mon->rs)
         return;
     if (--mon->suspend_cnt == 0)
@@ -3867,6 +3892,8 @@ static void monitor_qmp_event(void *opaque, int event)
     QObject *data;
     Monitor *mon = opaque;
 
+    assert(monitor_is_qmp(mon));
+
     switch (event) {
     case CHR_EVENT_OPENED:
         qmp_client_init(&mon->qmp.client, qmp_dispatch_return);
@@ -3890,6 +3917,8 @@ static void monitor_event(void *opaque, int event)
 {
     Monitor *mon = opaque;
 
+    assert(!monitor_is_qmp(mon));
+
     switch (event) {
     case CHR_EVENT_MUX_IN:
         qemu_mutex_lock(&mon->out_lock);
@@ -3962,15 +3991,23 @@ static void sortcmdlist(void)
 static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
                                                        const char *fmt, ...)
 {
+    Monitor *mon = opaque;
     va_list ap;
+
+    assert(!monitor_is_qmp(mon));
+
     va_start(ap, fmt);
-    monitor_vprintf(opaque, fmt, ap);
+    monitor_vprintf(mon, fmt, ap);
     va_end(ap);
 }
 
 static void monitor_readline_flush(void *opaque)
 {
-    monitor_flush(opaque);
+    Monitor *mon = opaque;
+
+    assert(!monitor_is_qmp(mon));
+
+    monitor_flush(mon);
 }
 
 /*
@@ -4059,6 +4096,8 @@ static void bdrv_password_cb(void *opaque, const char *password,
     int ret = 0;
     Error *local_err = NULL;
 
+    assert(!monitor_is_qmp(mon));
+
     bdrv_add_key(bs, password, &local_err);
     if (local_err) {
         error_report_err(local_err);
@@ -4076,6 +4115,8 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
 {
     int err;
 
+    assert(!monitor_is_qmp(mon));
+
     monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
                    bdrv_get_encrypted_filename(bs));
 
@@ -4097,6 +4138,8 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
     Error *err = NULL;
     BlockBackend *blk;
 
+    assert(!monitor_is_qmp(mon));
+
     blk = blk_by_name(device);
     if (!blk) {
         monitor_printf(mon, "Device not found %s\n", device);
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 15/25] monitor: suspend when running async and client has no async
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (13 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 14/25] monitor: add !qmp pre-conditions Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 16/25] qmp: update qmp-spec about async capability Marc-André Lureau
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

When the client doesn't support 'async' capability, let's suspend the
monitor until the on-going async command completes. That way, the client
will be able to use -async commands, but will get only in order
reply: (t won't be able to do concurrent commands. In this case, the
'id' field isn't mandatory.

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

diff --git a/monitor.c b/monitor.c
index c5c70d7e17..3ff32c000c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -165,6 +165,7 @@ typedef struct {
      * mode.
      */
     bool in_command_mode;       /* are we in command mode? */
+    QObject *suspended;
     QmpClient client;
 } MonitorQMP;
 
@@ -3675,9 +3676,10 @@ static int monitor_can_read(void *opaque)
 {
     Monitor *mon = opaque;
 
-    return (mon->suspend_cnt == 0) ? 1 : 0;
+    return (mon->suspend_cnt == 0 && !mon->qmp.suspended) ? 1 : 0;
 }
 
+
 static bool invalid_qmp_mode(const Monitor *mon, const char *cmd,
                              Error **errp)
 {
@@ -3754,11 +3756,33 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
     return input_dict;
 }
 
+static void monitor_qmp_suspend(Monitor *mon, QObject *req)
+{
+    assert(monitor_is_qmp(mon));
+    assert(!mon->qmp.suspended);
+
+    qobject_incref(req);
+    mon->qmp.suspended = req;
+}
+
+static void monitor_qmp_resume(Monitor *mon)
+{
+    assert(monitor_is_qmp(mon));
+    assert(mon->qmp.suspended);
+
+    qobject_decref(mon->qmp.suspended);
+    mon->qmp.suspended = NULL;
+}
+
 static void qmp_dispatch_return(QmpClient *client, QObject *rsp)
 {
     Monitor *mon = container_of(client, Monitor, qmp.client);
 
     monitor_json_emitter(mon, rsp);
+
+    if (mon->qmp.suspended) {
+        monitor_qmp_resume(mon);
+    }
 }
 
 static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
@@ -3797,6 +3821,12 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     }
 
     qmp_dispatch(&mon->qmp.client, req, rqdict);
+
+    /* suspend if the command is on-going and client doesn't support async */
+    if (!QLIST_EMPTY(&mon->qmp.client.pending) && !mon->qmp.client.has_async) {
+        monitor_qmp_suspend(mon, req);
+    }
+
     qobject_decref(req);
     return;
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 76c7402ac8..5bf4b1b520 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -109,7 +109,8 @@ static QObject *do_qmp_dispatch(QObject *request, QmpReturn *qret, Error **errp)
         }
         break;
     case QCT_ASYNC:
-        if (!qdict_haskey(qret->rsp, "id")) {
+        if (qret->client->has_async &&
+            !qdict_haskey(qret->rsp, "id")) {
             error_setg(errp, "An async command requires an 'id'");
             break;
         }
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 16/25] qmp: update qmp-spec about async capability
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (14 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 15/25] monitor: suspend when running async and client has no async Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 17/25] qtest: add qtest-timeout Marc-André Lureau
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 docs/qmp-spec.txt | 48 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 7 deletions(-)

diff --git a/docs/qmp-spec.txt b/docs/qmp-spec.txt
index f8b5356015..b45c0700b6 100644
--- a/docs/qmp-spec.txt
+++ b/docs/qmp-spec.txt
@@ -83,9 +83,41 @@ The greeting message format is:
 2.2.1 Capabilities
 ------------------
 
-As of the date this document was last revised, no server or client
-capability strings have been defined.
+The "capabilities" member of the greeting message and qmp_capabilities
+is a json-array of json-string of the following values:
 
+- "async"
+
+This capability indicates asynchronous commands support.
+
+An async command is a regular client message request with the "id"
+member mandatory (see 2.3), but the reply may be delivered
+asynchronously and out of order by the server if the client supports
+it too.
+
+If both the server and the client have the "async" capability, the
+client can make requests while previous async requests are being
+processed.
+
+If the client doesn't have the "async" capability, it may still call
+an async command, and make multiple outstanding calls. In this case,
+the commands are processed in order, so the replies will also be in
+order (this is sometime called 'pipelining'). The "id" member isn't
+mandatory in this case.
+
+The client should match the replies with the "id" member associated
+with the requests.
+
+When a client is disconnected, the pending commands are not
+necessarily canceled. But the future clients will not get replies from
+commands they didn't make (they might, however, receive side-effects
+events).
+
+Note that without "async" support, a client may still receive
+asynchronous messages (or events) from the server between the time a
+request is handled by the server and the reply is received. It must
+thus be prepared to handle dispatching both events and reply after
+sending a request.
 
 2.3 Issuing Commands
 --------------------
@@ -102,10 +134,11 @@ The format for command execution is:
   required. Each command documents what contents will be considered
   valid when handling the json-argument
 - The "id" member is a transaction identification associated with the
-  command execution, it is optional and will be part of the response if
-  provided. The "id" member can be any json-value, although most
+  command execution and will be part of the response if provided.
+  If "async" is negotiated (see 2.2.1), it is mandatory, optional
+  otherwise. The "id" member can be any json-value, although most
   clients merely use a json-number incremented for each successive
-  command
+  command.
 
 2.4 Commands Responses
 ----------------------
@@ -202,11 +235,12 @@ This section provides some examples of real QMP usage, in all of them
 -------------------
 
 S: { "QMP": { "version": { "qemu": { "micro": 50, "minor": 6, "major": 1 },
-     "package": ""}, "capabilities": []}}
+     "package": ""}, "capabilities": [ "async" ]}}
 
 3.2 Client QMP negotiation
 --------------------------
-C: { "execute": "qmp_capabilities" }
+C: { "execute": "qmp_capabilities",
+     "arguments": { "capabilities": [ "async" ] } }
 S: { "return": {}}
 
 3.3 Simple 'stop' execution
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 17/25] qtest: add qtest-timeout
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (15 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 16/25] qmp: update qmp-spec about async capability Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 18/25] qtest: add qtest_init_qmp_caps() Marc-André Lureau
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

This command allows to test async behavior. It is only registered when
qtest is enabled. See the schema documentation for more details.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json | 22 ++++++++++++++++++++++
 qtest.c          | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/qapi-schema.json b/qapi-schema.json
index 8366206415..42b2c645c5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -6033,3 +6033,25 @@
 #
 ##
 { 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
+
+##
+# @qtest-timeout:
+#
+# @duration: the time before timeout expires (in seconds)
+#
+# Test command that replies after @duration seconds.
+#
+# Example:
+#
+# -> { "execute": "qtest-timeout",
+#      "arguments": { "duration": 5 } }
+# ... after 5s
+# <- { "return": {} }
+#
+# Note: this command is only available with a qtest machine
+#
+# Since: 2.9
+##
+{ 'command': 'qtest-timeout',
+  'data': {'duration': 'int'},
+  'gen': false } # so we can can register it manually when qtest is enabled
diff --git a/qtest.c b/qtest.c
index bd9d417812..9477ad64e7 100644
--- a/qtest.c
+++ b/qtest.c
@@ -31,6 +31,8 @@
 #ifdef TARGET_PPC64
 #include "hw/ppc/spapr_rtas.h"
 #endif
+#include "qapi/qmp/dispatch.h"
+#include "qapi/qobject-input-visitor.h"
 
 #define MAX_IRQ 256
 
@@ -658,6 +660,49 @@ static void qtest_event(void *opaque, int event)
     }
 }
 
+static gboolean qtest_timeout_cb(void *data)
+{
+    QmpReturn *qret = data;
+
+    qmp_return(qret, NULL);
+
+    return FALSE;
+}
+
+static void qmp_qtest_timeout(QDict *args, QmpReturn *qret)
+{
+    Error *err = NULL;
+    Visitor *v;
+    int64_t duration = 0;
+
+    v = qobject_input_visitor_new(QOBJECT(args), true);
+    visit_start_struct(v, NULL, NULL, 0, &err);
+    if (err) {
+        goto out;
+    }
+
+    visit_type_int(v, "duration", &duration, &err);
+    if (!err) {
+        visit_check_struct(v, &err);
+    }
+    visit_end_struct(v, NULL);
+    if (err) {
+        goto out;
+    }
+
+    if (duration <= 0) {
+        qmp_return(qret, NULL);
+    } else {
+        g_timeout_add_seconds(duration, qtest_timeout_cb, qret);
+    }
+
+out:
+    if (err) {
+        qmp_return_error(qret, err);
+    }
+    visit_free(v);
+}
+
 static int qtest_init_accel(MachineState *ms)
 {
     QemuOpts *opts = qemu_opts_create(qemu_find_opts("icount"), NULL, 0,
@@ -665,6 +710,9 @@ static int qtest_init_accel(MachineState *ms)
     qemu_opt_set(opts, "shift", "0", &error_abort);
     configure_icount(opts, &error_abort);
     qemu_opts_del(opts);
+
+    qmp_register_async_command("qtest-timeout", qmp_qtest_timeout,
+                               QCO_NO_OPTIONS);
     return 0;
 }
 
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 18/25] qtest: add qtest_init_qmp_caps()
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (16 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 17/25] qtest: add qtest-timeout Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 19/25] tests: add tests for async and non-async clients Marc-André Lureau
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Add a function to specify the qmp capabilities content.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/libqtest.h |  9 +++++++++
 tests/libqtest.c | 13 +++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/tests/libqtest.h b/tests/libqtest.h
index 90f182e1d8..e7ab509d1a 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -32,6 +32,15 @@ extern QTestState *global_qtest;
 QTestState *qtest_init(const char *extra_args);
 
 /**
+ * qtest_init_qmp_caps:
+ * @extra_args: other arguments to pass to QEMU.
+ * @qmp_caps: qmp capabilities (ex: "'cap1', 'cap2'")
+ *
+ * Returns: #QTestState instance.
+ */
+QTestState *qtest_init_qmp_caps(const char *extra_args, const char *qmp_caps);
+
+/**
  * qtest_quit:
  * @s: #QTestState instance to operate on.
  *
diff --git a/tests/libqtest.c b/tests/libqtest.c
index d8fba6647a..eb4a0c12c0 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -149,7 +149,7 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data)
     g_hook_prepend(&abrt_hooks, hook);
 }
 
-QTestState *qtest_init(const char *extra_args)
+QTestState *qtest_init_qmp_caps(const char *extra_args, const char *qmp_caps)
 {
     QTestState *s;
     int sock, qmpsock, i;
@@ -206,7 +206,11 @@ QTestState *qtest_init(const char *extra_args)
 
     /* Read the QMP greeting and then do the handshake */
     qtest_qmp_discard_response(s, "");
-    qtest_qmp_discard_response(s, "{ 'execute': 'qmp_capabilities' }");
+    command = g_strdup_printf(
+        "{ 'execute': 'qmp_capabilities',"
+        " 'arguments': {'capabilities': [%s]}}", qmp_caps);
+    qtest_qmp_discard_response(s, command);
+    g_free(command);
 
     if (getenv("QTEST_STOP")) {
         kill(s->qemu_pid, SIGSTOP);
@@ -219,6 +223,11 @@ QTestState *qtest_init(const char *extra_args)
     return s;
 }
 
+QTestState *qtest_init(const char *extra_args)
+{
+    return qtest_init_qmp_caps(extra_args, "");
+}
+
 void qtest_quit(QTestState *s)
 {
     qtest_instances = g_list_remove(qtest_instances, s);
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 19/25] tests: add tests for async and non-async clients
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (17 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 18/25] qtest: add qtest_init_qmp_caps() Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 20/25] qapi: improve 'screendump' documentation Marc-André Lureau
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Add two tests to check async and non-async client behaviour:
- an async client can see out of order replies
- an non-async client has commands processed in order

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

diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 480ff28339..f383d5d6f6 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -58,6 +58,61 @@ static void test_qom_set_without_value(void)
     QDECREF(ret);
 }
 
+static void test_no_async(void)
+{
+    QDict *ret;
+    int64_t id;
+
+    /* check that only one async command is being processed */
+    qmp_async("{'execute': 'qtest-timeout', 'id': 42, "
+              " 'arguments': { 'duration': 1 } }");
+    qmp_async("{'execute': 'qtest-timeout', 'id': 43, "
+              " 'arguments': { 'duration': 0 } }");
+
+    /* check that the second command didn't execute immediately */
+    ret = qtest_qmp_receive(global_qtest);
+    g_assert_nonnull(ret);
+    id = qdict_get_try_int(ret, "id", -1);
+    g_assert_cmpint(id, ==, 42);
+    QDECREF(ret);
+
+    /* check that the second command executes after */
+    ret = qtest_qmp_receive(global_qtest);
+    g_assert_nonnull(ret);
+    id = qdict_get_try_int(ret, "id", -1);
+    g_assert_cmpint(id, ==, 43);
+    QDECREF(ret);
+}
+
+static void test_async(void)
+{
+    QDict *ret;
+    int64_t id;
+    QTestState *qtest;
+
+    qtest = qtest_init_qmp_caps("-machine none", "'async'");
+
+    /* check that async are concurrent */
+    qtest_async_qmp(qtest, "{'execute': 'qtest-timeout', 'id': 42, "
+              " 'arguments': { 'duration': 1 } }");
+    qtest_async_qmp(qtest, "{'execute': 'qtest-timeout', 'id': 43, "
+              " 'arguments': { 'duration': 0 } }");
+
+    ret = qtest_qmp_receive(qtest);
+    g_assert_nonnull(ret);
+    id = qdict_get_try_int(ret, "id", -1);
+    g_assert_cmpint(id, ==, 43);
+    QDECREF(ret);
+
+    ret = qtest_qmp_receive(qtest);
+    g_assert_nonnull(ret);
+    id = qdict_get_try_int(ret, "id", -1);
+    g_assert_cmpint(id, ==, 42);
+    QDECREF(ret);
+
+    qtest_quit(qtest);
+}
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -70,6 +125,10 @@ int main(int argc, char **argv)
                    test_object_add_without_props);
     qtest_add_func("/qemu-qmp/qom-set-without-value",
                    test_qom_set_without_value);
+    qtest_add_func("/qemu-qmp/no-async",
+                   test_no_async);
+    qtest_add_func("/qemu-qmp/async",
+                   test_async);
 
     ret = g_test_run();
 
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 20/25] qapi: improve 'screendump' documentation
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (18 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 19/25] tests: add tests for async and non-async clients Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 21/25] console: graphic_hw_update return true if async Marc-André Lureau
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

The command dumps the console 0, and it doesn't have to be VGA.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 42b2c645c5..2e7c96c122 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4680,7 +4680,7 @@
 ##
 # @screendump:
 #
-# Write a PPM of the VGA screen to a file.
+# Write a PPM of the first console to a file.
 #
 # @filename: the path of a new PPM file to store the image
 #
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 21/25] console: graphic_hw_update return true if async
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (19 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 20/25] qapi: improve 'screendump' documentation Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 22/25] console: add graphic_hw_update_done() Marc-André Lureau
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, 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 d2d49dd933..7ac31fc77d 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -167,7 +167,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 b59e7b8c15..9dd53c1a0f 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -365,6 +365,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);
@@ -378,7 +379,7 @@ void graphic_console_set_hwops(QemuConsole *con,
                                const GraphicHwOps *hw_ops,
                                void *opaque);
 
-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 9ad9d9e0f5..50a019162f 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 62d0c80dcf..025bd48d6f 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -134,7 +134,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, ...)
 {
@@ -1126,7 +1126,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)
@@ -1841,11 +1841,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 b9575f2ee5..9131e45b36 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -254,14 +254,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.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 22/25] console: add graphic_hw_update_done()
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (20 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 21/25] console: graphic_hw_update return true if async Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 23/25] console: make screendump async Marc-André Lureau
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, 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 9dd53c1a0f..e2d4f0df0d 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -380,6 +380,7 @@ void graphic_console_set_hwops(QemuConsole *con,
                                void *opaque);
 
 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 50a019162f..8341f583a2 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 9131e45b36..46ad6abd94 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -254,6 +254,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.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 23/25] console: make screendump async
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (21 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 22/25] console: add graphic_hw_update_done() Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-19  8:20   ` Gerd Hoffmann
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 24/25] qtest: add /qemu-qmp/screendump test Marc-André Lureau
                   ` (5 subsequent siblings)
  28 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Make screendump async to provide correct screendumps.

HMP doesn't have async support, so it has to remain sync 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-schema.json     |  5 +++-
 include/ui/console.h |  1 +
 hmp.c                |  2 +-
 ui/console.c         | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 2e7c96c122..2af8661357 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4686,6 +4686,9 @@
 #
 # Returns: Nothing on success
 #
+# Note: the operation can be cancelled and the file not written if the
+# client disconnects before completion.
+#
 # Since: 0.14.0
 #
 # Example:
@@ -4695,7 +4698,7 @@
 # <- { "return": {} }
 #
 ##
-{ 'command': 'screendump', 'data': {'filename': 'str'} }
+{ 'command': 'screendump', 'data': {'filename': 'str'}, 'async': true }
 
 
 ##
diff --git a/include/ui/console.h b/include/ui/console.h
index e2d4f0df0d..4199e7008a 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -75,6 +75,7 @@ struct MouseTransformInfo {
 };
 
 void hmp_mouse_set(Monitor *mon, const QDict *qdict);
+void hmp_screendump_sync(const char *filename, 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 8522efea26..6586247a31 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1917,7 +1917,7 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
     const char *filename = qdict_get_str(qdict, "filename");
     Error *err = NULL;
 
-    qmp_screendump(filename, &err);
+    hmp_screendump_sync(filename, &err);
     hmp_handle_error(mon, &err);
 }
 
diff --git a/ui/console.c b/ui/console.c
index 46ad6abd94..199296525c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -114,6 +114,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;
 
@@ -163,6 +169,8 @@ struct QemuConsole {
     QEMUFIFO out_fifo;
     uint8_t out_fifo_buf[16];
     QEMUTimer *kbd_timer;
+
+    QLIST_HEAD(, qmp_screendump) qmp_screendumps;
 };
 
 struct DisplayState {
@@ -188,6 +196,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)
 {
@@ -254,8 +264,39 @@ 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;
+
+    if (qmp_return_is_cancelled(ret)) {
+        return;
+    }
+
+    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);
+    }
+}
+
 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)
@@ -356,7 +397,8 @@ write_err:
     goto out;
 }
 
-void qmp_screendump(const char *filename, Error **errp)
+/* this sync screendump may produce outdated dumps: use qmp instead */
+void hmp_screendump_sync(const char *filename, Error **errp)
 {
     QemuConsole *con = qemu_console_lookup_by_index(0);
     DisplaySurface *surface;
@@ -371,6 +413,29 @@ void qmp_screendump(const char *filename, Error **errp)
     ppm_save(filename, surface, errp);
 }
 
+void qmp_screendump(const char *filename, QmpReturn *qret)
+{
+    QemuConsole *con = qemu_console_lookup_by_index(0);
+    bool async;
+    Error *err = NULL;
+
+    if (con == NULL) {
+        error_setg(&err, "There is no QemuConsole I can screendump from.");
+        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) {
@@ -1248,6 +1313,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.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 24/25] qtest: add /qemu-qmp/screendump test
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (22 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 23/25] console: make screendump async Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 25/25] qmp: move json-message-parser and check to QmpClient Marc-André Lureau
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Check that screendump works with and without client async support.

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

diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index f383d5d6f6..22b7315ca7 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -113,6 +113,57 @@ static void test_async(void)
     qtest_quit(qtest);
 }
 
+static void test_screendump(void)
+{
+    QDict *ret;
+    QTestState *qtest;
+    gchar *fname = NULL;
+    int64_t id;
+    int fd;
+    char *buf = NULL;
+    gsize len = 0;
+
+    fd = g_file_open_tmp("qemu-test-screendump.XXXXXX", &fname, NULL);
+    g_assert(fd >= 0);
+    g_assert_nonnull(fname);
+
+    /* without async */
+    qtest = qtest_init("-machine none");
+    qtest_async_qmp(qtest, "{'execute': 'screendump',"
+                    " 'arguments': { 'filename': %s } }", fname);
+
+    ret = qtest_qmp_receive(qtest);
+    g_assert_nonnull(ret);
+    QDECREF(ret);
+    qtest_quit(qtest);
+
+    g_file_get_contents(fname, &buf, &len, NULL);
+    g_assert_cmpint(len, >, 0);
+    g_assert_nonnull(buf);
+    g_free(buf);
+
+    /* with async */
+    qtest = qtest_init_qmp_caps("-machine none", "'async'");
+    qtest_async_qmp(qtest, "{'execute': 'screendump', 'id': 42,"
+                    " 'arguments': { 'filename': %s } }", fname);
+
+    ret = qtest_qmp_receive(qtest);
+    id = qdict_get_try_int(ret, "id", -1);
+    g_assert_cmpint(id, ==, 42);
+    g_assert_nonnull(ret);
+    QDECREF(ret);
+    qtest_quit(qtest);
+
+    g_file_get_contents(fname, &buf, &len, NULL);
+    g_assert_cmpint(len, >, 0);
+    g_assert_nonnull(buf);
+    g_free(buf);
+
+    close(fd);
+    unlink(fname);
+    g_free(fname);
+}
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -129,6 +180,8 @@ int main(int argc, char **argv)
                    test_no_async);
     qtest_add_func("/qemu-qmp/async",
                    test_async);
+    qtest_add_func("/qemu-qmp/screendump",
+                   test_screendump);
 
     ret = g_test_run();
 
-- 
2.11.0.295.gd7dffce1c

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

* [Qemu-devel] [PATCH v2 25/25] qmp: move json-message-parser and check to QmpClient
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (23 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 24/25] qtest: add /qemu-qmp/screendump test Marc-André Lureau
@ 2017-01-18 16:03 ` Marc-André Lureau
  2017-01-18 17:35 ` [Qemu-devel] [PATCH v2 00/25] qmp: add async command type no-reply
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, berrange, kraxel, armbru, Marc-André Lureau

Clean up qmp_dispatch usage to have consistant checks between qga &
qemu, and simplify QmpClient/parser_feed usage.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h |  13 +++-
 monitor.c                   | 140 ++++++++------------------------------------
 qapi/qmp-dispatch.c         | 124 ++++++++++++++++++++++++++++++++++++++-
 qga/main.c                  |  61 +------------------
 qobject/json-lexer.c        |   4 +-
 tests/test-qmp-commands.c   |  12 ++--
 6 files changed, 172 insertions(+), 182 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 4dd6de5ab2..0a545935d5 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -16,9 +16,12 @@
 
 #include "qapi/qmp/qobject.h"
 #include "qapi/qmp/qdict.h"
+#include "qapi/qmp/json-streamer.h"
 
 typedef struct QmpClient QmpClient;
 
+typedef bool (QmpPreDispatch) (QmpClient *client, QObject *rsp, Error **err);
+typedef bool (QmpPostDispatch) (QmpClient *client, QObject *rsp, Error **err);
 typedef void (QmpDispatchReturn) (QmpClient *client, QObject *rsp);
 
 typedef struct QmpReturn {
@@ -29,6 +32,9 @@ typedef struct QmpReturn {
 } QmpReturn;
 
 struct QmpClient {
+    JSONMessageParser parser;
+    QmpPreDispatch *pre_dispatch_cb;
+    QmpPostDispatch *post_dispatch_cb;
     QmpDispatchReturn *return_cb;
 
     QLIST_HEAD(, QmpReturn) pending;
@@ -68,8 +74,13 @@ void qmp_register_async_command(const char *name, QmpCommandFuncAsync *fn,
                                 QmpCommandOptions options);
 void qmp_unregister_command(const char *name);
 QmpCommand *qmp_find_command(const char *name);
-void qmp_client_init(QmpClient *client, QmpDispatchReturn *return_cb);
+void qmp_client_init(QmpClient *client,
+                     QmpPreDispatch *pre_dispatch_cb,
+                     QmpPostDispatch *post_dispatch_cb,
+                     QmpDispatchReturn *return_cb);
 void qmp_client_destroy(QmpClient *client);
+void qmp_client_feed(QmpClient *client, const char *buffer, size_t size);
+
 void qmp_dispatch(QmpClient *client, QObject *request, QDict *rsp);
 void qmp_disable_command(const char *name);
 void qmp_enable_command(const char *name);
diff --git a/monitor.c b/monitor.c
index 3ff32c000c..f763da462d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -56,7 +56,6 @@
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/types.h"
 #include "qapi/qmp/qjson.h"
-#include "qapi/qmp/json-streamer.h"
 #include "qapi/qmp/json-parser.h"
 #include "qom/object_interfaces.h"
 #include "trace.h"
@@ -158,7 +157,6 @@ struct MonFdset {
 };
 
 typedef struct {
-    JSONMessageParser parser;
     /*
      * When a client connects, we're in capabilities negotiation mode.
      * When command qmp_capabilities succeeds, we go into command
@@ -600,9 +598,6 @@ static void monitor_data_init(Monitor *mon)
 static void monitor_data_destroy(Monitor *mon)
 {
     qemu_chr_fe_deinit(&mon->chr);
-    if (monitor_is_qmp(mon)) {
-        json_message_parser_destroy(&mon->qmp.parser);
-    }
     qmp_client_destroy(&mon->qmp.client);
     g_free(mon->rs);
     QDECREF(mon->outbuf);
@@ -3700,62 +3695,6 @@ static bool invalid_qmp_mode(const Monitor *mon, const char *cmd,
     return false;
 }
 
-/*
- * Input object checking rules
- *
- * 1. Input object must be a dict
- * 2. The "execute" key must exist
- * 3. The "execute" key must be a string
- * 4. If the "arguments" key exists, it must be a dict
- * 5. If the "id" key exists, it can be anything (ie. json-value)
- * 6. Any argument not listed above is considered invalid
- */
-static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
-{
-    const QDictEntry *ent;
-    int has_exec_key = 0;
-    QDict *input_dict;
-
-    if (qobject_type(input_obj) != QTYPE_QDICT) {
-        error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "object");
-        return NULL;
-    }
-
-    input_dict = qobject_to_qdict(input_obj);
-
-    for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
-        const char *arg_name = qdict_entry_key(ent);
-        const QObject *arg_obj = qdict_entry_value(ent);
-
-        if (!strcmp(arg_name, "execute")) {
-            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
-                error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
-                           "execute", "string");
-                return NULL;
-            }
-            has_exec_key = 1;
-        } else if (!strcmp(arg_name, "arguments")) {
-            if (qobject_type(arg_obj) != QTYPE_QDICT) {
-                error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
-                           "arguments", "object");
-                return NULL;
-            }
-        } else if (!strcmp(arg_name, "id")) {
-            /* Any string is acceptable as "id", so nothing to check */
-        } else {
-            error_setg(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
-            return NULL;
-        }
-    }
-
-    if (!has_exec_key) {
-        error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
-        return NULL;
-    }
-
-    return input_dict;
-}
-
 static void monitor_qmp_suspend(Monitor *mon, QObject *req)
 {
     assert(monitor_is_qmp(mon));
@@ -3774,71 +3713,42 @@ static void monitor_qmp_resume(Monitor *mon)
     mon->qmp.suspended = NULL;
 }
 
-static void qmp_dispatch_return(QmpClient *client, QObject *rsp)
+static bool qmp_pre_dispatch(QmpClient *client, QObject *req, Error **errp)
 {
     Monitor *mon = container_of(client, Monitor, qmp.client);
+    QDict *qdict = qobject_to_qdict(req);
+    const char *cmd_name = qdict_get_str(qdict, "execute");
 
-    monitor_json_emitter(mon, rsp);
+    trace_handle_qmp_command(mon, cmd_name);
 
-    if (mon->qmp.suspended) {
-        monitor_qmp_resume(mon);
+    if (invalid_qmp_mode(mon, cmd_name, errp)) {
+        return false;
     }
+
+    return true;
 }
 
-static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
+static bool qmp_post_dispatch(QmpClient *client, QObject *req, Error **errp)
 {
-    QObject *req, *id = NULL;
-    QDict *qdict, *rqdict = qdict_new();
-    const char *cmd_name;
-    Monitor *mon = cur_mon;
-    Error *err = NULL;
-
-    req = json_parser_parse_err(tokens, NULL, &err);
-    if (err || !req || qobject_type(req) != QTYPE_QDICT) {
-        if (!err) {
-            error_setg(&err, QERR_JSON_PARSING);
-        }
-        goto err_out;
-    }
-
-    qdict = qmp_check_input_obj(req, &err);
-    if (!qdict) {
-        goto err_out;
-    }
-
-    id = qdict_get(qdict, "id");
-    if (id) {
-        qobject_incref(id);
-        qdict_del(qdict, "id");
-        qdict_put_obj(rqdict, "id", id);
-    }
-
-    cmd_name = qdict_get_str(qdict, "execute");
-    trace_handle_qmp_command(mon, cmd_name);
-
-    if (invalid_qmp_mode(mon, cmd_name, &err)) {
-        goto err_out;
-    }
-
-    qmp_dispatch(&mon->qmp.client, req, rqdict);
+    Monitor *mon = container_of(client, Monitor, qmp.client);
 
     /* suspend if the command is on-going and client doesn't support async */
     if (!QLIST_EMPTY(&mon->qmp.client.pending) && !mon->qmp.client.has_async) {
         monitor_qmp_suspend(mon, req);
     }
 
-    qobject_decref(req);
-    return;
+    return true;
+}
 
-err_out:
-    if (err) {
-        qdict_put_obj(rqdict, "error", qmp_build_error_object(err));
-        error_free(err);
-        monitor_json_emitter(mon, QOBJECT(rqdict));
-    }
+static void qmp_dispatch_return(QmpClient *client, QObject *rsp)
+{
+    Monitor *mon = container_of(client, Monitor, qmp.client);
+
+    monitor_json_emitter(mon, rsp);
 
-    QDECREF(rqdict);
-    qobject_decref(req);
+    if (mon->qmp.suspended) {
+        monitor_qmp_resume(mon);
+    }
 }
 
 static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
@@ -3849,7 +3759,7 @@ static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
 
     assert(monitor_is_qmp(cur_mon));
 
-    json_message_parser_feed(&cur_mon->qmp.parser, (const char *) buf, size);
+    qmp_client_feed(&cur_mon->qmp.client, (const char *)buf, size);
 
     cur_mon = old_mon;
 }
@@ -3926,7 +3836,10 @@ static void monitor_qmp_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_OPENED:
-        qmp_client_init(&mon->qmp.client, qmp_dispatch_return);
+        qmp_client_init(&mon->qmp.client,
+                        qmp_pre_dispatch,
+                        qmp_post_dispatch,
+                        qmp_dispatch_return);
         mon->qmp.in_command_mode = false;
         data = get_qmp_greeting();
         monitor_json_emitter(mon, data);
@@ -3934,8 +3847,6 @@ static void monitor_qmp_event(void *opaque, int event)
         mon_refcount++;
         break;
     case CHR_EVENT_CLOSED:
-        json_message_parser_destroy(&mon->qmp.parser);
-        json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
         qmp_client_destroy(&mon->qmp.client);
         mon_refcount--;
         monitor_fdsets_cleanup();
@@ -4094,7 +4005,6 @@ void monitor_init(CharDriverState *chr, int flags)
         qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
                                  monitor_qmp_event, mon, NULL, true);
         qemu_chr_fe_set_echo(&mon->chr, true);
-        json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
     } else {
         qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
                                  monitor_event, mon, NULL, true);
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 5bf4b1b520..9c5cfc6b5a 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -20,6 +20,12 @@
 #include "qapi-types.h"
 #include "qapi/qmp/qerror.h"
 
+void qmp_client_feed(QmpClient *client,
+                     const char *buffer, size_t size)
+{
+    json_message_parser_feed(&client->parser, buffer, size);
+}
+
 static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
 {
     const QDictEntry *ent;
@@ -180,10 +186,125 @@ bool qmp_return_is_cancelled(QmpReturn *qret)
     return false;
 }
 
-void qmp_client_init(QmpClient *client, QmpDispatchReturn *return_cb)
+/*
+ * Input object checking rules
+ *
+ * 1. Input object must be a dict
+ * 2. The "execute" key must exist
+ * 3. The "execute" key must be a string
+ * 4. If the "arguments" key exists, it must be a dict
+ * 5. If the "id" key exists, it can be anything (ie. json-value)
+ * 6. Any argument not listed above is considered invalid
+ */
+static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
+{
+    const QDictEntry *ent;
+    int has_exec_key = 0;
+    QDict *dict;
+
+    if (qobject_type(input_obj) != QTYPE_QDICT) {
+        error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "object");
+        return NULL;
+    }
+
+    dict = qobject_to_qdict(input_obj);
+
+    for (ent = qdict_first(dict); ent; ent = qdict_next(dict, ent)) {
+        const char *arg_name = qdict_entry_key(ent);
+        const QObject *arg_obj = qdict_entry_value(ent);
+
+        if (!strcmp(arg_name, "execute")) {
+            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
+                error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
+                           "execute", "string");
+                return NULL;
+            }
+            has_exec_key = 1;
+        } else if (!strcmp(arg_name, "arguments")) {
+            if (qobject_type(arg_obj) != QTYPE_QDICT) {
+                error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
+                           "arguments", "object");
+                return NULL;
+            }
+        } else if (!strcmp(arg_name, "id")) {
+            /* Any string is acceptable as "id", so nothing to check */
+        } else {
+            error_setg(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
+            return NULL;
+        }
+    }
+
+    if (!has_exec_key) {
+        error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
+        return NULL;
+    }
+
+    return dict;
+}
+
+static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
+{
+    QmpClient *client = container_of(parser, QmpClient, parser);
+    QObject *req, *id = NULL;
+    QDict *qdict, *rqdict = qdict_new();
+    Error *err = NULL;
+
+    req = json_parser_parse_err(tokens, NULL, &err);
+    if (err || !req || qobject_type(req) != QTYPE_QDICT) {
+        if (!err) {
+            error_setg(&err, QERR_JSON_PARSING);
+        }
+        goto err_out;
+    }
+
+    qdict = qmp_check_input_obj(req, &err);
+    if (!qdict) {
+        goto err_out;
+    }
+
+    id = qdict_get(qdict, "id");
+    if (id) {
+        qobject_incref(id);
+        qdict_del(qdict, "id");
+        qdict_put_obj(rqdict, "id", id);
+    }
+
+    if (client->pre_dispatch_cb &&
+        !client->pre_dispatch_cb(client, QOBJECT(qdict), &err)) {
+        goto err_out;
+    }
+
+    qmp_dispatch(client, req, rqdict);
+
+    if (client->post_dispatch_cb &&
+        !client->post_dispatch_cb(client, QOBJECT(qdict), &err)) {
+        goto err_out;
+    }
+
+    qobject_decref(req);
+    return;
+
+err_out:
+    if (err) {
+        qdict_put_obj(rqdict, "error", qmp_build_error_object(err));
+        error_free(err);
+        client->return_cb(client, QOBJECT(rqdict));
+    }
+
+    QDECREF(rqdict);
+    qobject_decref(req);
+}
+
+void qmp_client_init(QmpClient *client,
+                     QmpPreDispatch *pre_dispatch_cb,
+                     QmpPostDispatch *post_dispatch_cb,
+                     QmpDispatchReturn *return_cb)
 {
     assert(!client->return_cb);
 
+    json_message_parser_init(&client->parser, handle_qmp_command);
+    client->pre_dispatch_cb = pre_dispatch_cb;
+    client->post_dispatch_cb = post_dispatch_cb;
     client->return_cb = return_cb;
     QLIST_INIT(&client->pending);
 }
@@ -193,6 +314,7 @@ void qmp_client_destroy(QmpClient *client)
     QmpReturn *ret, *next;
 
     client->return_cb = NULL;
+    json_message_parser_destroy(&client->parser);
     /* Remove the weak references to the pending returns. The
      * dispatched function is the owner of QmpReturn, and will have to
      * qmp_return(). (it might be interesting to have a way to notify
diff --git a/qga/main.c b/qga/main.c
index a75544ed7a..d42b532cf4 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -65,7 +65,6 @@ typedef struct GAPersistentState {
 } GAPersistentState;
 
 struct GAState {
-    JSONMessageParser parser;
     GMainLoop *main_loop;
     GAChannel *channel;
     bool virtio; /* fastpath to check for virtio to deal with poll() quirks */
@@ -559,59 +558,7 @@ static void dispatch_return_cb(QmpClient *client, QObject *rsp)
     }
 }
 
-static void process_command(GAState *s, QDict *req)
-{
-    g_assert(req);
-    g_debug("processing command");
-    qmp_dispatch(&ga_state->client, QOBJECT(req), NULL);
-}
-
 /* 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;
-    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));
-        }
-        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
-        error_free(err);
-    }
-
-    /* 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 (ret < 0) {
-            g_warning("error sending error response: %s", strerror(-ret));
-        }
-    }
-
-    QDECREF(qdict);
-}
-
 /* false return signals GAChannel to close the current client connection */
 static gboolean channel_event_cb(GIOCondition condition, gpointer data)
 {
@@ -625,8 +572,8 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data)
         return false;
     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);
+        g_debug("read data, count: %" G_GSIZE_FORMAT ", data: %s", count, buf);
+        qmp_client_feed(&s->client, buf, count);
         break;
     case G_IO_STATUS_EOF:
         g_debug("received EOF");
@@ -1285,9 +1232,8 @@ static int run_agent(GAState *s, GAConfig *config)
     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);
     ga_state = s;
-    qmp_client_init(&s->client, dispatch_return_cb);
+    qmp_client_init(&s->client, NULL, NULL, dispatch_return_cb);
 #ifndef _WIN32
     if (!register_signal_handlers()) {
         g_critical("failed to register signal handlers");
@@ -1376,7 +1322,6 @@ end:
     if (s->command_state) {
         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);
diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index af4a75e05b..94f0db30df 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -382,5 +382,7 @@ 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);
+    }
 }
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 4613a9a4c8..9656fbb529 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -127,7 +127,7 @@ static void test_dispatch_cmd(void)
     QmpClient client = { 0, };
     QDict *req = qdict_new();
 
-    qmp_client_init(&client, dispatch_cmd_return);
+    qmp_client_init(&client, NULL, NULL, dispatch_cmd_return);
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
 
@@ -150,7 +150,7 @@ static void test_dispatch_cmd_failure(void)
     QDict *req = qdict_new();
     QDict *args = qdict_new();
 
-    qmp_client_init(&client, dispatch_cmd_error_return);
+    qmp_client_init(&client, NULL, NULL, dispatch_cmd_error_return);
 
     qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
 
@@ -192,7 +192,7 @@ static QObject *test_qmp_dispatch(QDict *req)
     QObject *ret;
     QmpClient client = { 0, };
 
-    qmp_client_init(&client, qmp_dispatch_return);
+    qmp_client_init(&client, NULL, NULL, qmp_dispatch_return);
     qmp_dispatch(&client, QOBJECT(req), NULL);
     qmp_client_destroy(&client);
 
@@ -258,7 +258,7 @@ static void test_dispatch_cmd_async(void)
     QDict *args = qdict_new();
 
     loop = g_main_loop_new(NULL, FALSE);
-    qmp_client_init(&client, qmp_dispatch_return);
+    qmp_client_init(&client, NULL, NULL, qmp_dispatch_return);
 
     qdict_put(args, "a", qint_from_int(99));
     qdict_put(req, "arguments", args);
@@ -287,7 +287,7 @@ static void test_dispatch_cmd_async_no_id(void)
     QDict *req = qdict_new();
     QDict *args = qdict_new();
 
-    qmp_client_init(&client, dispatch_cmd_error_return);
+    qmp_client_init(&client, NULL, NULL, dispatch_cmd_error_return);
 
     qdict_put(args, "a", qint_from_int(99));
     qdict_put(req, "arguments", args);
@@ -311,7 +311,7 @@ static void test_destroy_pending_async(void)
     int npending = 0;
 
     loop = g_main_loop_new(NULL, FALSE);
-    qmp_client_init(&client, qmp_dispatch_return);
+    qmp_client_init(&client, NULL, NULL, qmp_dispatch_return);
 
     qdict_put(args, "a", qint_from_int(99));
     qdict_put(req, "arguments", args);
-- 
2.11.0.295.gd7dffce1c

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

* Re: [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests Marc-André Lureau
@ 2017-01-18 16:14   ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-18 16:14 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, eblake, berrange, kraxel, armbru



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

Sorry, it was actually in 2.8

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  tests/qmp-test.c       | 79
>  ++++++++++++++++++++++++++++++++++++++++++++++++++
>  MAINTAINERS            |  1 +
>  tests/Makefile.include |  2 ++
>  3 files changed, 82 insertions(+)
>  create mode 100644 tests/qmp-test.c
> 
> diff --git a/tests/qmp-test.c b/tests/qmp-test.c
> new file mode 100644
> index 0000000000..480ff28339
> --- /dev/null
> +++ b/tests/qmp-test.c
> @@ -0,0 +1,79 @@
> +/*
> + * QTest testcase for QMP
> + *
> + * Copyright (c) 2016 Red Hat, Inc.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +/*
> + * This program tests QMP commands maintained with the QMP core.
> + * These are defined in qmp.c.  Tests for QMP commands defined in
> + * another subsystem should go into a test program maintained with
> + * that subsystem.
> + *
> + * TODO Actually cover the commands.  The tests we got so far only
> + * demonstrate specific bugs we've fixed.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +
> +static void test_object_add_without_props(void)
> +{
> +    QDict *ret, *error;
> +    const gchar *klass, *desc;
> +
> +    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);
> +}
> +
> +static void test_qom_set_without_value(void)
> +{
> +    QDict *ret, *error;
> +    const gchar *klass, *desc;
> +
> +    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);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    int ret;
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    qtest_start("-machine none");
> +
> +    qtest_add_func("/qemu-qmp/object-add-without-props",
> +                   test_object_add_without_props);
> +    qtest_add_func("/qemu-qmp/qom-set-without-value",
> +                   test_qom_set_without_value);
> +
> +    ret = g_test_run();
> +
> +    qtest_end();
> +
> +    return ret;
> +}
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1444b26dc0..0c94a1ce27 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1368,6 +1368,7 @@ F: qmp.c
>  F: monitor.c
>  F: docs/*qmp-*
>  F: scripts/qmp/
> +F: tests/qmp-test.c
>  T: git git://repo.or.cz/qemu/armbru.git qapi-next
>  
>  Register API
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 96f59703a1..152655d086 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -316,6 +316,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
>  check-qtest-s390x-y = tests/boot-serial-test$(EXESUF)
>  
>  check-qtest-generic-y += tests/qom-test$(EXESUF)
> +check-qtest-generic-y += tests/qmp-test$(EXESUF)
>  
>  qapi-schema += alternate-any.json
>  qapi-schema += alternate-array.json
> @@ -687,6 +688,7 @@ tests/tpci200-test$(EXESUF): tests/tpci200-test.o
>  tests/display-vga-test$(EXESUF): tests/display-vga-test.o
>  tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
>  tests/qom-test$(EXESUF): tests/qom-test.o
> +tests/qmp-test$(EXESUF): tests/qmp-test.o
>  tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-pc-obj-y)
>  tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o
>  $(libqos-pc-obj-y)
>  tests/nvme-test$(EXESUF): tests/nvme-test.o
> --
> 2.11.0.295.gd7dffce1c
> 
> 

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (24 preceding siblings ...)
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 25/25] qmp: move json-message-parser and check to QmpClient Marc-André Lureau
@ 2017-01-18 17:35 ` no-reply
  2017-01-23 10:55 ` Stefan Hajnoczi
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 61+ messages in thread
From: no-reply @ 2017-01-18 17:35 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: famz, qemu-devel, kraxel, armbru

Hi,

Your series failed automatic build test. Please find the testing commands and
their output below. If you have docker installed, you can probably reproduce it
locally.

Message-id: 20170118160332.13390-1-marcandre.lureau@redhat.com
Subject: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
Type: series

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

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
41964b5 qmp: move json-message-parser and check to QmpClient
cda70c8 qtest: add /qemu-qmp/screendump test
7f25d0c console: make screendump async
f6fd70a console: add graphic_hw_update_done()
3b4426b console: graphic_hw_update return true if async
eebbe9d qapi: improve 'screendump' documentation
296c894 tests: add tests for async and non-async clients
11f8f59 qtest: add qtest_init_qmp_caps()
9c37e95 qtest: add qtest-timeout
ee1936a qmp: update qmp-spec about async capability
772f607 monitor: suspend when running async and client has no async
7f9c73e monitor: add !qmp pre-conditions
9967230 monitor: add 'async' capability
3a484e5 tests: add dispatch async tests
8eded8c scripts: learn 'async' qapi commands
04a99cd qmp: check that async command have an 'id'
422c166 qmp: take 'id' from request
981bd6b qapi: ignore top-level 'id' field
7861275 qmp: introduce async command type
0328828 qmp: add qmp_return_is_cancelled()
8d2ff5f qmp: add QmpClient
4be5d8c qmp: use a return callback for the command reply
317c314 qmp: teach qmp_dispatch() to take a pre-filled QDict
5b8f81d tests: change /0.15/* tests to /qmp/*
d61d8f7 tests: start generic qemu-qmp tests

=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into 'dtc'...
Submodule path 'dtc': checked out '65cc4d2748a2c2e6f27f1cf39e07a5dbabd80ebf'
  BUILD   centos6
make[1]: Entering directory `/var/tmp/patchew-tester-tmp-nlrtpn_4/src'
  ARCHIVE qemu.tgz
  ARCHIVE dtc.tgz
  COPY    RUNNER
    RUN test-quick in qemu:centos6 
Packages installed:
SDL-devel-1.2.14-7.el6_7.1.x86_64
ccache-3.1.6-2.el6.x86_64
epel-release-6-8.noarch
gcc-4.4.7-17.el6.x86_64
git-1.7.1-4.el6_7.1.x86_64
glib2-devel-2.28.8-5.el6.x86_64
libfdt-devel-1.4.0-1.el6.x86_64
make-3.81-23.el6.x86_64
package g++ is not installed
pixman-devel-0.32.8-1.el6.x86_64
tar-1.23-15.el6_8.x86_64
zlib-devel-1.2.3-29.el6.x86_64

Environment variables:
PACKAGES=libfdt-devel ccache     tar git make gcc g++     zlib-devel glib2-devel SDL-devel pixman-devel     epel-release
HOSTNAME=4cb985a08678
TERM=xterm
MAKEFLAGS= -j16
HISTSIZE=1000
J=16
USER=root
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
LANG=en_US.UTF-8
TARGET_LIST=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES= dtc
DEBUG=
G_BROKEN_FILENAMES=1
CCACHE_HASHDIR=
_=/usr/bin/env

Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install
No C++ compiler available; disabling C++ specific optional code
Install prefix    /var/tmp/qemu-build/install
BIOS directory    /var/tmp/qemu-build/install/share/qemu
binary directory  /var/tmp/qemu-build/install/bin
library directory /var/tmp/qemu-build/install/lib
module directory  /var/tmp/qemu-build/install/lib/qemu
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory  /var/tmp/qemu-build/install/etc
local state directory   /var/tmp/qemu-build/install/var
Manual directory  /var/tmp/qemu-build/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /tmp/qemu-test/src
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    -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 -Wmissing-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
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
tcg debug enabled no
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
pixman            system
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
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
COLO support      yes
RDMA support      no
TCG interpreter   no
fdt support       yes
preadv support    yes
fdatasync         yes
madvise           yes
posix_madvise     yes
libcap-ng support no
vhost-net support yes
vhost-scsi support yes
vhost-vsock 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
GlusterFS support no
Archipelago support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   no
TPM passthrough   yes
QOM debugging     yes
lzo support       no
snappy support    no
bzip2 support     no
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     config-host.h
  GEN     aarch64-softmmu/config-devices.mak.tmp
  GEN     qemu-options.def
  GEN     qmp-commands.h
  GEN     qapi-types.h
  GEN     qapi-visit.h
  GEN     qapi-event.h
  GEN     qmp-introspect.h
  GEN     module_block.h
  GEN     tests/test-qapi-types.h
  GEN     tests/test-qapi-visit.h
  GEN     tests/test-qmp-commands.h
  GEN     tests/test-qapi-event.h
  GEN     tests/test-qmp-introspect.h
  GEN     trace/generated-tracers.h
  GEN     x86_64-softmmu/config-devices.mak
  GEN     aarch64-softmmu/config-devices.mak
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
  GEN     trace/generated-helpers.h
  GEN     config-all-devices.mak
  GEN     qga/qapi-generated/qga-qapi-visit.h
  CC      tests/qemu-iotests/socket_scm_helper.o
  GEN     qga/qapi-generated/qga-qapi-types.h
  GEN     qga/qapi-generated/qga-qapi-visit.c
  GEN     qga/qapi-generated/qga-qmp-commands.h
  GEN     qga/qapi-generated/qga-qapi-types.c
  GEN     qga/qapi-generated/qga-qmp-marshal.c
  GEN     qmp-introspect.c
  GEN     qapi-types.c
  GEN     qapi-visit.c
  GEN     qapi-event.c
  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-util.o
  CC      qapi/qapi-clone-visitor.o
  CC      qapi/qmp-event.o
  CC      qobject/qnull.o
  CC      qobject/qint.o
  CC      qobject/qstring.o
  CC      qobject/qdict.o
  CC      qobject/qlist.o
  CC      qobject/qfloat.o
  CC      qobject/qbool.o
  CC      qobject/qjson.o
  CC      qobject/qobject.o
  CC      qobject/json-lexer.o
  CC      qobject/json-streamer.o
  CC      qobject/json-parser.o
  GEN     trace/generated-tracers.c
  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/compatfd.o
  CC      util/event_notifier-posix.o
  CC      util/mmap-alloc.o
  CC      util/oslib-posix.o
  CC      util/qemu-thread-posix.o
  CC      util/qemu-openpty.o
  CC      util/memfd.o
  CC      util/path.o
  CC      util/envlist.o
  CC      util/module.o
  CC      util/bitmap.o
  CC      util/bitops.o
  CC      util/hbitmap.o
  CC      util/fifo8.o
  CC      util/acl.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/uri.o
  CC      util/qemu-sockets.o
  CC      util/notify.o
  CC      util/qemu-option.o
  CC      util/qemu-progress.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/qdist.o
  CC      util/qht.o
  CC      util/range.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/clock-warp.o
  CC      stubs/cpu-get-clock.o
  CC      stubs/cpu-get-icount.o
  CC      stubs/dump.o
  CC      stubs/error-printf.o
  CC      stubs/fdset-add-fd.o
  CC      stubs/fdset-find-fd.o
  CC      stubs/fdset-get-fd.o
  CC      stubs/fdset-remove-fd.o
  CC      stubs/gdbstub.o
  CC      stubs/get-fd.o
  CC      stubs/get-next-serial.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/mon-is-qmp.o
  CC      stubs/monitor-init.o
  CC      stubs/notify-event.o
  CC      stubs/qtest.o
  CC      stubs/replay.o
  CC      stubs/replay-user.o
  CC      stubs/reset.o
  CC      stubs/runstate-check.o
  CC      stubs/set-fd-handler.o
  CC      stubs/slirp.o
  CC      stubs/sysbus.o
  CC      stubs/trace-control.o
  CC      stubs/uuid.o
  CC      stubs/vm-stop.o
  CC      stubs/vmstate.o
  CC      stubs/cpus.o
  CC      stubs/kvm.o
  CC      stubs/qmp_pc_dimm_device_list.o
  CC      stubs/target-monitor-defs.o
  CC      stubs/target-get-monitor-def.o
  CC      stubs/vhost.o
  CC      stubs/iohandler.o
  CC      stubs/smbios_type_38.o
  CC      stubs/ipmi.o
  CC      stubs/pc_madt_cpu_entry.o
  CC      stubs/migration-colo.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      async.o
  CC      thread-pool.o
  CC      block.o
  CC      blockjob.o
  CC      main-loop.o
  CC      iohandler.o
  CC      aio-posix.o
  CC      qemu-timer.o
  CC      qemu-io-cmds.o
  CC      replication.o
  CC      block/raw-format.o
  CC      block/vdi.o
  CC      block/qcow.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/qed.o
  CC      block/qed-gencb.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/qapi.o
  CC      block/block-backend.o
  CC      block/snapshot.o
  CC      block/file-posix.o
  CC      block/null.o
  CC      block/mirror.o
  CC      block/commit.o
  CC      block/io.o
  CC      block/throttle-groups.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/crypto.o
  CC      nbd/server.o
  CC      nbd/client.o
  CC      nbd/common.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-buffer.o
  CC      io/channel.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/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      qemu-bridge-helper.o
  CC      blockdev.o
  CC      iothread.o
  CC      blockdev-nbd.o
  CC      qdev-monitor.o
  CC      device-hotplug.o
  CC      os-posix.o
  CC      qemu-char.o
  CC      page_cache.o
  CC      accel.o
  CC      bt-host.o
  CC      bt-vhci.o
  CC      dma-helpers.o
  CC      vl.o
  CC      tpm.o
  CC      device_tree.o
  GEN     qmp-marshal.c
  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/sdlaudio.o
  CC      audio/ossaudio.o
  CC      audio/wavcapture.o
  CC      backends/rng.o
  CC      backends/rng-egd.o
  CC      backends/rng-random.o
  CC      backends/msmouse.o
  CC      backends/testdev.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      block/stream.o
  CC      disas/arm.o
  CC      disas/i386.o
  CC      fsdev/qemu-fsdev-dummy.o
  CC      fsdev/qemu-fsdev-opts.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/acpi_interface.o
  CC      hw/acpi/bios-linker-loader.o
  CC      hw/acpi/aml-build.o
  CC      hw/acpi/ipmi.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/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/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/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/fw-path-provider.o
  CC      hw/core/hotplug.o
  CC      hw/core/irq.o
  CC      hw/core/ptimer.o
  CC      hw/core/sysbus.o
  CC      hw/core/machine.o
  CC      hw/core/null-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/platform-bus.o
  CC      hw/display/ads7846.o
  CC      hw/display/cirrus_vga.o
  CC      hw/display/pl110.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/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/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/vmmouse.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/imx_avic.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/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/debugexit.o
  CC      hw/misc/sga.o
  CC      hw/misc/pc-testdev.o
  CC      hw/misc/pci-testdev.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/allwinner_emac.o
  CC      hw/net/imx_fec.o
  CC      hw/net/cadence_gem.o
  CC      hw/net/stellaris_enet.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/nvram/eeprom93xx.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/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/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/pci-stub.o
  CC      hw/pci/pcie_port.o
  CC      hw/pcmcia/pcmcia.o
/tmp/qemu-test/src/hw/nvram/fw_cfg.c: In function ‘fw_cfg_dma_transfer’:
/tmp/qemu-test/src/hw/nvram/fw_cfg.c:329: warning: ‘read’ may be used uninitialized in this function
  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/sdhci.o
  CC      hw/smbios/smbios.o
  CC      hw/smbios/smbios_type_38.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/timer/arm_timer.o
  CC      hw/timer/arm_mptimer.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/aspeed_timer.o
  CC      hw/tpm/tpm_tis.o
  CC      hw/tpm/tpm_passthrough.o
  CC      hw/tpm/tpm_util.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.o
  CC      hw/usb/desc-msos.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-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/watchdog/watchdog.o
  CC      hw/watchdog/wdt_i6300esb.o
  CC      hw/watchdog/wdt_ib700.o
  CC      migration/migration.o
  CC      migration/socket.o
  CC      migration/fd.o
  CC      migration/exec.o
  CC      migration/tls.o
  CC      migration/colo-comm.o
  CC      migration/colo.o
  CC      migration/colo-failover.o
  CC      migration/vmstate.o
  CC      migration/qemu-file.o
  CC      migration/qemu-file-channel.o
  CC      migration/xbzrle.o
  CC      migration/postcopy-ram.o
  CC      migration/qjson.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/tap.o
  CC      net/vhost-user.o
  CC      net/tap-linux.o
  CC      net/filter.o
  CC      net/slirp.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      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
/tmp/qemu-test/src/replay/replay-internal.c: In function ‘replay_put_array’:
/tmp/qemu-test/src/replay/replay-internal.c:65: warning: ignoring return value of ‘fwrite’, declared with attribute warn_unused_result
  CC      replay/replay-net.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/dnssearch.o
  CC      slirp/dhcpv6.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
  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      ui/keymaps.o
  CC      ui/console.o
  CC      ui/cursor.o
  CC      ui/qemu-pixman.o
  CC      ui/input-keymap.o
  CC      ui/input.o
  CC      ui/input-legacy.o
  CC      ui/input-linux.o
  CC      ui/sdl.o
  CC      ui/sdl_zoom.o
  CC      ui/x_keymap.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
/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      ui/vnc-auth-vencrypt.o
  CC      ui/vnc-ws.o
  CC      ui/vnc-jobs.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
  CC      qga/commands-posix.o
  BUILD   optionrom/multiboot.img
  BUILD   optionrom/linuxboot.img
  BUILD   optionrom/linuxboot_dma.img
  BUILD   optionrom/kvmvapic.img
  CC      qga/channel-posix.o
  BUILD   optionrom/linuxboot.raw
  BUILD   optionrom/multiboot.raw
  BUILD   optionrom/linuxboot_dma.raw
  SIGN    optionrom/multiboot.bin
  CC      qga/qapi-generated/qga-qapi-types.o
  BUILD   optionrom/kvmvapic.raw
  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-qmp-marshal.o
  CC      qmp-introspect.o
  CC      qapi-types.o
  CC      qapi-visit.o
  CC      qapi-event.o
  AR      libqemustub.a
  CC      qemu-img.o
  CC      qmp-marshal.o
  CC      trace/generated-tracers.o
  AR      libqemuutil.a
  LINK    qemu-ga
  LINK    ivshmem-client
  LINK    ivshmem-server
  LINK    qemu-nbd
  LINK    qemu-img
  LINK    qemu-io
  LINK    qemu-bridge-helper
  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/exec.o
  CC      x86_64-softmmu/cpu-exec-common.o
  CC      x86_64-softmmu/translate-all.o
  CC      x86_64-softmmu/cpu-exec.o
  CC      x86_64-softmmu/translate-common.o
  CC      x86_64-softmmu/tcg/tcg.o
  CC      x86_64-softmmu/tcg/tcg-op.o
  CC      x86_64-softmmu/disas.o
  CC      x86_64-softmmu/tcg/optimize.o
  CC      x86_64-softmmu/tcg/tcg-common.o
  CC      x86_64-softmmu/fpu/softfloat.o
  CC      x86_64-softmmu/tcg-runtime.o
  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      aarch64-softmmu/exec.o
  CC      aarch64-softmmu/translate-all.o
  CC      aarch64-softmmu/cpu-exec.o
  CC      aarch64-softmmu/translate-common.o
  CC      aarch64-softmmu/cpu-exec-common.o
  CC      aarch64-softmmu/tcg/tcg.o
  CC      x86_64-softmmu/balloon.o
  CC      x86_64-softmmu/ioport.o
  CC      aarch64-softmmu/tcg/tcg-op.o
  CC      aarch64-softmmu/tcg/optimize.o
  CC      x86_64-softmmu/numa.o
  CC      x86_64-softmmu/qtest.o
  CC      aarch64-softmmu/tcg/tcg-common.o
  CC      aarch64-softmmu/fpu/softfloat.o
  CC      x86_64-softmmu/bootdevice.o
  CC      x86_64-softmmu/kvm-all.o
  CC      x86_64-softmmu/memory.o
  CC      aarch64-softmmu/disas.o
  CC      aarch64-softmmu/tcg-runtime.o
  CC      x86_64-softmmu/cputlb.o
  GEN     aarch64-softmmu/gdbstub-xml.c
  CC      aarch64-softmmu/kvm-stub.o
  CC      x86_64-softmmu/memory_mapping.o
  CC      x86_64-softmmu/dump.o
  CC      aarch64-softmmu/arch_init.o
  CC      aarch64-softmmu/cpus.o
  CC      x86_64-softmmu/migration/ram.o
  CC      x86_64-softmmu/migration/savevm.o
  CC      x86_64-softmmu/xen-common-stub.o
  CC      x86_64-softmmu/xen-hvm-stub.o
  CC      x86_64-softmmu/hw/block/virtio-blk.o
  CC      x86_64-softmmu/hw/block/dataplane/virtio-blk.o
  CC      aarch64-softmmu/monitor.o
  CC      aarch64-softmmu/gdbstub.o
  CC      aarch64-softmmu/balloon.o
  CC      x86_64-softmmu/hw/char/virtio-serial-bus.o
  CC      aarch64-softmmu/ioport.o
  CC      aarch64-softmmu/numa.o
  CC      aarch64-softmmu/qtest.o
  CC      aarch64-softmmu/bootdevice.o
  CC      x86_64-softmmu/hw/core/nmi.o
  CC      aarch64-softmmu/memory.o
  CC      x86_64-softmmu/hw/core/generic-loader.o
  CC      aarch64-softmmu/cputlb.o
  CC      aarch64-softmmu/memory_mapping.o
  CC      aarch64-softmmu/dump.o
  CC      aarch64-softmmu/migration/ram.o
  CC      aarch64-softmmu/migration/savevm.o
  CC      aarch64-softmmu/xen-common-stub.o
  CC      aarch64-softmmu/xen-hvm-stub.o
  CC      aarch64-softmmu/hw/adc/stm32f2xx_adc.o
  CC      aarch64-softmmu/hw/block/virtio-blk.o
  CC      x86_64-softmmu/hw/cpu/core.o
  CC      aarch64-softmmu/hw/block/dataplane/virtio-blk.o
  CC      x86_64-softmmu/hw/display/vga.o
  CC      aarch64-softmmu/hw/char/exynos4210_uart.o
  CC      x86_64-softmmu/hw/display/virtio-gpu.o
  CC      x86_64-softmmu/hw/display/virtio-gpu-3d.o
  CC      aarch64-softmmu/hw/char/omap_uart.o
  CC      aarch64-softmmu/hw/char/digic-uart.o
  CC      aarch64-softmmu/hw/char/stm32f2xx_usart.o
  CC      aarch64-softmmu/hw/char/bcm2835_aux.o
  CC      x86_64-softmmu/hw/display/virtio-gpu-pci.o
  CC      x86_64-softmmu/hw/display/virtio-vga.o
  CC      x86_64-softmmu/hw/intc/apic.o
  CC      aarch64-softmmu/hw/char/virtio-serial-bus.o
  CC      aarch64-softmmu/hw/core/nmi.o
  CC      x86_64-softmmu/hw/intc/apic_common.o
  CC      aarch64-softmmu/hw/core/generic-loader.o
  CC      x86_64-softmmu/hw/intc/ioapic.o
  CC      aarch64-softmmu/hw/cpu/arm11mpcore.o
  CC      x86_64-softmmu/hw/isa/lpc_ich9.o
  CC      aarch64-softmmu/hw/cpu/realview_mpcore.o
  CC      aarch64-softmmu/hw/cpu/a9mpcore.o
  CC      x86_64-softmmu/hw/misc/vmport.o
  CC      x86_64-softmmu/hw/misc/pvpanic.o
  CC      x86_64-softmmu/hw/misc/ivshmem.o
  CC      aarch64-softmmu/hw/cpu/a15mpcore.o
  CC      aarch64-softmmu/hw/cpu/core.o
  CC      aarch64-softmmu/hw/display/omap_dss.o
  CC      aarch64-softmmu/hw/display/omap_lcdc.o
  CC      aarch64-softmmu/hw/display/pxa2xx_lcd.o
  CC      x86_64-softmmu/hw/misc/edu.o
  CC      x86_64-softmmu/hw/misc/hyperv_testdev.o
  CC      aarch64-softmmu/hw/display/bcm2835_fb.o
  CC      aarch64-softmmu/hw/display/vga.o
  CC      x86_64-softmmu/hw/net/virtio-net.o
  CC      aarch64-softmmu/hw/display/virtio-gpu.o
  CC      x86_64-softmmu/hw/net/vhost_net.o
  CC      aarch64-softmmu/hw/display/virtio-gpu-3d.o
  CC      aarch64-softmmu/hw/display/virtio-gpu-pci.o
  CC      x86_64-softmmu/hw/scsi/virtio-scsi.o
  CC      x86_64-softmmu/hw/scsi/virtio-scsi-dataplane.o
  CC      x86_64-softmmu/hw/scsi/vhost-scsi.o
  CC      x86_64-softmmu/hw/timer/mc146818rtc.o
  CC      aarch64-softmmu/hw/display/dpcd.o
  CC      x86_64-softmmu/hw/vfio/common.o
  CC      aarch64-softmmu/hw/display/xlnx_dp.o
  CC      aarch64-softmmu/hw/dma/xlnx_dpdma.o
  CC      x86_64-softmmu/hw/vfio/pci.o
  CC      x86_64-softmmu/hw/vfio/pci-quirks.o
  CC      aarch64-softmmu/hw/dma/omap_dma.o
  CC      aarch64-softmmu/hw/dma/soc_dma.o
  CC      x86_64-softmmu/hw/vfio/platform.o
  CC      x86_64-softmmu/hw/vfio/calxeda-xgmac.o
  CC      aarch64-softmmu/hw/dma/pxa2xx_dma.o
  CC      aarch64-softmmu/hw/dma/bcm2835_dma.o
  CC      x86_64-softmmu/hw/vfio/amd-xgbe.o
  CC      aarch64-softmmu/hw/gpio/omap_gpio.o
  CC      x86_64-softmmu/hw/vfio/spapr.o
  CC      x86_64-softmmu/hw/virtio/virtio.o
  CC      aarch64-softmmu/hw/gpio/imx_gpio.o
  CC      aarch64-softmmu/hw/i2c/omap_i2c.o
  CC      aarch64-softmmu/hw/input/pxa2xx_keypad.o
  CC      x86_64-softmmu/hw/virtio/virtio-balloon.o
  CC      x86_64-softmmu/hw/virtio/vhost.o
  CC      x86_64-softmmu/hw/virtio/vhost-backend.o
  CC      aarch64-softmmu/hw/input/tsc210x.o
  CC      x86_64-softmmu/hw/virtio/vhost-user.o
  CC      x86_64-softmmu/hw/virtio/vhost-vsock.o
  CC      aarch64-softmmu/hw/intc/armv7m_nvic.o
  CC      aarch64-softmmu/hw/intc/exynos4210_gic.o
  CC      aarch64-softmmu/hw/intc/exynos4210_combiner.o
  CC      aarch64-softmmu/hw/intc/omap_intc.o
  CC      x86_64-softmmu/hw/virtio/virtio-crypto.o
  CC      aarch64-softmmu/hw/intc/bcm2835_ic.o
  CC      x86_64-softmmu/hw/virtio/virtio-crypto-pci.o
  CC      aarch64-softmmu/hw/intc/bcm2836_control.o
  CC      x86_64-softmmu/hw/i386/multiboot.o
  CC      x86_64-softmmu/hw/i386/pc.o
  CC      x86_64-softmmu/hw/i386/pc_piix.o
  CC      x86_64-softmmu/hw/i386/pc_q35.o
  CC      x86_64-softmmu/hw/i386/pc_sysfw.o
  CC      aarch64-softmmu/hw/intc/allwinner-a10-pic.o
  CC      aarch64-softmmu/hw/intc/aspeed_vic.o
  CC      x86_64-softmmu/hw/i386/x86-iommu.o
  CC      x86_64-softmmu/hw/i386/intel_iommu.o
  CC      aarch64-softmmu/hw/intc/arm_gicv3_cpuif.o
  CC      x86_64-softmmu/hw/i386/amd_iommu.o
  CC      aarch64-softmmu/hw/misc/ivshmem.o
  CC      x86_64-softmmu/hw/i386/kvmvapic.o
  CC      aarch64-softmmu/hw/misc/arm_sysctl.o
  CC      x86_64-softmmu/hw/i386/acpi-build.o
  CC      aarch64-softmmu/hw/misc/cbus.o
  CC      x86_64-softmmu/hw/i386/pci-assign-load-rom.o
  CC      x86_64-softmmu/hw/i386/kvm/clock.o
  CC      x86_64-softmmu/hw/i386/kvm/apic.o
  CC      aarch64-softmmu/hw/misc/exynos4210_pmu.o
  CC      aarch64-softmmu/hw/misc/imx_ccm.o
  CC      aarch64-softmmu/hw/misc/imx31_ccm.o
/tmp/qemu-test/src/hw/i386/pc_piix.c: In function ‘igd_passthrough_isa_bridge_create’:
/tmp/qemu-test/src/hw/i386/pc_piix.c:1046: warning: ‘pch_rev_id’ may be used uninitialized in this function
  CC      x86_64-softmmu/hw/i386/kvm/i8259.o
  CC      aarch64-softmmu/hw/misc/imx25_ccm.o
  CC      aarch64-softmmu/hw/misc/imx6_ccm.o
  CC      aarch64-softmmu/hw/misc/imx6_src.o
  CC      aarch64-softmmu/hw/misc/mst_fpga.o
  CC      x86_64-softmmu/hw/i386/kvm/ioapic.o
  CC      x86_64-softmmu/hw/i386/kvm/i8254.o
  CC      x86_64-softmmu/hw/i386/kvm/pci-assign.o
  CC      aarch64-softmmu/hw/misc/omap_clk.o
  CC      x86_64-softmmu/target/i386/translate.o
  CC      x86_64-softmmu/target/i386/helper.o
  CC      x86_64-softmmu/target/i386/cpu.o
  CC      x86_64-softmmu/target/i386/bpt_helper.o
  CC      x86_64-softmmu/target/i386/excp_helper.o
  CC      aarch64-softmmu/hw/misc/omap_gpmc.o
  CC      aarch64-softmmu/hw/misc/omap_l4.o
  CC      aarch64-softmmu/hw/misc/omap_sdrc.o
  CC      aarch64-softmmu/hw/misc/omap_tap.o
/tmp/qemu-test/src/hw/i386/acpi-build.c: In function ‘build_append_pci_bus_devices’:
/tmp/qemu-test/src/hw/i386/acpi-build.c:496: warning: ‘notify_method’ may be used uninitialized in this function
  CC      x86_64-softmmu/target/i386/fpu_helper.o
  CC      aarch64-softmmu/hw/misc/bcm2835_mbox.o
  CC      x86_64-softmmu/target/i386/cc_helper.o
  CC      x86_64-softmmu/target/i386/int_helper.o
  CC      x86_64-softmmu/target/i386/svm_helper.o
  CC      aarch64-softmmu/hw/misc/bcm2835_property.o
  CC      aarch64-softmmu/hw/misc/zynq_slcr.o
  CC      aarch64-softmmu/hw/misc/zynq-xadc.o
  CC      x86_64-softmmu/target/i386/smm_helper.o
  CC      aarch64-softmmu/hw/misc/stm32f2xx_syscfg.o
  CC      aarch64-softmmu/hw/misc/edu.o
  CC      x86_64-softmmu/target/i386/misc_helper.o
  CC      aarch64-softmmu/hw/misc/auxbus.o
  CC      x86_64-softmmu/target/i386/mem_helper.o
  CC      aarch64-softmmu/hw/misc/aspeed_scu.o
  CC      x86_64-softmmu/target/i386/seg_helper.o
  CC      x86_64-softmmu/target/i386/mpx_helper.o
  CC      aarch64-softmmu/hw/misc/aspeed_sdmc.o
  CC      x86_64-softmmu/target/i386/gdbstub.o
  CC      aarch64-softmmu/hw/net/virtio-net.o
  CC      x86_64-softmmu/target/i386/machine.o
  CC      x86_64-softmmu/target/i386/arch_memory_mapping.o
  CC      aarch64-softmmu/hw/net/vhost_net.o
  CC      x86_64-softmmu/target/i386/arch_dump.o
  CC      x86_64-softmmu/target/i386/monitor.o
  CC      x86_64-softmmu/target/i386/kvm.o
  CC      aarch64-softmmu/hw/pcmcia/pxa2xx.o
  CC      aarch64-softmmu/hw/scsi/virtio-scsi.o
  CC      x86_64-softmmu/target/i386/hyperv.o
  CC      aarch64-softmmu/hw/scsi/virtio-scsi-dataplane.o
  CC      aarch64-softmmu/hw/scsi/vhost-scsi.o
  CC      aarch64-softmmu/hw/sd/omap_mmc.o
  CC      aarch64-softmmu/hw/sd/pxa2xx_mmci.o
  GEN     trace/generated-helpers.c
  CC      aarch64-softmmu/hw/ssi/omap_spi.o
  CC      x86_64-softmmu/trace/control-target.o
  CC      aarch64-softmmu/hw/ssi/imx_spi.o
  CC      aarch64-softmmu/hw/timer/exynos4210_mct.o
  CC      aarch64-softmmu/hw/timer/exynos4210_pwm.o
  CC      aarch64-softmmu/hw/timer/exynos4210_rtc.o
  CC      aarch64-softmmu/hw/timer/omap_gptimer.o
  CC      aarch64-softmmu/hw/timer/omap_synctimer.o
  CC      aarch64-softmmu/hw/timer/pxa2xx_timer.o
  CC      aarch64-softmmu/hw/timer/digic-timer.o
  CC      aarch64-softmmu/hw/usb/tusb6010.o
  CC      aarch64-softmmu/hw/timer/allwinner-a10-pit.o
  CC      aarch64-softmmu/hw/vfio/common.o
  CC      aarch64-softmmu/hw/vfio/pci.o
  CC      x86_64-softmmu/trace/generated-helpers.o
  CC      aarch64-softmmu/hw/vfio/pci-quirks.o
  CC      aarch64-softmmu/hw/vfio/platform.o
  CC      aarch64-softmmu/hw/vfio/calxeda-xgmac.o
  CC      aarch64-softmmu/hw/vfio/amd-xgbe.o
  CC      aarch64-softmmu/hw/vfio/spapr.o
  CC      aarch64-softmmu/hw/virtio/virtio.o
  CC      aarch64-softmmu/hw/virtio/virtio-balloon.o
  CC      aarch64-softmmu/hw/virtio/vhost.o
  CC      aarch64-softmmu/hw/virtio/vhost-backend.o
  CC      aarch64-softmmu/hw/virtio/vhost-user.o
  CC      aarch64-softmmu/hw/virtio/vhost-vsock.o
  CC      aarch64-softmmu/hw/virtio/virtio-crypto.o
  CC      aarch64-softmmu/hw/virtio/virtio-crypto-pci.o
  CC      aarch64-softmmu/hw/arm/boot.o
  CC      aarch64-softmmu/hw/arm/collie.o
  CC      aarch64-softmmu/hw/arm/exynos4_boards.o
  CC      aarch64-softmmu/hw/arm/gumstix.o
  CC      aarch64-softmmu/hw/arm/highbank.o
  CC      aarch64-softmmu/hw/arm/digic_boards.o
  CC      aarch64-softmmu/hw/arm/integratorcp.o
  CC      aarch64-softmmu/hw/arm/mainstone.o
  CC      aarch64-softmmu/hw/arm/musicpal.o
  CC      aarch64-softmmu/hw/arm/nseries.o
  CC      aarch64-softmmu/hw/arm/omap_sx1.o
  CC      aarch64-softmmu/hw/arm/palm.o
  CC      aarch64-softmmu/hw/arm/realview.o
  CC      aarch64-softmmu/hw/arm/spitz.o
  CC      aarch64-softmmu/hw/arm/stellaris.o
  CC      aarch64-softmmu/hw/arm/tosa.o
  CC      aarch64-softmmu/hw/arm/versatilepb.o
  CC      aarch64-softmmu/hw/arm/vexpress.o
  CC      aarch64-softmmu/hw/arm/virt.o
  CC      aarch64-softmmu/hw/arm/xilinx_zynq.o
  CC      aarch64-softmmu/hw/arm/z2.o
  CC      aarch64-softmmu/hw/arm/virt-acpi-build.o
  CC      aarch64-softmmu/hw/arm/netduino2.o
  CC      aarch64-softmmu/hw/arm/sysbus-fdt.o
  CC      aarch64-softmmu/hw/arm/armv7m.o
  CC      aarch64-softmmu/hw/arm/exynos4210.o
  CC      aarch64-softmmu/hw/arm/pxa2xx.o
  CC      aarch64-softmmu/hw/arm/pxa2xx_gpio.o
  CC      aarch64-softmmu/hw/arm/pxa2xx_pic.o
  CC      aarch64-softmmu/hw/arm/digic.o
  CC      aarch64-softmmu/hw/arm/omap1.o
  CC      aarch64-softmmu/hw/arm/omap2.o
  CC      aarch64-softmmu/hw/arm/strongarm.o
  CC      aarch64-softmmu/hw/arm/allwinner-a10.o
  CC      aarch64-softmmu/hw/arm/cubieboard.o
  CC      aarch64-softmmu/hw/arm/bcm2835_peripherals.o
  CC      aarch64-softmmu/hw/arm/bcm2836.o
  CC      aarch64-softmmu/hw/arm/stm32f205_soc.o
  CC      aarch64-softmmu/hw/arm/raspi.o
  CC      aarch64-softmmu/hw/arm/xlnx-zynqmp.o
  CC      aarch64-softmmu/hw/arm/xlnx-ep108.o
  CC      aarch64-softmmu/hw/arm/fsl-imx25.o
  CC      aarch64-softmmu/hw/arm/imx25_pdk.o
  CC      aarch64-softmmu/hw/arm/fsl-imx31.o
  CC      aarch64-softmmu/hw/arm/kzm.o
  CC      aarch64-softmmu/hw/arm/fsl-imx6.o
  CC      aarch64-softmmu/hw/arm/sabrelite.o
  CC      aarch64-softmmu/hw/arm/aspeed_soc.o
  CC      aarch64-softmmu/hw/arm/aspeed.o
  CC      aarch64-softmmu/target/arm/machine.o
  CC      aarch64-softmmu/target/arm/arm-semi.o
  CC      aarch64-softmmu/target/arm/psci.o
  CC      aarch64-softmmu/target/arm/arch_dump.o
  CC      aarch64-softmmu/target/arm/monitor.o
  CC      aarch64-softmmu/target/arm/kvm-stub.o
  CC      aarch64-softmmu/target/arm/translate.o
  CC      aarch64-softmmu/target/arm/op_helper.o
  CC      aarch64-softmmu/target/arm/helper.o
  CC      aarch64-softmmu/target/arm/neon_helper.o
  CC      aarch64-softmmu/target/arm/cpu.o
  CC      aarch64-softmmu/target/arm/iwmmxt_helper.o
  CC      aarch64-softmmu/target/arm/gdbstub.o
  CC      aarch64-softmmu/target/arm/cpu64.o
  CC      aarch64-softmmu/target/arm/translate-a64.o
  CC      aarch64-softmmu/target/arm/helper-a64.o
  LINK    x86_64-softmmu/qemu-system-x86_64
  CC      aarch64-softmmu/target/arm/gdbstub64.o
  CC      aarch64-softmmu/target/arm/crypto_helper.o
  CC      aarch64-softmmu/target/arm/arm-powerctl.o
  GEN     trace/generated-helpers.c
  CC      aarch64-softmmu/trace/control-target.o
  CC      aarch64-softmmu/gdbstub-xml.o
  CC      aarch64-softmmu/trace/generated-helpers.o
/tmp/qemu-test/src/target/arm/translate-a64.c: In function ‘handle_shri_with_rndacc’:
/tmp/qemu-test/src/target/arm/translate-a64.c:6369: warning: ‘tcg_src_hi’ may be used uninitialized in this function
/tmp/qemu-test/src/target/arm/translate-a64.c: In function ‘disas_simd_scalar_two_reg_misc’:
/tmp/qemu-test/src/target/arm/translate-a64.c:8096: warning: ‘rmode’ may be used uninitialized in this function
  LINK    aarch64-softmmu/qemu-system-aarch64
  TEST    tests/qapi-schema/alternate-any.out
  TEST    tests/qapi-schema/alternate-array.out
  TEST    tests/qapi-schema/alternate-base.out
  TEST    tests/qapi-schema/alternate-clash.out
  TEST    tests/qapi-schema/alternate-conflict-dict.out
  TEST    tests/qapi-schema/alternate-empty.out
  TEST    tests/qapi-schema/alternate-conflict-string.out
  TEST    tests/qapi-schema/alternate-nested.out
  TEST    tests/qapi-schema/alternate-unknown.out
  TEST    tests/qapi-schema/args-any.out
  TEST    tests/qapi-schema/args-alternate.out
  TEST    tests/qapi-schema/args-array-empty.out
  TEST    tests/qapi-schema/args-array-unknown.out
  TEST    tests/qapi-schema/args-bad-boxed.out
  TEST    tests/qapi-schema/args-boxed-anon.out
  TEST    tests/qapi-schema/args-boxed-empty.out
  TEST    tests/qapi-schema/args-boxed-string.out
  TEST    tests/qapi-schema/args-int.out
  TEST    tests/qapi-schema/args-invalid.out
  TEST    tests/qapi-schema/args-member-array-bad.out
  TEST    tests/qapi-schema/args-member-case.out
  TEST    tests/qapi-schema/args-member-unknown.out
  TEST    tests/qapi-schema/args-name-clash.out
  TEST    tests/qapi-schema/args-union.out
  TEST    tests/qapi-schema/args-unknown.out
  TEST    tests/qapi-schema/async.out
  TEST    tests/qapi-schema/bad-base.out
  TEST    tests/qapi-schema/bad-data.out
  TEST    tests/qapi-schema/bad-ident.out
  TEST    tests/qapi-schema/bad-type-bool.out
  TEST    tests/qapi-schema/bad-type-dict.out
  TEST    tests/qapi-schema/bad-type-int.out
  TEST    tests/qapi-schema/base-cycle-direct.out
  TEST    tests/qapi-schema/base-cycle-indirect.out
  TEST    tests/qapi-schema/command-int.out
  TEST    tests/qapi-schema/comments.out
  TEST    tests/qapi-schema/doc-bad-args.out
  TEST    tests/qapi-schema/doc-bad-symbol.out
  TEST    tests/qapi-schema/doc-duplicated-arg.out
  TEST    tests/qapi-schema/doc-duplicated-return.out
  TEST    tests/qapi-schema/doc-duplicated-since.out
  TEST    tests/qapi-schema/doc-empty-arg.out
  TEST    tests/qapi-schema/doc-empty-section.out
  TEST    tests/qapi-schema/doc-empty-symbol.out
  TEST    tests/qapi-schema/doc-interleaved-section.out
  TEST    tests/qapi-schema/doc-invalid-end.out
  TEST    tests/qapi-schema/doc-invalid-end2.out
  TEST    tests/qapi-schema/doc-invalid-return.out
  TEST    tests/qapi-schema/doc-invalid-section.out
  TEST    tests/qapi-schema/doc-invalid-start.out
  TEST    tests/qapi-schema/doc-missing-colon.out
  TEST    tests/qapi-schema/doc-missing-expr.out
  TEST    tests/qapi-schema/doc-missing-space.out
  TEST    tests/qapi-schema/doc-optional.out
  TEST    tests/qapi-schema/double-type.out
  TEST    tests/qapi-schema/duplicate-key.out
  TEST    tests/qapi-schema/double-data.out
  TEST    tests/qapi-schema/empty.out
  TEST    tests/qapi-schema/enum-bad-name.out
  TEST    tests/qapi-schema/enum-bad-prefix.out
  TEST    tests/qapi-schema/enum-clash-member.out
  TEST    tests/qapi-schema/enum-dict-member.out
  TEST    tests/qapi-schema/enum-int-member.out
  TEST    tests/qapi-schema/enum-member-case.out
  TEST    tests/qapi-schema/enum-missing-data.out
  TEST    tests/qapi-schema/enum-wrong-data.out
  TEST    tests/qapi-schema/escape-outside-string.out
  TEST    tests/qapi-schema/escape-too-big.out
  TEST    tests/qapi-schema/escape-too-short.out
  TEST    tests/qapi-schema/event-boxed-empty.out
  TEST    tests/qapi-schema/event-case.out
  TEST    tests/qapi-schema/event-nest-struct.out
  TEST    tests/qapi-schema/flat-union-array-branch.out
  TEST    tests/qapi-schema/flat-union-bad-base.out
  TEST    tests/qapi-schema/flat-union-base-any.out
  TEST    tests/qapi-schema/flat-union-bad-discriminator.out
  TEST    tests/qapi-schema/flat-union-base-union.out
  TEST    tests/qapi-schema/flat-union-clash-member.out
  TEST    tests/qapi-schema/flat-union-empty.out
  TEST    tests/qapi-schema/flat-union-int-branch.out
  TEST    tests/qapi-schema/flat-union-incomplete-branch.out
  TEST    tests/qapi-schema/flat-union-inline.out
  TEST    tests/qapi-schema/flat-union-invalid-branch-key.out
  TEST    tests/qapi-schema/flat-union-invalid-discriminator.out
  TEST    tests/qapi-schema/flat-union-no-base.out
  TEST    tests/qapi-schema/flat-union-optional-discriminator.out
  TEST    tests/qapi-schema/flat-union-string-discriminator.out
  TEST    tests/qapi-schema/funny-char.out
  TEST    tests/qapi-schema/ident-with-escape.out
  TEST    tests/qapi-schema/include-before-err.out
  TEST    tests/qapi-schema/include-cycle.out
  TEST    tests/qapi-schema/include-format-err.out
  TEST    tests/qapi-schema/include-nested-err.out
  TEST    tests/qapi-schema/include-no-file.out
  TEST    tests/qapi-schema/include-non-file.out
  TEST    tests/qapi-schema/include-relpath.out
  TEST    tests/qapi-schema/include-self-cycle.out
  TEST    tests/qapi-schema/include-repetition.out
  TEST    tests/qapi-schema/include-simple.out
  TEST    tests/qapi-schema/indented-expr.out
  TEST    tests/qapi-schema/leading-comma-list.out
  TEST    tests/qapi-schema/leading-comma-object.out
  TEST    tests/qapi-schema/missing-comma-list.out
  TEST    tests/qapi-schema/missing-colon.out
  TEST    tests/qapi-schema/missing-comma-object.out
  TEST    tests/qapi-schema/missing-type.out
  TEST    tests/qapi-schema/nested-struct-data.out
  TEST    tests/qapi-schema/non-objects.out
  TEST    tests/qapi-schema/qapi-schema-test.out
  TEST    tests/qapi-schema/quoted-structural-chars.out
  TEST    tests/qapi-schema/redefined-builtin.out
  TEST    tests/qapi-schema/redefined-command.out
  TEST    tests/qapi-schema/redefined-event.out
  TEST    tests/qapi-schema/redefined-type.out
  TEST    tests/qapi-schema/reserved-command-q.out
  TEST    tests/qapi-schema/reserved-enum-q.out
  TEST    tests/qapi-schema/reserved-member-has.out
  TEST    tests/qapi-schema/reserved-member-q.out
  TEST    tests/qapi-schema/reserved-member-u.out
  TEST    tests/qapi-schema/reserved-member-underscore.out
  TEST    tests/qapi-schema/reserved-type-kind.out
  TEST    tests/qapi-schema/reserved-type-list.out
  TEST    tests/qapi-schema/returns-alternate.out
  TEST    tests/qapi-schema/returns-array-bad.out
  TEST    tests/qapi-schema/returns-unknown.out
  TEST    tests/qapi-schema/returns-dict.out
  TEST    tests/qapi-schema/returns-whitelist.out
  TEST    tests/qapi-schema/struct-base-clash-deep.out
  TEST    tests/qapi-schema/struct-base-clash.out
  TEST    tests/qapi-schema/struct-data-invalid.out
  TEST    tests/qapi-schema/struct-member-invalid.out
  TEST    tests/qapi-schema/trailing-comma-list.out
  TEST    tests/qapi-schema/trailing-comma-object.out
  TEST    tests/qapi-schema/type-bypass-bad-gen.out
  TEST    tests/qapi-schema/unclosed-list.out
  TEST    tests/qapi-schema/unclosed-object.out
  TEST    tests/qapi-schema/unclosed-string.out
  TEST    tests/qapi-schema/unicode-str.out
  TEST    tests/qapi-schema/union-base-no-discriminator.out
  TEST    tests/qapi-schema/union-branch-case.out
  TEST    tests/qapi-schema/union-clash-branches.out
  TEST    tests/qapi-schema/union-empty.out
  TEST    tests/qapi-schema/union-optional-branch.out
  TEST    tests/qapi-schema/union-unknown.out
  TEST    tests/qapi-schema/union-invalid-base.out
  TEST    tests/qapi-schema/unknown-escape.out
  TEST    tests/qapi-schema/unknown-expr-key.out
  CC      tests/check-qdict.o
  CC      tests/test-char.o
  CC      tests/check-qint.o
  CC      tests/check-qfloat.o
  CC      tests/check-qstring.o
  CC      tests/check-qjson.o
  CC      tests/check-qnull.o
  CC      tests/check-qlist.o
  CC      tests/test-qobject-output-visitor.o
  GEN     tests/test-qapi-visit.c
  GEN     tests/test-qapi-event.c
  GEN     tests/test-qmp-introspect.c
  GEN     tests/test-qapi-types.c
  CC      tests/test-clone-visitor.o
  CC      tests/test-qobject-input-visitor.o
  CC      tests/test-qobject-input-strict.o
  CC      tests/test-qmp-commands.o
  GEN     tests/test-qmp-marshal.c
  CC      tests/test-string-input-visitor.o
  CC      tests/test-string-output-visitor.o
  CC      tests/test-qmp-event.o
  CC      tests/test-opts-visitor.o
  CC      tests/test-coroutine.o
  CC      tests/test-aio.o
  CC      tests/test-visitor-serialization.o
  CC      tests/test-iov.o
  CC      tests/test-throttle.o
  CC      tests/test-thread-pool.o
  CC      tests/test-hbitmap.o
/tmp/qemu-test/src/tests/test-qmp-commands.c: In function ‘test_dispatch_cmd’:
/tmp/qemu-test/src/tests/test-qmp-commands.c:127: warning: missing braces around initializer
/tmp/qemu-test/src/tests/test-qmp-commands.c:127: warning: (near initialization for ‘client.parser’)
/tmp/qemu-test/src/tests/test-qmp-commands.c: In function ‘test_dispatch_cmd_failure’:
/tmp/qemu-test/src/tests/test-qmp-commands.c:149: warning: missing braces around initializer
/tmp/qemu-test/src/tests/test-qmp-commands.c:149: warning: (near initialization for ‘client.parser’)
/tmp/qemu-test/src/tests/test-qmp-commands.c: In function ‘test_qmp_dispatch’:
/tmp/qemu-test/src/tests/test-qmp-commands.c:193: warning: missing braces around initializer
/tmp/qemu-test/src/tests/test-qmp-commands.c:193: warning: (near initialization for ‘client.parser’)
  CC      tests/test-blockjob.o
  CC      tests/test-blockjob-txn.o
  CC      tests/test-x86-cpuid.o
  CC      tests/test-xbzrle.o
  CC      tests/test-vmstate.o
  CC      tests/test-cutils.o
  CC      tests/test-mul64.o
  CC      tests/test-int128.o
  CC      tests/rcutorture.o
  CC      tests/test-rcu-list.o
/tmp/qemu-test/src/tests/test-int128.c:180: warning: ‘__noclone__’ attribute directive ignored
  CC      tests/test-qdist.o
  CC      tests/test-qht.o
  CC      tests/test-qht-par.o
  CC      tests/qht-bench.o
  CC      tests/test-bitops.o
  CC      tests/test-bitcnt.o
  CC      tests/check-qom-interface.o
  CC      tests/check-qom-proplist.o
  CC      tests/test-qemu-opts.o
  CC      tests/test-write-threshold.o
  CC      tests/test-crypto-hash.o
  CC      tests/test-crypto-hmac.o
  CC      tests/test-crypto-cipher.o
  CC      tests/test-crypto-secret.o
  CC      tests/test-qga.o
  CC      tests/libqtest.o
  CC      tests/test-timed-average.o
  CC      tests/test-io-task.o
  CC      tests/test-io-channel-socket.o
  CC      tests/io-channel-helpers.o
  CC      tests/test-io-channel-file.o
  CC      tests/test-io-channel-command.o
  CC      tests/test-io-channel-buffer.o
  CC      tests/test-base64.o
  CC      tests/test-crypto-ivgen.o
  CC      tests/test-crypto-afsplit.o
  CC      tests/test-crypto-xts.o
  CC      tests/test-crypto-block.o
  CC      tests/test-logging.o
  CC      tests/test-replication.o
  CC      tests/test-bufferiszero.o
  CC      tests/test-uuid.o
  CC      tests/ptimer-test.o
  CC      tests/ptimer-test-stubs.o
  CC      tests/vhost-user-test.o
  CC      tests/libqos/pci.o
  CC      tests/libqos/fw_cfg.o
  CC      tests/libqos/malloc.o
  CC      tests/libqos/i2c.o
  CC      tests/libqos/libqos.o
  CC      tests/libqos/malloc-spapr.o
  CC      tests/libqos/libqos-spapr.o
  CC      tests/libqos/rtas.o
  CC      tests/libqos/pci-spapr.o
  CC      tests/libqos/pci-pc.o
  CC      tests/libqos/malloc-pc.o
  CC      tests/libqos/libqos-pc.o
  CC      tests/libqos/ahci.o
  CC      tests/libqos/virtio.o
  CC      tests/libqos/virtio-pci.o
  CC      tests/libqos/virtio-mmio.o
  CC      tests/libqos/malloc-generic.o
  CC      tests/endianness-test.o
  CC      tests/fdc-test.o
  CC      tests/ide-test.o
  CC      tests/ahci-test.o
  CC      tests/hd-geo-test.o
  CC      tests/boot-order-test.o
  CC      tests/bios-tables-test.o
  CC      tests/boot-sector.o
  CC      tests/boot-serial-test.o
  CC      tests/pxe-test.o
  CC      tests/rtc-test.o
  CC      tests/ipmi-kcs-test.o
  CC      tests/ipmi-bt-test.o
  CC      tests/i440fx-test.o
  CC      tests/fw_cfg-test.o
  CC      tests/drive_del-test.o
  CC      tests/wdt_ib700-test.o
  CC      tests/tco-test.o
  CC      tests/e1000-test.o
  CC      tests/e1000e-test.o
  CC      tests/rtl8139-test.o
/tmp/qemu-test/src/tests/ide-test.c: In function ‘cdrom_pio_impl’:
/tmp/qemu-test/src/tests/ide-test.c:791: warning: ignoring return value of ‘fwrite’, declared with attribute warn_unused_result
/tmp/qemu-test/src/tests/ide-test.c: In function ‘test_cdrom_dma’:
/tmp/qemu-test/src/tests/ide-test.c:886: warning: ignoring return value of ‘fwrite’, declared with attribute warn_unused_result
  CC      tests/pcnet-test.o
  CC      tests/eepro100-test.o
  CC      tests/ne2000-test.o
  CC      tests/nvme-test.o
  CC      tests/ac97-test.o
  CC      tests/es1370-test.o
  CC      tests/virtio-net-test.o
  CC      tests/virtio-balloon-test.o
  CC      tests/virtio-blk-test.o
  CC      tests/virtio-rng-test.o
  CC      tests/virtio-scsi-test.o
  CC      tests/virtio-serial-test.o
  CC      tests/virtio-console-test.o
  CC      tests/tpci200-test.o
  CC      tests/ipoctal232-test.o
  CC      tests/display-vga-test.o
  CC      tests/intel-hda-test.o
  CC      tests/ivshmem-test.o
  CC      tests/vmxnet3-test.o
  CC      tests/pvpanic-test.o
  CC      tests/i82801b11-test.o
  CC      tests/ioh3420-test.o
  CC      tests/usb-hcd-ohci-test.o
  CC      tests/libqos/usb.o
  CC      tests/usb-hcd-uhci-test.o
  CC      tests/usb-hcd-ehci-test.o
  CC      tests/usb-hcd-xhci-test.o
  CC      tests/pc-cpu-test.o
  CC      tests/q35-test.o
  CC      tests/test-netfilter.o
  CC      tests/test-filter-mirror.o
  CC      tests/test-filter-redirector.o
  CC      tests/postcopy-test.o
  CC      tests/test-x86-cpuid-compat.o
  CC      tests/device-introspect-test.o
  CC      tests/qom-test.o
  CC      tests/qmp-test.o
  LINK    tests/check-qdict
  LINK    tests/test-char
  LINK    tests/check-qfloat
  LINK    tests/check-qint
  LINK    tests/check-qstring
  LINK    tests/check-qlist
  LINK    tests/check-qnull
  LINK    tests/check-qjson
  CC      tests/test-qapi-visit.o
  CC      tests/test-qapi-types.o
  CC      tests/test-qapi-event.o
  CC      tests/test-qmp-introspect.o
  CC      tests/test-qmp-marshal.o
  LINK    tests/test-coroutine
  LINK    tests/test-iov
  LINK    tests/test-aio
  LINK    tests/test-throttle
  LINK    tests/test-thread-pool
  LINK    tests/test-hbitmap
  LINK    tests/test-blockjob
  LINK    tests/test-blockjob-txn
  LINK    tests/test-x86-cpuid
  LINK    tests/test-xbzrle
  LINK    tests/test-vmstate
  LINK    tests/test-cutils
  LINK    tests/test-mul64
  LINK    tests/test-int128
  LINK    tests/rcutorture
  LINK    tests/test-rcu-list
  LINK    tests/test-qdist
  LINK    tests/test-qht
  LINK    tests/qht-bench
  LINK    tests/test-bitops
  LINK    tests/test-bitcnt
  LINK    tests/check-qom-interface
  LINK    tests/check-qom-proplist
  LINK    tests/test-qemu-opts
  LINK    tests/test-write-threshold
  LINK    tests/test-crypto-hash
  LINK    tests/test-crypto-hmac
  LINK    tests/test-crypto-cipher
  LINK    tests/test-crypto-secret
  LINK    tests/test-qga
  LINK    tests/test-timed-average
  LINK    tests/test-io-task
  LINK    tests/test-io-channel-socket
  LINK    tests/test-io-channel-file
  LINK    tests/test-io-channel-command
  LINK    tests/test-io-channel-buffer
  LINK    tests/test-base64
  LINK    tests/test-crypto-ivgen
  LINK    tests/test-crypto-afsplit
  LINK    tests/test-crypto-xts
  LINK    tests/test-crypto-block
  LINK    tests/test-logging
  LINK    tests/test-replication
  LINK    tests/test-bufferiszero
  LINK    tests/test-uuid
  LINK    tests/ptimer-test
  LINK    tests/vhost-user-test
  LINK    tests/endianness-test
  LINK    tests/fdc-test
  LINK    tests/ide-test
  LINK    tests/ahci-test
  LINK    tests/hd-geo-test
  LINK    tests/boot-order-test
  LINK    tests/bios-tables-test
  LINK    tests/boot-serial-test
  LINK    tests/pxe-test
  LINK    tests/rtc-test
  LINK    tests/ipmi-kcs-test
  LINK    tests/ipmi-bt-test
  LINK    tests/i440fx-test
  LINK    tests/fw_cfg-test
  LINK    tests/drive_del-test
  LINK    tests/wdt_ib700-test
  LINK    tests/tco-test
  LINK    tests/e1000-test
  LINK    tests/e1000e-test
  LINK    tests/rtl8139-test
  LINK    tests/pcnet-test
  LINK    tests/eepro100-test
  LINK    tests/ne2000-test
  LINK    tests/nvme-test
  LINK    tests/ac97-test
  LINK    tests/es1370-test
  LINK    tests/virtio-net-test
  LINK    tests/virtio-balloon-test
  LINK    tests/virtio-blk-test
  LINK    tests/virtio-rng-test
  LINK    tests/virtio-scsi-test
  LINK    tests/virtio-serial-test
  LINK    tests/virtio-console-test
  LINK    tests/tpci200-test
  LINK    tests/ipoctal232-test
  LINK    tests/display-vga-test
  LINK    tests/intel-hda-test
  LINK    tests/ivshmem-test
  LINK    tests/vmxnet3-test
  LINK    tests/pvpanic-test
  LINK    tests/i82801b11-test
  LINK    tests/ioh3420-test
  LINK    tests/usb-hcd-ohci-test
  LINK    tests/usb-hcd-uhci-test
  LINK    tests/usb-hcd-ehci-test
  LINK    tests/usb-hcd-xhci-test
  LINK    tests/pc-cpu-test
  LINK    tests/q35-test
  LINK    tests/test-netfilter
  LINK    tests/test-filter-mirror
  LINK    tests/test-filter-redirector
  LINK    tests/postcopy-test
  LINK    tests/test-x86-cpuid-compat
  LINK    tests/device-introspect-test
  LINK    tests/qom-test
  LINK    tests/qmp-test
  GTESTER tests/test-char
  GTESTER tests/check-qdict
  GTESTER tests/check-qfloat
  GTESTER tests/check-qint
  GTESTER tests/check-qstring
  GTESTER tests/check-qlist
  GTESTER tests/check-qnull
  GTESTER tests/check-qjson
  LINK    tests/test-qobject-output-visitor
  LINK    tests/test-clone-visitor
  LINK    tests/test-qobject-input-visitor
  LINK    tests/test-qobject-input-strict
  LINK    tests/test-qmp-commands
  LINK    tests/test-string-input-visitor
  LINK    tests/test-string-output-visitor
  LINK    tests/test-qmp-event
  LINK    tests/test-opts-visitor
  GTESTER tests/test-coroutine
  LINK    tests/test-visitor-serialization
  GTESTER tests/test-iov
  GTESTER tests/test-aio
  GTESTER tests/test-throttle
  GTESTER tests/test-thread-pool
  GTESTER tests/test-hbitmap
  GTESTER tests/test-x86-cpuid
  GTESTER tests/test-blockjob
  GTESTER tests/test-vmstate
  GTESTER tests/test-blockjob-txn
  GTESTER tests/test-xbzrle
  GTESTER tests/test-cutils
  GTESTER tests/test-mul64
Failed to load simple/primitive:b_1
Failed to load simple/primitive:i64_2
Failed to load simple/primitive:i32_1
Failed to load simple/primitive:i32_1
  GTESTER tests/test-int128
  GTESTER tests/rcutorture
  GTESTER tests/test-rcu-list
  GTESTER tests/test-qdist
  GTESTER tests/test-qht
  LINK    tests/test-qht-par
  GTESTER tests/test-bitops
  GTESTER tests/check-qom-proplist
  GTESTER tests/test-bitcnt
  GTESTER tests/check-qom-interface
  GTESTER tests/test-qemu-opts
  GTESTER tests/test-crypto-hash
  GTESTER tests/test-write-threshold
  GTESTER tests/test-crypto-hmac
  GTESTER tests/test-crypto-cipher
  GTESTER tests/test-crypto-secret
  GTESTER tests/test-qga
  GTESTER tests/test-timed-average
  GTESTER tests/test-io-task
  GTESTER tests/test-io-channel-socket
  GTESTER tests/test-io-channel-file
  GTESTER tests/test-io-channel-command
  GTESTER tests/test-io-channel-buffer
  GTESTER tests/test-base64
  GTESTER tests/test-crypto-ivgen
  GTESTER tests/test-crypto-afsplit
  GTESTER tests/test-crypto-xts
  GTESTER tests/test-crypto-block
  GTESTER tests/test-logging
  GTESTER tests/test-replication
  GTESTER tests/test-bufferiszero
  GTESTER tests/test-uuid
  GTESTER tests/ptimer-test
  GTESTER check-qtest-x86_64
  GTESTER check-qtest-aarch64
  GTESTER tests/test-qobject-output-visitor
  GTESTER tests/test-clone-visitor
  GTESTER tests/test-qobject-input-visitor
  GTESTER tests/test-qobject-input-strict
  GTESTER tests/test-qmp-commands
  GTESTER tests/test-string-input-visitor
  GTESTER tests/test-string-output-visitor
  GTESTER tests/test-qmp-event
  GTESTER tests/test-opts-visitor
  GTESTER tests/test-qht-par
  GTESTER tests/test-visitor-serialization
ftruncate: Permission denied
ftruncate: Permission denied
ftruncate: Permission denied
**
ERROR:/tmp/qemu-test/src/tests/vhost-user-test.c:668:test_migrate: assertion failed: (qdict_haskey(rsp, "return"))
GTester: last random seed: R02S543b6f5a8838ad1423dc5b884df4ef55
ftruncate: Permission denied
ftruncate: Permission denied
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-nlrtpn_4/src'
  BUILD   fedora
make[1]: Entering directory `/var/tmp/patchew-tester-tmp-nlrtpn_4/src'
  ARCHIVE qemu.tgz
  ARCHIVE dtc.tgz
  COPY    RUNNER
    RUN test-mingw in qemu:fedora 
Packages installed:
PyYAML-3.11-12.fc24.x86_64
SDL-devel-1.2.15-21.fc24.x86_64
bc-1.06.95-16.fc24.x86_64
bison-3.0.4-4.fc24.x86_64
ccache-3.3.2-1.fc24.x86_64
clang-3.8.0-2.fc24.x86_64
findutils-4.6.0-7.fc24.x86_64
flex-2.6.0-2.fc24.x86_64
gcc-6.2.1-2.fc24.x86_64
gcc-c++-6.2.1-2.fc24.x86_64
git-2.7.4-3.fc24.x86_64
glib2-devel-2.48.2-1.fc24.x86_64
libfdt-devel-1.4.2-1.fc24.x86_64
make-4.1-5.fc24.x86_64
mingw32-SDL-1.2.15-7.fc24.noarch
mingw32-bzip2-1.0.6-7.fc24.noarch
mingw32-curl-7.47.0-1.fc24.noarch
mingw32-glib2-2.48.2-1.fc24.noarch
mingw32-gmp-6.1.0-1.fc24.noarch
mingw32-gnutls-3.4.14-1.fc24.noarch
mingw32-gtk2-2.24.31-1.fc24.noarch
mingw32-gtk3-3.20.9-1.fc24.noarch
mingw32-libjpeg-turbo-1.5.0-1.fc24.noarch
mingw32-libpng-1.6.23-1.fc24.noarch
mingw32-libssh2-1.4.3-5.fc24.noarch
mingw32-libtasn1-4.5-2.fc24.noarch
mingw32-nettle-3.2-1.fc24.noarch
mingw32-pixman-0.34.0-1.fc24.noarch
mingw32-pkg-config-0.28-6.fc24.x86_64
mingw64-SDL-1.2.15-7.fc24.noarch
mingw64-bzip2-1.0.6-7.fc24.noarch
mingw64-curl-7.47.0-1.fc24.noarch
mingw64-glib2-2.48.2-1.fc24.noarch
mingw64-gmp-6.1.0-1.fc24.noarch
mingw64-gnutls-3.4.14-1.fc24.noarch
mingw64-gtk2-2.24.31-1.fc24.noarch
mingw64-gtk3-3.20.9-1.fc24.noarch
mingw64-libjpeg-turbo-1.5.0-1.fc24.noarch
mingw64-libpng-1.6.23-1.fc24.noarch
mingw64-libssh2-1.4.3-5.fc24.noarch
mingw64-libtasn1-4.5-2.fc24.noarch
mingw64-nettle-3.2-1.fc24.noarch
mingw64-pixman-0.34.0-1.fc24.noarch
mingw64-pkg-config-0.28-6.fc24.x86_64
perl-5.22.2-362.fc24.x86_64
pixman-devel-0.34.0-2.fc24.x86_64
sparse-0.5.0-7.fc24.x86_64
tar-1.28-7.fc24.x86_64
which-2.20-13.fc24.x86_64
zlib-devel-1.2.8-10.fc24.x86_64

Environment variables:
PACKAGES=ccache git tar PyYAML sparse flex bison     glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel     gcc gcc-c++ clang make perl which bc findutils     mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config     mingw32-gtk2 mingw32-gtk3 mingw32-gnutls mingw32-nettle mingw32-libtasn1     mingw32-libjpeg-turbo mingw32-libpng mingw32-curl mingw32-libssh2     mingw32-bzip2     mingw64-pixman mingw64-glib2 mingw64-gmp mingw64-SDL mingw64-pkg-config     mingw64-gtk2 mingw64-gtk3 mingw64-gnutls mingw64-nettle mingw64-libtasn1     mingw64-libjpeg-turbo mingw64-libpng mingw64-curl mingw64-libssh2     mingw64-bzip2
HOSTNAME=
TERM=xterm
MAKEFLAGS= -j16
HISTSIZE=1000
J=16
USER=root
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
TARGET_LIST=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES=mingw clang pyyaml dtc
DEBUG=
_=/usr/bin/env

Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install --cross-prefix=x86_64-w64-mingw32- --enable-trace-backends=simple --enable-debug --enable-gnutls --enable-nettle --enable-curl --enable-vnc --enable-bzip2 --enable-guest-agent --with-sdlabi=1.2 --with-gtkabi=2.0
Install prefix    /var/tmp/qemu-build/install
BIOS directory    /var/tmp/qemu-build/install
binary directory  /var/tmp/qemu-build/install
library directory /var/tmp/qemu-build/install/lib
module directory  /var/tmp/qemu-build/install/lib
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory  /var/tmp/qemu-build/install
local state directory   queried at runtime
Windows SDK       no
Source path       /tmp/qemu-test/src
C compiler        x86_64-w64-mingw32-gcc
Host C compiler   cc
C++ compiler      x86_64-w64-mingw32-g++
Objective-C compiler clang
ARFLAGS           rv
CFLAGS            -g 
QEMU_CFLAGS       -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/pixman-1  -I$(SRC_PATH)/dtc/libfdt -Werror -mms-bitfields -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 -I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include  -m64 -mcx16 -mthreads -D__USE_MINGW_ANSI_STDIO=1 -DWIN32_LEAN_AND_MEAN -DWINVER=0x501 -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-shift-negative-value -Wmissing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-strong -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/p11-kit-1 -I/usr/x86_64-w64-mingw32/sys-root/mingw/include  -I/usr/x86_64-w64-mingw32/sys-root/mingw/include   -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/libpng16 
LDFLAGS           -Wl,--nxcompat -Wl,--no-seh -Wl,--dynamicbase -Wl,--warn-common -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
tcg debug enabled yes
gprof enabled     no
sparse enabled    no
strip binaries    no
profiler          no
static build      no
pixman            system
SDL support       yes (1.2.15)
GTK support       yes (2.24.31)
GTK GL support    no
VTE support       no 
TLS priority      NORMAL
GNUTLS support    yes
GNUTLS rnd        yes
libgcrypt         no
libgcrypt kdf     no
nettle            yes (3.2)
nettle kdf        yes
libtasn1          yes
curses support    no
virgl support     no
curl support      yes
mingw32 support   yes
Audio drivers     dsound
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    no
VNC support       yes
VNC SASL support  no
VNC JPEG support  yes
VNC PNG support   yes
xen support       no
brlapi support    no
bluez  support    no
Documentation     no
PIE               no
vde support       no
netmap support    no
Linux AIO support no
ATTR/XATTR support no
Install blobs     yes
KVM support       no
COLO support      yes
RDMA support      no
TCG interpreter   no
fdt support       yes
preadv support    no
fdatasync         no
madvise           no
posix_madvise     no
libcap-ng support no
vhost-net support no
vhost-scsi support no
vhost-vsock support no
Trace backends    simple
Trace output file trace-<pid>
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 yes
QGA MSI support   no
seccomp support   no
coroutine backend win32
coroutine pool    yes
debug stack usage no
GlusterFS support no
Archipelago support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   yes
TPM passthrough   no
QOM debugging     yes
lzo support       no
snappy support    no
bzip2 support     yes
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization yes
replication support yes
mkdir -p dtc/libfdt
  GEN     x86_64-softmmu/config-devices.mak.tmp
mkdir -p dtc/tests
  GEN     aarch64-softmmu/config-devices.mak.tmp
  GEN     config-host.h
  GEN     qemu-options.def
  GEN     qmp-commands.h
  GEN     qapi-types.h
  GEN     qapi-visit.h
  GEN     qapi-event.h
  GEN     qmp-introspect.h
  GEN     module_block.h
  GEN     tests/test-qapi-types.h
  GEN     tests/test-qapi-visit.h
  GEN     tests/test-qmp-commands.h
  GEN     tests/test-qapi-event.h
  GEN     tests/test-qmp-introspect.h
  GEN     x86_64-softmmu/config-devices.mak
  GEN     aarch64-softmmu/config-devices.mak
  GEN     trace/generated-tracers.h
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
	 DEP /tmp/qemu-test/src/dtc/tests/dumptrees.c
  GEN     trace/generated-helpers.h
	 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
  GEN     config-all-devices.mak
	 DEP /tmp/qemu-test/src/dtc/tests/subnode_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/string_escapes.c
	 DEP /tmp/qemu-test/src/dtc/tests/references.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/setprop.c
	 DEP /tmp/qemu-test/src/dtc/tests/del_property.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/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/get_path.c
	 DEP /tmp/qemu-test/src/dtc/tests/supernode_atdepth_offset.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/subnode_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_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/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/data.c
	 DEP /tmp/qemu-test/src/dtc/checks.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_wip.o
	 CC libfdt/fdt_ro.o
	 CC libfdt/fdt_sw.o
	 CC libfdt/fdt_strerror.o
	 CC libfdt/fdt_rw.o
	 CC libfdt/fdt_empty_tree.o
	 AR libfdt/libfdt.a
x86_64-w64-mingw32-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
  RC      version.o
  GEN     qga/qapi-generated/qga-qapi-visit.h
  GEN     qga/qapi-generated/qga-qapi-types.h
  GEN     qga/qapi-generated/qga-qmp-commands.h
  GEN     qga/qapi-generated/qga-qapi-types.c
  GEN     qga/qapi-generated/qga-qmp-marshal.c
  GEN     qga/qapi-generated/qga-qapi-visit.c
  GEN     qmp-introspect.c
  GEN     qapi-types.c
  GEN     qapi-visit.c
  GEN     qapi-event.c
  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/qint.o
  CC      qobject/qstring.o
  CC      qobject/qdict.o
  CC      qobject/qlist.o
  CC      qobject/qfloat.o
  CC      qobject/qbool.o
  CC      qobject/qjson.o
  CC      qobject/qobject.o
  CC      qobject/json-lexer.o
  CC      qobject/json-streamer.o
  CC      qobject/json-parser.o
  GEN     trace/generated-tracers.c
  CC      trace/simple.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/event_notifier-win32.o
  CC      util/oslib-win32.o
  CC      util/qemu-thread-win32.o
  CC      util/envlist.o
  CC      util/path.o
  CC      util/module.o
  CC      util/bitmap.o
  CC      util/bitops.o
  CC      util/hbitmap.o
  CC      util/fifo8.o
  CC      util/acl.o
  CC      util/error.o
  CC      util/qemu-error.o
  CC      util/id.o
  CC      util/qemu-config.o
  CC      util/iov.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/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-win32.o
  CC      util/buffer.o
  CC      util/timed-average.o
  CC      util/base64.o
  CC      util/log.o
  CC      util/qdist.o
  CC      util/qht.o
  CC      util/range.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/clock-warp.o
  CC      stubs/cpu-get-clock.o
  CC      stubs/cpu-get-icount.o
  CC      stubs/dump.o
  CC      stubs/error-printf.o
  CC      stubs/fdset-add-fd.o
  CC      stubs/fdset-find-fd.o
  CC      stubs/fdset-get-fd.o
  CC      stubs/fdset-remove-fd.o
  CC      stubs/gdbstub.o
  CC      stubs/get-fd.o
  CC      stubs/get-next-serial.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/mon-is-qmp.o
  CC      stubs/monitor-init.o
  CC      stubs/notify-event.o
  CC      stubs/qtest.o
  CC      stubs/replay.o
  CC      stubs/replay-user.o
  CC      stubs/reset.o
  CC      stubs/runstate-check.o
  CC      stubs/set-fd-handler.o
  CC      stubs/slirp.o
  CC      stubs/sysbus.o
  CC      stubs/trace-control.o
  CC      stubs/uuid.o
  CC      stubs/vm-stop.o
  CC      stubs/vmstate.o
  CC      stubs/fd-register.o
  CC      stubs/cpus.o
  CC      stubs/kvm.o
  CC      stubs/qmp_pc_dimm_device_list.o
  CC      stubs/target-monitor-defs.o
  CC      stubs/target-get-monitor-def.o
  CC      stubs/vhost.o
  CC      stubs/iohandler.o
  CC      stubs/smbios_type_38.o
  CC      stubs/ipmi.o
  CC      stubs/pc_madt_cpu_entry.o
  CC      stubs/migration-colo.o
  GEN     qemu-img-cmds.h
  CC      async.o
  CC      thread-pool.o
  CC      block.o
  CC      blockjob.o
  CC      main-loop.o
  CC      iohandler.o
  CC      qemu-timer.o
  CC      aio-win32.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
  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/qed.o
  CC      block/qed-gencb.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-win32.o
  CC      block/win32-aio.o
  CC      block/null.o
  CC      block/mirror.o
  CC      block/commit.o
  CC      block/io.o
  CC      block/throttle-groups.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/crypto.o
  CC      nbd/server.o
  CC      nbd/client.o
  CC      nbd/common.o
  CC      block/curl.o
  CC      block/ssh.o
  CC      block/dmg-bz2.o
  CC      crypto/init.o
  CC      crypto/hash.o
  CC      crypto/hash-nettle.o
  CC      crypto/hmac.o
  CC      crypto/hmac-nettle.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-gnutls.o
  CC      crypto/pbkdf.o
  CC      crypto/pbkdf-nettle.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/task.o
  CC      qom/object.o
  CC      qom/container.o
  CC      qom/qom-qobject.o
  CC      qom/object_interfaces.o
  CC      qemu-io.o
  CC      blockdev.o
  CC      blockdev-nbd.o
  CC      iothread.o
  CC      qdev-monitor.o
  CC      device-hotplug.o
  CC      os-win32.o
  CC      qemu-char.o
  CC      page_cache.o
  CC      accel.o
  CC      bt-host.o
  CC      bt-vhci.o
  CC      dma-helpers.o
  CC      vl.o
  CC      tpm.o
  CC      device_tree.o
  GEN     qmp-marshal.c
  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/sdlaudio.o
  CC      audio/dsoundaudio.o
  CC      audio/audio_win_int.o
  CC      audio/wavcapture.o
  CC      backends/rng.o
  CC      backends/rng-egd.o
  CC      backends/msmouse.o
  CC      backends/testdev.o
  CC      backends/tpm.o
  CC      backends/hostmem.o
  CC      backends/hostmem-ram.o
  CC      backends/cryptodev.o
  CC      backends/cryptodev-builtin.o
  CC      block/stream.o
  CC      disas/arm.o
  CXX     disas/arm-a64.o
  CC      disas/i386.o
  CXX     disas/libvixl/vixl/utils.o
  CXX     disas/libvixl/vixl/compiler-intrinsics.o
  CXX     disas/libvixl/vixl/a64/instructions-a64.o
  CXX     disas/libvixl/vixl/a64/decoder-a64.o
  CXX     disas/libvixl/vixl/a64/disasm-a64.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/acpi_interface.o
  CC      hw/acpi/bios-linker-loader.o
  CC      hw/acpi/aml-build.o
  CC      hw/acpi/ipmi.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/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/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/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/fw-path-provider.o
  CC      hw/core/irq.o
  CC      hw/core/hotplug.o
  CC      hw/core/ptimer.o
  CC      hw/core/sysbus.o
  CC      hw/core/machine.o
  CC      hw/core/null-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/platform-bus.o
  CC      hw/display/ads7846.o
  CC      hw/display/cirrus_vga.o
  CC      hw/display/pl110.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/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/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/vmmouse.o
  CC      hw/input/virtio-input.o
  CC      hw/input/virtio-input-hid.o
  CC      hw/intc/i8259_common.o
  CC      hw/intc/i8259.o
  CC      hw/intc/pl190.o
  CC      hw/intc/imx_avic.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/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/debugexit.o
  CC      hw/misc/sga.o
  CC      hw/misc/pc-testdev.o
  CC      hw/misc/pci-testdev.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/allwinner_emac.o
  CC      hw/net/imx_fec.o
  CC      hw/net/cadence_gem.o
  CC      hw/net/stellaris_enet.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/nvram/eeprom93xx.o
  CC      hw/nvram/fw_cfg.o
  CC      hw/pci-bridge/pci_bridge_dev.o
  CC      hw/nvram/chrp_nvram.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/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/sdhci.o
  CC      hw/smbios/smbios.o
  CC      hw/smbios/smbios_type_38.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/timer/arm_timer.o
  CC      hw/timer/arm_mptimer.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/aspeed_timer.o
  CC      hw/tpm/tpm_tis.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.o
  CC      hw/usb/desc-msos.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-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/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/watchdog/watchdog.o
  CC      hw/watchdog/wdt_i6300esb.o
  CC      hw/watchdog/wdt_ib700.o
  CC      migration/migration.o
  CC      migration/socket.o
  CC      migration/fd.o
  CC      migration/exec.o
  CC      migration/tls.o
  CC      migration/colo-comm.o
  CC      migration/colo.o
  CC      migration/colo-failover.o
  CC      migration/vmstate.o
  CC      migration/qemu-file.o
  CC      migration/qemu-file-channel.o
  CC      migration/xbzrle.o
  CC      migration/postcopy-ram.o
  CC      migration/qjson.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/tap-win32.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      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      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/dnssearch.o
  CC      slirp/dhcpv6.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
  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      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/sdl.o
  CC      ui/sdl_zoom.o
  CC      ui/x_keymap.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/gtk.o
  CC      qga/commands.o
  CC      qga/guest-agent-command-state.o
  CC      qga/main.o
  CC      qga/commands-win32.o
  AS      optionrom/multiboot.o
  AS      optionrom/linuxboot.o
  CC      optionrom/linuxboot_dma.o
  AS      optionrom/kvmvapic.o
  BUILD   optionrom/multiboot.img
  BUILD   optionrom/linuxboot.img
  BUILD   optionrom/linuxboot_dma.img
  BUILD   optionrom/kvmvapic.img
  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
  CC      qga/channel-win32.o
  SIGN    optionrom/kvmvapic.bin
  CC      qga/service-win32.o
  CC      qga/vss-win32.o
  CC      qga/qapi-generated/qga-qapi-types.o
  CC      qga/qapi-generated/qga-qapi-visit.o
  CC      qga/qapi-generated/qga-qmp-marshal.o
  CC      qmp-introspect.o
  CC      qapi-types.o
  CC      qapi-visit.o
  CC      qapi-event.o
In file included from /usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0/glib.h:62:0,
                 from /tmp/qemu-test/src/include/glib-compat.h:19,
                 from /tmp/qemu-test/src/include/qemu/osdep.h:107,
                 from /tmp/qemu-test/src/qga/main.c:13:
/tmp/qemu-test/src/qga/main.c: In function 'channel_event_cb':
/tmp/qemu-test/src/qga/main.c:575:17: error: format '%u' expects argument of type 'unsigned int', but argument 4 has type 'gsize {aka long long unsigned int}' [-Werror=format=]
         g_debug("read data, count: %" G_GSIZE_FORMAT ", data: %s", count, buf);
                 ^
/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0/glib/gmessages.h:170:32: note: in definition of macro 'g_debug'
                                __VA_ARGS__)
                                ^~~~~~~~~~~
cc1: all warnings being treated as errors
  AR      libqemustub.a
/tmp/qemu-test/src/rules.mak:64: recipe for target 'qga/main.o' failed
make: *** [qga/main.o] Error 1
make: *** Waiting for unfinished jobs....
make[1]: *** [docker-run] Error 2
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-nlrtpn_4/src'
make: *** [docker-run-test-mingw@fedora] Error 2
=== 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 v2 23/25] console: make screendump async
  2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 23/25] console: make screendump async Marc-André Lureau
@ 2017-01-19  8:20   ` Gerd Hoffmann
  2017-01-20 13:07     ` Marc-André Lureau
  0 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2017-01-19  8:20 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, eblake, berrange, armbru

On Mi, 2017-01-18 at 20:03 +0400, Marc-André Lureau wrote:
> +    surface = qemu_console_surface(con);
> +
> +    /* FIXME: async save with coroutine? it would have to copy or
> lock
> +     * the surface. */
> +    ppm_save(filename, surface, &err);
> +

No need to lock or copy.

ppm_save() uses the pixman image (surface->image) only anyway, so
changing it to accept a pixman image instead of the surface is easy.

pixman images are reference counted, so you can just grab a reference
using pixman_image_ref() and run with it, without risking it'll be
released underneath your feet, then unref when done.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v2 23/25] console: make screendump async
  2017-01-19  8:20   ` Gerd Hoffmann
@ 2017-01-20 13:07     ` Marc-André Lureau
  2017-01-23 12:04       ` Gerd Hoffmann
  0 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-20 13:07 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, armbru

Hi

On Thu, Jan 19, 2017 at 12:21 PM Gerd Hoffmann <kraxel@redhat.com> wrote:

> On Mi, 2017-01-18 at 20:03 +0400, Marc-André Lureau wrote:
> > +    surface = qemu_console_surface(con);
> > +
> > +    /* FIXME: async save with coroutine? it would have to copy or
> > lock
> > +     * the surface. */
> > +    ppm_save(filename, surface, &err);
> > +
>
> No need to lock or copy.
>
> ppm_save() uses the pixman image (surface->image) only anyway, so
> changing it to accept a pixman image instead of the surface is easy.
>
> pixman images are reference counted, so you can just grab a reference
> using pixman_image_ref() and run with it, without risking it'll be
> released underneath your feet, then unref when done.
>
>
If you only ref, you could have the image being modified while it is being
saved asynchronously, this could result in tearing artefacts, no?

-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (25 preceding siblings ...)
  2017-01-18 17:35 ` [Qemu-devel] [PATCH v2 00/25] qmp: add async command type no-reply
@ 2017-01-23 10:55 ` Stefan Hajnoczi
  2017-01-23 11:27   ` Marc-André Lureau
  2017-01-25 15:16 ` Markus Armbruster
  2017-05-04 19:01 ` Markus Armbruster
  28 siblings, 1 reply; 61+ messages in thread
From: Stefan Hajnoczi @ 2017-01-23 10:55 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, kraxel, armbru, Jeff Cody, John Snow

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

On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> Hi,

CCing Jeff Cody and John Snow, who have been working on generalizing
Block Job APIs to generic background jobs.  There is some overlap
between async commands and background jobs.

> 
> 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.
> 
> Note that qmp events are asynchronous messages, and must be handled
> appropriately by the client: dispatch both reply and events after a
> command is sent for example.
> 
> The benefits of async commands that can be trade-off depending on the
> requirements are:
> 
> 1) allow 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 tricky
> (see below) to solve.  Furthermore, many QMP commands do IO and could
> be considered 'slow' and blocking today.
> 
> 2) allow concurrent commands and events. This mainly implies hanlding
> concurrency in qemu and out-of-order replies for the client. As noted
> earlier, a good qmp client already has to handle dispatching of
> received messages (reply and events).
> 
> The traditional approach to solving the above in qemu is the following
> scheme:
> -> { "execute": "do-foo" }
> <- { "return": {} }
> <- { "event": "FOO_DONE" }
> 
> It has several flaws:
> - FOO_DONE event has no semantic link with do-foo in the qapi
>   schema. It is not simple to generalize that pattern when writing
>   qmp clients. It makes documentation and usage harder.
> - the FOO_DONE event has no clear association with the command that
>   triggered it: commands/events have to come up with additional
>   specific association schemes (ids, path etc)
> - FOO_DONE is broadcasted to all clients, but they may have no way to
>   interprete it or interest in it, or worse it may conflict with their
>   own commands.
> - the arguably useless empty reply return
> 
> For some cases, it makes sense to use that scheme, or a more complete
> one: to have an "handler" associated with an on-going operation, that
> can be queried, modified, cancelled etc (block jobs etc). Also, some
> operations have a global side-effect, in which case that cmd+event
> scheme is right, as all clients are listening for global events.
> 
> However, for the simple case where a client want to perform a "local
> context" operation (dump, query etc), QAPI can easily do better
> without resorting to this pattern: it can send the reply when the
> operation is done. That would make QAPI schema, usage and
> documentation more obvious.
> 
> The following series implements an async solution, by introducing a
> context associated with a command, it can:
> - defer the return
> - return only to the caller (no broadcasted event)

As long as replies/events have ids then clients can discard messages for
ids they do not own.  Let's err on the side of broadcasting so that
clients can receive events after reconnecting to the monitor.

Is there a specific case where broadcasting causes problems?

> - return with the 'id' associated with the call (as originally intended)
> - optionnally allow cancellation when the client is gone
> - track on-going qapi command(s) per client
> 
> 1) 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.
> 
> 2) allow concurrent commands when 'async' is negotiated. If the client
> doesn't support 'async', then the monitor is suspended during command
> execution (events are still sent). Effectively, async commands behave
> like normal commands from client POV in this case, giving full
> backward compatibility.
> 
> 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). HMP remains sync, but it would be worth to make
> it possible to call async:true qapi commands.
> 
> The last patch cleans up qmp_dispatch usage to have consistant checks
> between qga & qemu, and simplify QmpClient/parser_feed usage.
> 
> 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 (25):
>   tests: start generic qemu-qmp tests
>   tests: change /0.15/* tests to /qmp/*
>   qmp: teach qmp_dispatch() to take a pre-filled QDict
>   qmp: use a return callback for the command reply
>   qmp: add QmpClient
>   qmp: add qmp_return_is_cancelled()
>   qmp: introduce async command type
>   qapi: ignore top-level 'id' field
>   qmp: take 'id' from request
>   qmp: check that async command have an 'id'
>   scripts: learn 'async' qapi commands
>   tests: add dispatch async tests
>   monitor: add 'async' capability
>   monitor: add !qmp pre-conditions
>   monitor: suspend when running async and client has no async
>   qmp: update qmp-spec about async capability
>   qtest: add qtest-timeout
>   qtest: add qtest_init_qmp_caps()
>   tests: add tests for async and non-async clients
>   qapi: improve 'screendump' documentation
>   console: graphic_hw_update return true if async
>   console: add graphic_hw_update_done()
>   console: make screendump async
>   qtest: add /qemu-qmp/screendump test
>   qmp: move json-message-parser and check to QmpClient
> 
>  qapi-schema.json                        |  45 +++++-
>  qapi/introspect.json                    |   2 +-
>  scripts/qapi.py                         |  14 +-
>  scripts/qapi-commands.py                | 139 ++++++++++++++---
>  scripts/qapi-introspect.py              |   7 +-
>  hw/display/qxl.h                        |   2 +-
>  include/qapi/qmp/dispatch.h             |  66 +++++++-
>  include/ui/console.h                    |   5 +-
>  tests/libqtest.h                        |   9 ++
>  hmp.c                                   |   2 +-
>  hw/display/qxl-render.c                 |  14 +-
>  hw/display/qxl.c                        |   8 +-
>  monitor.c                               | 213 +++++++++++++-------------
>  qapi/qmp-dispatch.c                     | 260 +++++++++++++++++++++++++++++---
>  qapi/qmp-registry.c                     |  25 ++-
>  qga/main.c                              |  73 ++-------
>  qobject/json-lexer.c                    |   4 +-
>  qtest.c                                 |  48 ++++++
>  tests/libqtest.c                        |  13 +-
>  tests/qmp-test.c                        | 191 +++++++++++++++++++++++
>  tests/test-qmp-commands.c               | 211 ++++++++++++++++++++++----
>  ui/console.c                            |  86 ++++++++++-
>  MAINTAINERS                             |   1 +
>  docs/qmp-spec.txt                       |  48 +++++-
>  tests/Makefile.include                  |   3 +
>  tests/qapi-schema/async.err             |   0
>  tests/qapi-schema/async.exit            |   1 +
>  tests/qapi-schema/async.json            |   6 +
>  tests/qapi-schema/async.out             |  10 ++
>  tests/qapi-schema/qapi-schema-test.json |   6 +
>  tests/qapi-schema/qapi-schema-test.out  |   6 +
>  tests/qapi-schema/test-qapi.py          |   7 +-
>  32 files changed, 1236 insertions(+), 289 deletions(-)
>  create mode 100644 tests/qmp-test.c
>  create mode 100644 tests/qapi-schema/async.err
>  create mode 100644 tests/qapi-schema/async.exit
>  create mode 100644 tests/qapi-schema/async.json
>  create mode 100644 tests/qapi-schema/async.out
> 
> -- 
> 2.11.0.295.gd7dffce1c
> 
> 

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

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-23 10:55 ` Stefan Hajnoczi
@ 2017-01-23 11:27   ` Marc-André Lureau
  2017-01-24 11:43     ` Stefan Hajnoczi
  0 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-23 11:27 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: Marc-André Lureau, qemu-devel, kraxel, armbru, Jeff Cody, John Snow

Hi

----- Original Message -----
> On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> > Hi,
> 
> CCing Jeff Cody and John Snow, who have been working on generalizing
> Block Job APIs to generic background jobs.  There is some overlap
> between async commands and background jobs.

If you say so :) Did I miss a proposal or a discussion for async qmp commands?

> > 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.
> > 
> > Note that qmp events are asynchronous messages, and must be handled
> > appropriately by the client: dispatch both reply and events after a
> > command is sent for example.
> > 
> > The benefits of async commands that can be trade-off depending on the
> > requirements are:
> > 
> > 1) allow 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 tricky
> > (see below) to solve.  Furthermore, many QMP commands do IO and could
> > be considered 'slow' and blocking today.
> > 
> > 2) allow concurrent commands and events. This mainly implies hanlding
> > concurrency in qemu and out-of-order replies for the client. As noted
> > earlier, a good qmp client already has to handle dispatching of
> > received messages (reply and events).
> > 
> > The traditional approach to solving the above in qemu is the following
> > scheme:
> > -> { "execute": "do-foo" }
> > <- { "return": {} }
> > <- { "event": "FOO_DONE" }
> > 
> > It has several flaws:
> > - FOO_DONE event has no semantic link with do-foo in the qapi
> >   schema. It is not simple to generalize that pattern when writing
> >   qmp clients. It makes documentation and usage harder.
> > - the FOO_DONE event has no clear association with the command that
> >   triggered it: commands/events have to come up with additional
> >   specific association schemes (ids, path etc)
> > - FOO_DONE is broadcasted to all clients, but they may have no way to
> >   interprete it or interest in it, or worse it may conflict with their
> >   own commands.
> > - the arguably useless empty reply return
> > 
> > For some cases, it makes sense to use that scheme, or a more complete
> > one: to have an "handler" associated with an on-going operation, that
> > can be queried, modified, cancelled etc (block jobs etc). Also, some
> > operations have a global side-effect, in which case that cmd+event
> > scheme is right, as all clients are listening for global events.
> > 
> > However, for the simple case where a client want to perform a "local
> > context" operation (dump, query etc), QAPI can easily do better
> > without resorting to this pattern: it can send the reply when the
> > operation is done. That would make QAPI schema, usage and
> > documentation more obvious.
> > 
> > The following series implements an async solution, by introducing a
> > context associated with a command, it can:
> > - defer the return
> > - return only to the caller (no broadcasted event)
> 
> As long as replies/events have ids then clients can discard messages for
> ids they do not own.  

There is no guarantee about id conflict between clients, the id is generated by the client, usually with a simple increment. Although we could check for id conflicts in qemu, I think it is unnecessary and costly (for both client & server)

> Let's err on the side of broadcasting so that
> clients can receive events after reconnecting to the monitor.

Sorry, what do you mean?

> Is there a specific case where broadcasting causes problems?

Fortunately, it seems all events today are global state change events, and not command replies (otherwise we could have reply conflicts). It was suggested to me to use the do-foo/FOO_DONE pattern, but it is not suitable for async command replies (see flaws above).

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

* Re: [Qemu-devel] [PATCH v2 23/25] console: make screendump async
  2017-01-20 13:07     ` Marc-André Lureau
@ 2017-01-23 12:04       ` Gerd Hoffmann
  2017-01-23 12:35         ` Marc-André Lureau
  0 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2017-01-23 12:04 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, armbru

  Hi,
> 
> If you only ref, you could have the image being modified while it is
> being saved asynchronously, this could result in tearing artefacts,
> no?

Yes, but you have that problem _anyway_.  screendump qmp command can run
in parallel to guest vcpu, so it can race with guest display updates
today.  Assuming they happen as simple framebuffer writes and therefore
don't involve vmexit + grabbing big qemu lock.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v2 23/25] console: make screendump async
  2017-01-23 12:04       ` Gerd Hoffmann
@ 2017-01-23 12:35         ` Marc-André Lureau
  0 siblings, 0 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-23 12:35 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, armbru, Paolo Bonzini, Daniel P. Berrange

Hi

On Mon, Jan 23, 2017 at 4:04 PM Gerd Hoffmann <kraxel@redhat.com> wrote:

>   Hi,
> >
> > If you only ref, you could have the image being modified while it is
> > being saved asynchronously, this could result in tearing artefacts,
> > no?
>
> Yes, but you have that problem _anyway_.  screendump qmp command can run
> in parallel to guest vcpu, so it can race with guest display updates
> today.  Assuming they happen as simple framebuffer writes and therefore
> don't involve vmexit + grabbing big qemu lock.
>

Agreed, fwiw, I implemented a coroutine-based ppm_save in the qapi-async
branch:
https://github.com/elmarco/qemu/commit/6f45a28ce737eab1d0ce4639f7b015a51a43674c

btw, is it supported to reenter the main_loop in hmp_screendump_sync()
(Paolo)?

(the alternative is probably to block hmp until the async command is
finished. This would eventually be interesting if more qmp commands used
from hmp are converted to be async)
-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-23 11:27   ` Marc-André Lureau
@ 2017-01-24 11:43     ` Stefan Hajnoczi
  2017-01-24 18:43       ` Marc-André Lureau
  0 siblings, 1 reply; 61+ messages in thread
From: Stefan Hajnoczi @ 2017-01-24 11:43 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Marc-André Lureau, qemu-devel, kraxel, armbru, Jeff Cody, John Snow

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

On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> ----- Original Message -----
> > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> > > Hi,
> > 
> > CCing Jeff Cody and John Snow, who have been working on generalizing
> > Block Job APIs to generic background jobs.  There is some overlap
> > between async commands and background jobs.
> 
> If you say so :) Did I miss a proposal or a discussion for async qmp commands?

There is no recent mailing list thread, so it's probably best to discuss
here:

The goal of jobs is to support long-running operations that can be
managed via QMP.  Jobs can have a more elaborate lifecycle than just
start -> finish/cancel (e.g. they can be paused/resumed and may have
multiple phases of execution that the client controls).  There are QMP
APIs to query their state (Are they running?  How much "progress" has
been made?).

A client reconnecting to QEMU can query running jobs.  This way a client
can resume with a running QEMU process.  For commands like saving a
screenshot is mostly does not matter, but for commands that modify state
it's critical that clients are aware of running commands after reconnect
to prevent corruption/interference.  This behavior is what I asked about
in my previous mail.

Jobs are currently only used by the block layer and called "block jobs",
but the idea is to generalize this.  They use synchronous QMP + events.

Jobs are more heavy-weight than async QMP commands, but pause/resume,
rate-limiting, progress reporting, robust reconnect, etc are important
features.  Users want to be aware of long-running operations and have
the ability to control them.

I suspect that if we transition synchronous QMP commands to async we'll
soon have requirements for progress reporting, pause/resume, etc.  So is
there a set of commands that should be async and others that should be
jobs or should everything just be a job?

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

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-24 11:43     ` Stefan Hajnoczi
@ 2017-01-24 18:43       ` Marc-André Lureau
  2017-01-30 13:43         ` Stefan Hajnoczi
  0 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-24 18:43 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: Marc-André Lureau, qemu-devel, kraxel, armbru, Jeff Cody, John Snow

Hi

----- Original Message -----
> On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> > ----- Original Message -----
> > > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> > > > Hi,
> > > 
> > > CCing Jeff Cody and John Snow, who have been working on generalizing
> > > Block Job APIs to generic background jobs.  There is some overlap
> > > between async commands and background jobs.
> > 
> > If you say so :) Did I miss a proposal or a discussion for async qmp
> > commands?
> 
> There is no recent mailing list thread, so it's probably best to discuss
> here:
> 
> The goal of jobs is to support long-running operations that can be
> managed via QMP.  Jobs can have a more elaborate lifecycle than just
> start -> finish/cancel (e.g. they can be paused/resumed and may have
> multiple phases of execution that the client controls).  There are QMP
> APIs to query their state (Are they running?  How much "progress" has
> been made?).

Indeed, I mention that in my cover. Such use cases require something more complete than simple async qmp commands. I don't see why it would be incompatible with the usage of async qmp commands.

> A client reconnecting to QEMU can query running jobs.  This way a client
> can resume with a running QEMU process.  For commands like saving a
> screenshot is mostly does not matter, but for commands that modify state
> it's critical that clients are aware of running commands after reconnect
> to prevent corruption/interference.  This behavior is what I asked about
> in my previous mail.

That's what I mention in the cover, some commands are global (and broadcasted events are appropriate) and some are local to the client context. Some could be discarded when the client disconnects etc. It's a case by case.

> Jobs are currently only used by the block layer and called "block jobs",
> but the idea is to generalize this.  They use synchronous QMP + events.

That pattern will have the flaws I mentioned (empty return, broadcast events, id conflict, qapi semantic & documentation etc). Something new can be invented, but it will likely make the protocol more complicated compared to the solution I proposed (which is optional btw, and gracefully fallbacks to sync processing for clients that do not support the async qmp capability). However, I believe the job interface could be built on top of what I propose.

> Jobs are more heavy-weight than async QMP commands, but pause/resume,
> rate-limiting, progress reporting, robust reconnect, etc are important
> features.  Users want to be aware of long-running operations and have
> the ability to control them.

You can't generalize such job interface to all async commands. Some may not implement the ability to report progress, to cancel, to pause etc, etc. In the end, it will be complicated and unneeded in many cases (what's the use case to pause or to get the progress of a screendump?). What I propose is simpler and compatible with job/task interfaces appropriate for various domains.

> I suspect that if we transition synchronous QMP commands to async we'll
> soon have requirements for progress reporting, pause/resume, etc.  So is
> there a set of commands that should be async and others that should be
> jobs or should everything just be a job?

Hard to say without a concrete proposal of what "job" is. Likely, everything is not going to be a "job".

But hopefully qmp-async and jobs can co-exist and benefit from each other.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (26 preceding siblings ...)
  2017-01-23 10:55 ` Stefan Hajnoczi
@ 2017-01-25 15:16 ` Markus Armbruster
  2017-04-24 19:10   ` Markus Armbruster
  2017-05-04 19:01 ` Markus Armbruster
  28 siblings, 1 reply; 61+ messages in thread
From: Markus Armbruster @ 2017-01-25 15:16 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, kraxel, Jeff Cody, John Snow, Stefan Hajnoczi, Kevin Wolf

Cc'ing block job people.

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

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

Correct.

QMP's initial design stipulated that commands are asynchronous.  The
initial implementation made them all synchronous, with very few
exceptions (buggy ones, to boot).  Naturally, clients relied on the
actual rather than the theoretical behavior, i.e. on getting command
replies synchronously, in order.

> Note that qmp events are asynchronous messages, and must be handled
> appropriately by the client: dispatch both reply and events after a
> command is sent for example.

Yes.

> The benefits of async commands that can be trade-off depending on the
> requirements are:
>
> 1) allow 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 tricky
> (see below) to solve.  Furthermore, many QMP commands do IO and could
> be considered 'slow' and blocking today.
>
> 2) allow concurrent commands and events. This mainly implies hanlding
> concurrency in qemu and out-of-order replies for the client. As noted
> earlier, a good qmp client already has to handle dispatching of
> received messages (reply and events).

We need to distingish two kinds of concurrency.  One, execution of QMP
commands concurrently with other activities in QEMU, including other QMP
monitors.  Two, executing multiple QMP commands concurrently in the same
monitor, which obviously requires all but one of them to be
asynchronous.

> The traditional approach to solving the above in qemu is the following
> scheme:
> -> { "execute": "do-foo" }
> <- { "return": {} }
> <- { "event": "FOO_DONE" }

... where the event may carry additional data, such as the command's
true result.

> It has several flaws:
> - FOO_DONE event has no semantic link with do-foo in the qapi
>   schema. It is not simple to generalize that pattern when writing
>   qmp clients. It makes documentation and usage harder.
> - the FOO_DONE event has no clear association with the command that
>   triggered it: commands/events have to come up with additional
>   specific association schemes (ids, path etc)

Valid points.  Emulating asynchronous commands with a synchronous
command + event isn't quite as simple to specify as a native
asynchronous command could be.

> - FOO_DONE is broadcasted to all clients, but they may have no way to
>   interprete it or interest in it, or worse it may conflict with their
>   own commands.

The part about "no interest" is valid in cases where the event signals
completion of a job without side effects, because then only the job's
initiator cares (the event has to carry a result for this to make
sense).  But when the job has side effects, other clients may want to
know, and broadcast is probably the right thing to do.

We deliberately broadcast events even though some clients may not care
about some of them.  It's the stupidest solution that could possibly
work.  Has never been a problem; clients simply ignore events they don't
need.  If it becomes a problem, we can provide a mechanism to subscribe
to events.  Adds some interface complexity to save a bit of bandwidth.

The part about "conflict due to broadcast" is weak.  To create a
conflict, the interface has to be misdesigned so that events can't be
reliably connected back to their commands.  But then the conflict could
just as well happen between commands issued by a single client.  I think
the valid point here is that synchronous command + event offers an
additional opportunity for screwing up at the command design level.
Perhaps we should do something about it; more on that below.

> - the arguably useless empty reply return

Valid point, but really, really minor.

> For some cases, it makes sense to use that scheme, or a more complete
> one: to have an "handler" associated with an on-going operation, that
> can be queried, modified, cancelled etc (block jobs etc).

Block jobs provide ways to query status and properties, modify
properties, pause, resume, cancel, and initiate synchronous completion.

I suspect that we could use some of these "job control" features for
pretty much any long-running activity.

Migration is such an activity, but uses its own job control interfaces.

We hope to unify both under a more generic "job" abstraction.

>                                                           Also, some
> operations have a global side-effect, in which case that cmd+event
> scheme is right, as all clients are listening for global events.

Yes.

> However, for the simple case where a client want to perform a "local
> context" operation (dump, query etc), QAPI can easily do better
> without resorting to this pattern: it can send the reply when the
> operation is done. That would make QAPI schema, usage and
> documentation more obvious.

On the other hand, it creates a second, independent way to do
asynchronous.

Let me review the design space.

1. Commands are asynchronous

   We still need events to broadcast state changes of interest.

   Commands that complete "quickly" will probably behave synchronously
   anyway, because messing with threads or coroutines would be
   inefficient and needlessly complex then.

   Risk: clients that erroneously rely on synchronous behavior can work
   in simple testing, yet break in entertaining ways under load, or when
   a "quick" command becomes "slow" later on.  Not an argument against
   this design, I'm merely pointing out an opportunity to screw up.  It
   could make evolving de facto synchronous commands into asynchronous
   ones impractical, though.

   We still need job control.  A natural way to do it is to provide job
   control for *any* asynchronous command, i.e. there's no separate
   concept of "jobs", there are just commands that haven't completed,
   yet.  Job control commands simply fail when the asynchronous command
   they target doesn't support them.  I figure only select commands
   support cancellation, for instance.

   Of course, we could also do job control the way we do it now, with a
   separate "job" concept.  You can't evolve a mere command into a job
   then: if you start with a mere command, and it later turns out that
   it can run for a very long time, and you need to be able to cancel
   it, you have to start over: create a new command that creates a job.

   While this feels like a perfectly sensible design to me, we can't
   have it without a massive compatibility break.  Or can we?

2. Commands are synchronous

   This is what we have now.

   Commands that may not complete "quickly" need to be split into a
   command to kick off the job, and an event to signal completion and
   transmit the result.

   If we misjudge "quickly", we have to start over with a new command.
   With 1., we can change the old command from synchronous to
   asynchronous instead, but that risks breaking clients, which may
   force us to start over anyway.

   We currently lack a generic way to connect events back to their
   commands, and instead leave the problem to each command/event pair to
   solve.

   A special case of the command+event pattern is "block jobs".  We'd
   like to evolve them into general job abstraction.  Perhaps any
   (non-deprecated) command/event combo could be an instance of this job
   abstraction.  Such a job abstraction should certainly provide an
   unambiguous connection between event and command.

3. Both

   Existing commands stay synchronous for compatibility.  New commands
   that complete "quickly" are synchronous.  New commands that may not
   complete "quickly" become asynchronous if job control isn't needed,
   else they start jobs.  Having a single job abstraction for them would
   be nice.

   If we misjudge "quickly" or "no need for job control", we have to
   start over with a new command.

   I hope this is a fair description of what you're proposing, please
   correct misunderstandings.

   While I accept your assertion that the commands we can make
   asynchronous would be a bit simpler than their synchronous command +
   event equivalent, I'm afraid adding them to what we have now merely
   moves the complexity around: three kinds of commands (quick,
   command+event, async) instead of two.  Whether that's a net win is
   unclear.  I doubt it.

I'm pretty confident adding a suitable jobs abstraction can make 2. work
reasonably well.

I can't quite see how we can get from here to 1., but perhaps you can
show us.

I strongly dislike the lack of orthogonality in 3.

> The following series implements an async solution, by introducing a
> context associated with a command, it can:
> - defer the return
> - return only to the caller (no broadcasted event)
> - return with the 'id' associated with the call (as originally intended)

Context: 'id' is passed by the client with the command.

As you mentioned elsewhere in this thread, 'id' could conceivably
ambiguous with multiple QMP monitors.  One way to disambiguate is
including a monitor-id that uniquely identifies the monitor where 'id'
comes from.

> - optionnally allow cancellation when the client is gone
> - track on-going qapi command(s) per client

Inching towards job control...

> 1) existing qemu commands can be gradually replaced by async:true
> variants when needed, and by carefully reviewing the concurrency
> aspects.

It's a behavioral change that can conceivably break clients, so
"reviewing the concurrency aspects" includes reviewing all clients, I'm
afraid.  I'm not saying it's impossible, but I'm not exactly looking
forward to it.

>          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.
>
> 2) allow concurrent commands when 'async' is negotiated. If the client
> doesn't support 'async', then the monitor is suspended during command
> execution (events are still sent). Effectively, async commands behave
> like normal commands from client POV in this case, giving full
> backward compatibility.

Aha.  Okay, that makes it more practical.  Converting to async can break
a client even when it claims to support async, but I guess it's less
likely.

> 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). HMP remains sync, but it would be worth to make
> it possible to call async:true qapi commands.
>
> The last patch cleans up qmp_dispatch usage to have consistant checks
> between qga & qemu, and simplify QmpClient/parser_feed usage.

I'm afraid I lack the time to review your actual patches in a reasonable
time frame; I really need to hunker down and deliver the QemuOpts / QAPI
work I promised for 2.9, or else my block friends will be sad, Dan
Berrange will be sad, and my manager will be sad, too.  This is
unfortunate.  More so since your proposal has been pending for so long.
My sincere apologies.

Let's at least use the time to discuss the design, in particular how it
relates to the work on evolving block jobs into a generic jobs
abstraction.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-24 18:43       ` Marc-André Lureau
@ 2017-01-30 13:43         ` Stefan Hajnoczi
  2017-01-30 18:18           ` Marc-André Lureau
  0 siblings, 1 reply; 61+ messages in thread
From: Stefan Hajnoczi @ 2017-01-30 13:43 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Marc-André Lureau, qemu-devel, kraxel, armbru, Jeff Cody, John Snow

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

On Tue, Jan 24, 2017 at 01:43:17PM -0500, Marc-André Lureau wrote:
> Hi
> 
> ----- Original Message -----
> > On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> > > ----- Original Message -----
> > > > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> > > > > Hi,
> > > > 
> > > > CCing Jeff Cody and John Snow, who have been working on generalizing
> > > > Block Job APIs to generic background jobs.  There is some overlap
> > > > between async commands and background jobs.
> > > 
> > > If you say so :) Did I miss a proposal or a discussion for async qmp
> > > commands?
> > 
> > There is no recent mailing list thread, so it's probably best to discuss
> > here:
> > 
> > The goal of jobs is to support long-running operations that can be
> > managed via QMP.  Jobs can have a more elaborate lifecycle than just
> > start -> finish/cancel (e.g. they can be paused/resumed and may have
> > multiple phases of execution that the client controls).  There are QMP
> > APIs to query their state (Are they running?  How much "progress" has
> > been made?).
> 
> Indeed, I mention that in my cover. Such use cases require something more complete than simple async qmp commands. I don't see why it would be incompatible with the usage of async qmp commands.
> 
> > A client reconnecting to QEMU can query running jobs.  This way a client
> > can resume with a running QEMU process.  For commands like saving a
> > screenshot is mostly does not matter, but for commands that modify state
> > it's critical that clients are aware of running commands after reconnect
> > to prevent corruption/interference.  This behavior is what I asked about
> > in my previous mail.
> 
> That's what I mention in the cover, some commands are global (and broadcasted events are appropriate) and some are local to the client context. Some could be discarded when the client disconnects etc. It's a case by case.
> 
> > Jobs are currently only used by the block layer and called "block jobs",
> > but the idea is to generalize this.  They use synchronous QMP + events.
> 
> That pattern will have the flaws I mentioned (empty return, broadcast events, id conflict, qapi semantic & documentation etc). Something new can be invented, but it will likely make the protocol more complicated compared to the solution I proposed (which is optional btw, and gracefully fallbacks to sync processing for clients that do not support the async qmp capability). However, I believe the job interface could be built on top of what I propose.
> 
> > Jobs are more heavy-weight than async QMP commands, but pause/resume,
> > rate-limiting, progress reporting, robust reconnect, etc are important
> > features.  Users want to be aware of long-running operations and have
> > the ability to control them.
> 
> You can't generalize such job interface to all async commands. Some may not implement the ability to report progress, to cancel, to pause etc, etc. In the end, it will be complicated and unneeded in many cases (what's the use case to pause or to get the progress of a screendump?). What I propose is simpler and compatible with job/task interfaces appropriate for various domains.
> 
> > I suspect that if we transition synchronous QMP commands to async we'll
> > soon have requirements for progress reporting, pause/resume, etc.  So is
> > there a set of commands that should be async and others that should be
> > jobs or should everything just be a job?
> 
> Hard to say without a concrete proposal of what "job" is. Likely, everything is not going to be a "job".
> 
> But hopefully qmp-async and jobs can co-exist and benefit from each other.

My concern with this series is that background operations must be
observable and there must be a way to cancel them.  Otherwise management
tools cannot do their job and it's hard to troubleshoot a misbehaving
system because you can't answer the question "what's going on?".  Once
you add that then a large chunk of block jobs is duplicated.

So then you look at block jobs and realize that no QMP wire protocol
changes are necessary.  Despite the limitations you've listed, block
jobs have been working successfully for years and don't require QMP
clients to change.

I agree that not all background operations need to support the same set
of management primitives to rate-limit, report progress, cancel,
pause/resume, etc.

It would be nice for this series to evolve to a generic QMP jobs series
so that all background operations are visible to the client and a useful
subset of management primitives can be implemented on a per-command
basis.  Both live migration and existing block jobs could use this code
so that we don't have multiple copies of the same infrastructure.

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 v2 00/25] qmp: add async command type
  2017-01-30 13:43         ` Stefan Hajnoczi
@ 2017-01-30 18:18           ` Marc-André Lureau
  2017-01-31  7:43             ` Gerd Hoffmann
  2017-02-01 16:25             ` Stefan Hajnoczi
  0 siblings, 2 replies; 61+ messages in thread
From: Marc-André Lureau @ 2017-01-30 18:18 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: Marc-André Lureau, qemu-devel, kraxel, armbru, Jeff Cody, John Snow

Hi

----- Original Message -----
> On Tue, Jan 24, 2017 at 01:43:17PM -0500, Marc-André Lureau wrote:
> > Hi
> > 
> > ----- Original Message -----
> > > On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> > > > ----- Original Message -----
> > > > > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> > > > > > Hi,
> > > > > 
> > > > > CCing Jeff Cody and John Snow, who have been working on generalizing
> > > > > Block Job APIs to generic background jobs.  There is some overlap
> > > > > between async commands and background jobs.
> > > > 
> > > > If you say so :) Did I miss a proposal or a discussion for async qmp
> > > > commands?
> > > 
> > > There is no recent mailing list thread, so it's probably best to discuss
> > > here:
> > > 
> > > The goal of jobs is to support long-running operations that can be
> > > managed via QMP.  Jobs can have a more elaborate lifecycle than just
> > > start -> finish/cancel (e.g. they can be paused/resumed and may have
> > > multiple phases of execution that the client controls).  There are QMP
> > > APIs to query their state (Are they running?  How much "progress" has
> > > been made?).
> > 
> > Indeed, I mention that in my cover. Such use cases require something more
> > complete than simple async qmp commands. I don't see why it would be
> > incompatible with the usage of async qmp commands.
> > 
> > > A client reconnecting to QEMU can query running jobs.  This way a client
> > > can resume with a running QEMU process.  For commands like saving a
> > > screenshot is mostly does not matter, but for commands that modify state
> > > it's critical that clients are aware of running commands after reconnect
> > > to prevent corruption/interference.  This behavior is what I asked about
> > > in my previous mail.
> > 
> > That's what I mention in the cover, some commands are global (and
> > broadcasted events are appropriate) and some are local to the client
> > context. Some could be discarded when the client disconnects etc. It's a
> > case by case.
> > 
> > > Jobs are currently only used by the block layer and called "block jobs",
> > > but the idea is to generalize this.  They use synchronous QMP + events.
> > 
> > That pattern will have the flaws I mentioned (empty return, broadcast
> > events, id conflict, qapi semantic & documentation etc). Something new can
> > be invented, but it will likely make the protocol more complicated
> > compared to the solution I proposed (which is optional btw, and gracefully
> > fallbacks to sync processing for clients that do not support the async qmp
> > capability). However, I believe the job interface could be built on top of
> > what I propose.
> > 
> > > Jobs are more heavy-weight than async QMP commands, but pause/resume,
> > > rate-limiting, progress reporting, robust reconnect, etc are important
> > > features.  Users want to be aware of long-running operations and have
> > > the ability to control them.
> > 
> > You can't generalize such job interface to all async commands. Some may not
> > implement the ability to report progress, to cancel, to pause etc, etc. In
> > the end, it will be complicated and unneeded in many cases (what's the use
> > case to pause or to get the progress of a screendump?). What I propose is
> > simpler and compatible with job/task interfaces appropriate for various
> > domains.
> > 
> > > I suspect that if we transition synchronous QMP commands to async we'll
> > > soon have requirements for progress reporting, pause/resume, etc.  So is
> > > there a set of commands that should be async and others that should be
> > > jobs or should everything just be a job?
> > 
> > Hard to say without a concrete proposal of what "job" is. Likely,
> > everything is not going to be a "job".
> > 
> > But hopefully qmp-async and jobs can co-exist and benefit from each other.
> 
> My concern with this series is that background operations must be
> observable and there must be a way to cancel them.  Otherwise management
> tools cannot do their job and it's hard to troubleshoot a misbehaving
> system because you can't answer the question "what's going on?".  Once
> you add that then a large chunk of block jobs is duplicated.

Tracking ongoing operations can also be done at management layer. If needed, we could add qmp-commands to list on-going commands (their ids etc), and add commands to cancel them. But then again, not all operations will be cancellable, and I am not sure having requirements to list or cancel or modify all on-going operation is needed (I would say no, just like today you can't do anything while a command is running)

> 
> So then you look at block jobs and realize that no QMP wire protocol
> changes are necessary.  Despite the limitations you've listed, block
> jobs have been working successfully for years and don't require QMP
> clients to change.

Right, but we have existing bugs with functions that need to be async, at least at the qemu level. My proposal fixes this and optionally also allows commands to be async at the qmp level to solve the limitations and issues I listed.

> 
> I agree that not all background operations need to support the same set
> of management primitives to rate-limit, report progress, cancel,
> pause/resume, etc.
> 
> It would be nice for this series to evolve to a generic QMP jobs series
> so that all background operations are visible to the client and a useful
> subset of management primitives can be implemented on a per-command
> basis.  Both live migration and existing block jobs could use this code
> so that we don't have multiple copies of the same infrastructure.

Indeed, but I would need to know what proposal or requirements the block layer have here, and I would appreciate if they took time to review mine. 

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-30 18:18           ` Marc-André Lureau
@ 2017-01-31  7:43             ` Gerd Hoffmann
  2017-01-31  8:18               ` Markus Armbruster
  2017-02-01 16:25             ` Stefan Hajnoczi
  1 sibling, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2017-01-31  7:43 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Stefan Hajnoczi, Marc-André Lureau, qemu-devel, armbru,
	Jeff Cody, John Snow

  Hi,

> > It would be nice for this series to evolve to a generic QMP jobs series
> > so that all background operations are visible to the client and a useful
> > subset of management primitives can be implemented on a per-command
> > basis.  Both live migration and existing block jobs could use this code
> > so that we don't have multiple copies of the same infrastructure.
> 
> Indeed, but I would need to know what proposal or requirements the
> block layer have here, and I would appreciate if they took time to
> review mine. 

Disclaimer:  Havn't looked into the qmp (especially block jobs) details
too much.

But I suspect we can have both, sharing most of the infrastructure,
without too much effort.

We have block jobs today.  Other areas in qemu can use that too.  So
moving the jobs infrastructure from block to qmp level makes perfect
sense to me.  Live migration and possibly others can start using it.

And once we have that building async commands on top of that is probably
easy.  It'll be just a primitive job which typically takes at most a few
seconds to finish, has no ->cancel() callback and sends a different kind
of completion notification ...

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-31  7:43             ` Gerd Hoffmann
@ 2017-01-31  8:18               ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2017-01-31  8:18 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Marc-André Lureau, Stefan Hajnoczi, Jeff Cody, qemu-devel,
	Marc-André Lureau, John Snow

Gerd Hoffmann <kraxel@redhat.com> writes:

>   Hi,
>
>> > It would be nice for this series to evolve to a generic QMP jobs series
>> > so that all background operations are visible to the client and a useful
>> > subset of management primitives can be implemented on a per-command
>> > basis.  Both live migration and existing block jobs could use this code
>> > so that we don't have multiple copies of the same infrastructure.
>> 
>> Indeed, but I would need to know what proposal or requirements the
>> block layer have here, and I would appreciate if they took time to
>> review mine. 
>
> Disclaimer:  Havn't looked into the qmp (especially block jobs) details
> too much.
>
> But I suspect we can have both, sharing most of the infrastructure,
> without too much effort.
>
> We have block jobs today.  Other areas in qemu can use that too.  So
> moving the jobs infrastructure from block to qmp level makes perfect
> sense to me.  Live migration and possibly others can start using it.

Yes.  When everything uses a generic job infrastructure instead of
rolling their own, things get simpler and more regular.  Should take
less code, too, although backward compatibility might thwart that to a
degree.

> And once we have that building async commands on top of that is probably
> easy.  It'll be just a primitive job which typically takes at most a few
> seconds to finish, has no ->cancel() callback and sends a different kind
> of completion notification ...

Plausible.  "Can" doesn't imply "should", of course.

Here's my current thinking:

* "Jobs" are a generalization of the ad hoc ways we do long-running
  activities, including "block jobs" and migration.  Having one general
  way to do a common, non-trivial thing makes sense.

* Block people have wanted "jobs" for quite a while.  The limitations of
  the existing "block jobs" are getting painful.

* Given this "jobs" concept, asynchronous commands are a degenerate case
  of it.  Whether they are a common case, I can't say, yet.  How the
  special case fits into the whole, and whether it's worth having needs
  to be evaluated.

* Like Gerd, I think we should do jobs first.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-30 18:18           ` Marc-André Lureau
  2017-01-31  7:43             ` Gerd Hoffmann
@ 2017-02-01 16:25             ` Stefan Hajnoczi
  2017-02-01 20:25               ` Marc-André Lureau
  1 sibling, 1 reply; 61+ messages in thread
From: Stefan Hajnoczi @ 2017-02-01 16:25 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Marc-André Lureau, qemu-devel, kraxel, armbru, Jeff Cody, John Snow

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

On Mon, Jan 30, 2017 at 01:18:16PM -0500, Marc-André Lureau wrote:
> Hi
> 
> ----- Original Message -----
> > On Tue, Jan 24, 2017 at 01:43:17PM -0500, Marc-André Lureau wrote:
> > > Hi
> > > 
> > > ----- Original Message -----
> > > > On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> > > > > ----- Original Message -----
> > > > > > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau wrote:
> > > > > > > Hi,
> > > > > > 
> > > > > > CCing Jeff Cody and John Snow, who have been working on generalizing
> > > > > > Block Job APIs to generic background jobs.  There is some overlap
> > > > > > between async commands and background jobs.
> > > > > 
> > > > > If you say so :) Did I miss a proposal or a discussion for async qmp
> > > > > commands?
> > > > 
> > > > There is no recent mailing list thread, so it's probably best to discuss
> > > > here:
> > > > 
> > > > The goal of jobs is to support long-running operations that can be
> > > > managed via QMP.  Jobs can have a more elaborate lifecycle than just
> > > > start -> finish/cancel (e.g. they can be paused/resumed and may have
> > > > multiple phases of execution that the client controls).  There are QMP
> > > > APIs to query their state (Are they running?  How much "progress" has
> > > > been made?).
> > > 
> > > Indeed, I mention that in my cover. Such use cases require something more
> > > complete than simple async qmp commands. I don't see why it would be
> > > incompatible with the usage of async qmp commands.
> > > 
> > > > A client reconnecting to QEMU can query running jobs.  This way a client
> > > > can resume with a running QEMU process.  For commands like saving a
> > > > screenshot is mostly does not matter, but for commands that modify state
> > > > it's critical that clients are aware of running commands after reconnect
> > > > to prevent corruption/interference.  This behavior is what I asked about
> > > > in my previous mail.
> > > 
> > > That's what I mention in the cover, some commands are global (and
> > > broadcasted events are appropriate) and some are local to the client
> > > context. Some could be discarded when the client disconnects etc. It's a
> > > case by case.
> > > 
> > > > Jobs are currently only used by the block layer and called "block jobs",
> > > > but the idea is to generalize this.  They use synchronous QMP + events.
> > > 
> > > That pattern will have the flaws I mentioned (empty return, broadcast
> > > events, id conflict, qapi semantic & documentation etc). Something new can
> > > be invented, but it will likely make the protocol more complicated
> > > compared to the solution I proposed (which is optional btw, and gracefully
> > > fallbacks to sync processing for clients that do not support the async qmp
> > > capability). However, I believe the job interface could be built on top of
> > > what I propose.
> > > 
> > > > Jobs are more heavy-weight than async QMP commands, but pause/resume,
> > > > rate-limiting, progress reporting, robust reconnect, etc are important
> > > > features.  Users want to be aware of long-running operations and have
> > > > the ability to control them.
> > > 
> > > You can't generalize such job interface to all async commands. Some may not
> > > implement the ability to report progress, to cancel, to pause etc, etc. In
> > > the end, it will be complicated and unneeded in many cases (what's the use
> > > case to pause or to get the progress of a screendump?). What I propose is
> > > simpler and compatible with job/task interfaces appropriate for various
> > > domains.
> > > 
> > > > I suspect that if we transition synchronous QMP commands to async we'll
> > > > soon have requirements for progress reporting, pause/resume, etc.  So is
> > > > there a set of commands that should be async and others that should be
> > > > jobs or should everything just be a job?
> > > 
> > > Hard to say without a concrete proposal of what "job" is. Likely,
> > > everything is not going to be a "job".
> > > 
> > > But hopefully qmp-async and jobs can co-exist and benefit from each other.
> > 
> > My concern with this series is that background operations must be
> > observable and there must be a way to cancel them.  Otherwise management
> > tools cannot do their job and it's hard to troubleshoot a misbehaving
> > system because you can't answer the question "what's going on?".  Once
> > you add that then a large chunk of block jobs is duplicated.
> 
> Tracking ongoing operations can also be done at management layer. If needed, we could add qmp-commands to list on-going commands (their ids etc), and add commands to cancel them. But then again, not all operations will be cancellable, and I am not sure having requirements to list or cancel or modify all on-going operation is needed (I would say no, just like today you can't do anything while a command is running)

It cannot be done by robustly by the client.  If the client crashes then
there's no way of knowing what pending commands are running.  Requiring
the client to keep a journal would force every client that wants to be
robust and easy to troubleshoot to duplicate this and IMO isn't a
solution.

QEMU knows which commands are in-flight, it should be able to report
this info.  It's important for troubleshooting.

I agree that it's not important today since only one command runs at a
time (except block jobs and migration, which do have commands to query
their status).  But the nature of async commands means that they can run
in the background for a long time, so it will be necessary.

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 v2 00/25] qmp: add async command type
  2017-02-01 16:25             ` Stefan Hajnoczi
@ 2017-02-01 20:25               ` Marc-André Lureau
  2017-02-02 10:13                 ` Stefan Hajnoczi
  0 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-02-01 20:25 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Jeff Cody, qemu-devel, armbru, kraxel, John Snow

Hi

On Wed, Feb 1, 2017 at 8:26 PM Stefan Hajnoczi <stefanha@gmail.com> wrote:

> On Mon, Jan 30, 2017 at 01:18:16PM -0500, Marc-André Lureau wrote:
> > Hi
> >
> > ----- Original Message -----
> > > On Tue, Jan 24, 2017 at 01:43:17PM -0500, Marc-André Lureau wrote:
> > > > Hi
> > > >
> > > > ----- Original Message -----
> > > > > On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> > > > > > ----- Original Message -----
> > > > > > > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau
> wrote:
> > > > > > > > Hi,
> > > > > > >
> > > > > > > CCing Jeff Cody and John Snow, who have been working on
> generalizing
> > > > > > > Block Job APIs to generic background jobs.  There is some
> overlap
> > > > > > > between async commands and background jobs.
> > > > > >
> > > > > > If you say so :) Did I miss a proposal or a discussion for async
> qmp
> > > > > > commands?
> > > > >
> > > > > There is no recent mailing list thread, so it's probably best to
> discuss
> > > > > here:
> > > > >
> > > > > The goal of jobs is to support long-running operations that can be
> > > > > managed via QMP.  Jobs can have a more elaborate lifecycle than
> just
> > > > > start -> finish/cancel (e.g. they can be paused/resumed and may
> have
> > > > > multiple phases of execution that the client controls).  There are
> QMP
> > > > > APIs to query their state (Are they running?  How much "progress"
> has
> > > > > been made?).
> > > >
> > > > Indeed, I mention that in my cover. Such use cases require something
> more
> > > > complete than simple async qmp commands. I don't see why it would be
> > > > incompatible with the usage of async qmp commands.
> > > >
> > > > > A client reconnecting to QEMU can query running jobs.  This way a
> client
> > > > > can resume with a running QEMU process.  For commands like saving a
> > > > > screenshot is mostly does not matter, but for commands that modify
> state
> > > > > it's critical that clients are aware of running commands after
> reconnect
> > > > > to prevent corruption/interference.  This behavior is what I asked
> about
> > > > > in my previous mail.
> > > >
> > > > That's what I mention in the cover, some commands are global (and
> > > > broadcasted events are appropriate) and some are local to the client
> > > > context. Some could be discarded when the client disconnects etc.
> It's a
> > > > case by case.
> > > >
> > > > > Jobs are currently only used by the block layer and called "block
> jobs",
> > > > > but the idea is to generalize this.  They use synchronous QMP +
> events.
> > > >
> > > > That pattern will have the flaws I mentioned (empty return, broadcast
> > > > events, id conflict, qapi semantic & documentation etc). Something
> new can
> > > > be invented, but it will likely make the protocol more complicated
> > > > compared to the solution I proposed (which is optional btw, and
> gracefully
> > > > fallbacks to sync processing for clients that do not support the
> async qmp
> > > > capability). However, I believe the job interface could be built on
> top of
> > > > what I propose.
> > > >
> > > > > Jobs are more heavy-weight than async QMP commands, but
> pause/resume,
> > > > > rate-limiting, progress reporting, robust reconnect, etc are
> important
> > > > > features.  Users want to be aware of long-running operations and
> have
> > > > > the ability to control them.
> > > >
> > > > You can't generalize such job interface to all async commands. Some
> may not
> > > > implement the ability to report progress, to cancel, to pause etc,
> etc. In
> > > > the end, it will be complicated and unneeded in many cases (what's
> the use
> > > > case to pause or to get the progress of a screendump?). What I
> propose is
> > > > simpler and compatible with job/task interfaces appropriate for
> various
> > > > domains.
> > > >
> > > > > I suspect that if we transition synchronous QMP commands to async
> we'll
> > > > > soon have requirements for progress reporting, pause/resume, etc.
> So is
> > > > > there a set of commands that should be async and others that
> should be
> > > > > jobs or should everything just be a job?
> > > >
> > > > Hard to say without a concrete proposal of what "job" is. Likely,
> > > > everything is not going to be a "job".
> > > >
> > > > But hopefully qmp-async and jobs can co-exist and benefit from each
> other.
> > >
> > > My concern with this series is that background operations must be
> > > observable and there must be a way to cancel them.  Otherwise
> management
> > > tools cannot do their job and it's hard to troubleshoot a misbehaving
> > > system because you can't answer the question "what's going on?".  Once
> > > you add that then a large chunk of block jobs is duplicated.
> >
> > Tracking ongoing operations can also be done at management layer. If
> needed, we could add qmp-commands to list on-going commands (their ids
> etc), and add commands to cancel them. But then again, not all operations
> will be cancellable, and I am not sure having requirements to list or
> cancel or modify all on-going operation is needed (I would say no, just
> like today you can't do anything while a command is running)
>
> It cannot be done by robustly by the client.  If the client crashes then
> there's no way of knowing what pending commands are running.  Requiring
> the client to keep a journal would force every client that wants to be
> robust and easy to troubleshoot to duplicate this and IMO isn't a
> solution.
>
>
My proposal allows for commands to be cancelled when the client is gone.
And we can quite easily provide a qmp command to list on-going commands, I
can add a patch for that.

There is no per-client context as of today, so recovering from on-going job
would conflict with other clients (there is no per client id or job-id
namespace neither). I don't know if there is a way to enforce only a single
qmp client today, I would have to check.

QEMU knows which commands are in-flight, it should be able to report
> this info.  It's important for troubleshooting.
>
> I agree that it's not important today since only one command runs at a
> time (except block jobs and migration, which do have commands to query
> their status).  But the nature of async commands means that they can run
> in the background for a long time, so it will be necessary.
>
>
If needed, it can be added with this proposal. I will add a
proof-of-concept patch in the next iteration.

thanks
-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-02-01 20:25               ` Marc-André Lureau
@ 2017-02-02 10:13                 ` Stefan Hajnoczi
  0 siblings, 0 replies; 61+ messages in thread
From: Stefan Hajnoczi @ 2017-02-02 10:13 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: Jeff Cody, qemu-devel, armbru, kraxel, John Snow

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

On Wed, Feb 01, 2017 at 08:25:10PM +0000, Marc-André Lureau wrote:
> Hi
> 
> On Wed, Feb 1, 2017 at 8:26 PM Stefan Hajnoczi <stefanha@gmail.com> wrote:
> 
> > On Mon, Jan 30, 2017 at 01:18:16PM -0500, Marc-André Lureau wrote:
> > > Hi
> > >
> > > ----- Original Message -----
> > > > On Tue, Jan 24, 2017 at 01:43:17PM -0500, Marc-André Lureau wrote:
> > > > > Hi
> > > > >
> > > > > ----- Original Message -----
> > > > > > On Mon, Jan 23, 2017 at 06:27:29AM -0500, Marc-André Lureau wrote:
> > > > > > > ----- Original Message -----
> > > > > > > > On Wed, Jan 18, 2017 at 08:03:07PM +0400, Marc-André Lureau
> > wrote:
> > > > > > > > > Hi,
> > > > > > > >
> > > > > > > > CCing Jeff Cody and John Snow, who have been working on
> > generalizing
> > > > > > > > Block Job APIs to generic background jobs.  There is some
> > overlap
> > > > > > > > between async commands and background jobs.
> > > > > > >
> > > > > > > If you say so :) Did I miss a proposal or a discussion for async
> > qmp
> > > > > > > commands?
> > > > > >
> > > > > > There is no recent mailing list thread, so it's probably best to
> > discuss
> > > > > > here:
> > > > > >
> > > > > > The goal of jobs is to support long-running operations that can be
> > > > > > managed via QMP.  Jobs can have a more elaborate lifecycle than
> > just
> > > > > > start -> finish/cancel (e.g. they can be paused/resumed and may
> > have
> > > > > > multiple phases of execution that the client controls).  There are
> > QMP
> > > > > > APIs to query their state (Are they running?  How much "progress"
> > has
> > > > > > been made?).
> > > > >
> > > > > Indeed, I mention that in my cover. Such use cases require something
> > more
> > > > > complete than simple async qmp commands. I don't see why it would be
> > > > > incompatible with the usage of async qmp commands.
> > > > >
> > > > > > A client reconnecting to QEMU can query running jobs.  This way a
> > client
> > > > > > can resume with a running QEMU process.  For commands like saving a
> > > > > > screenshot is mostly does not matter, but for commands that modify
> > state
> > > > > > it's critical that clients are aware of running commands after
> > reconnect
> > > > > > to prevent corruption/interference.  This behavior is what I asked
> > about
> > > > > > in my previous mail.
> > > > >
> > > > > That's what I mention in the cover, some commands are global (and
> > > > > broadcasted events are appropriate) and some are local to the client
> > > > > context. Some could be discarded when the client disconnects etc.
> > It's a
> > > > > case by case.
> > > > >
> > > > > > Jobs are currently only used by the block layer and called "block
> > jobs",
> > > > > > but the idea is to generalize this.  They use synchronous QMP +
> > events.
> > > > >
> > > > > That pattern will have the flaws I mentioned (empty return, broadcast
> > > > > events, id conflict, qapi semantic & documentation etc). Something
> > new can
> > > > > be invented, but it will likely make the protocol more complicated
> > > > > compared to the solution I proposed (which is optional btw, and
> > gracefully
> > > > > fallbacks to sync processing for clients that do not support the
> > async qmp
> > > > > capability). However, I believe the job interface could be built on
> > top of
> > > > > what I propose.
> > > > >
> > > > > > Jobs are more heavy-weight than async QMP commands, but
> > pause/resume,
> > > > > > rate-limiting, progress reporting, robust reconnect, etc are
> > important
> > > > > > features.  Users want to be aware of long-running operations and
> > have
> > > > > > the ability to control them.
> > > > >
> > > > > You can't generalize such job interface to all async commands. Some
> > may not
> > > > > implement the ability to report progress, to cancel, to pause etc,
> > etc. In
> > > > > the end, it will be complicated and unneeded in many cases (what's
> > the use
> > > > > case to pause or to get the progress of a screendump?). What I
> > propose is
> > > > > simpler and compatible with job/task interfaces appropriate for
> > various
> > > > > domains.
> > > > >
> > > > > > I suspect that if we transition synchronous QMP commands to async
> > we'll
> > > > > > soon have requirements for progress reporting, pause/resume, etc.
> > So is
> > > > > > there a set of commands that should be async and others that
> > should be
> > > > > > jobs or should everything just be a job?
> > > > >
> > > > > Hard to say without a concrete proposal of what "job" is. Likely,
> > > > > everything is not going to be a "job".
> > > > >
> > > > > But hopefully qmp-async and jobs can co-exist and benefit from each
> > other.
> > > >
> > > > My concern with this series is that background operations must be
> > > > observable and there must be a way to cancel them.  Otherwise
> > management
> > > > tools cannot do their job and it's hard to troubleshoot a misbehaving
> > > > system because you can't answer the question "what's going on?".  Once
> > > > you add that then a large chunk of block jobs is duplicated.
> > >
> > > Tracking ongoing operations can also be done at management layer. If
> > needed, we could add qmp-commands to list on-going commands (their ids
> > etc), and add commands to cancel them. But then again, not all operations
> > will be cancellable, and I am not sure having requirements to list or
> > cancel or modify all on-going operation is needed (I would say no, just
> > like today you can't do anything while a command is running)
> >
> > It cannot be done by robustly by the client.  If the client crashes then
> > there's no way of knowing what pending commands are running.  Requiring
> > the client to keep a journal would force every client that wants to be
> > robust and easy to troubleshoot to duplicate this and IMO isn't a
> > solution.
> >
> >
> My proposal allows for commands to be cancelled when the client is gone.
> And we can quite easily provide a qmp command to list on-going commands, I
> can add a patch for that.
> 
> There is no per-client context as of today, so recovering from on-going job
> would conflict with other clients (there is no per client id or job-id
> namespace neither). I don't know if there is a way to enforce only a single
> qmp client today, I would have to check.
> 
> QEMU knows which commands are in-flight, it should be able to report
> > this info.  It's important for troubleshooting.
> >
> > I agree that it's not important today since only one command runs at a
> > time (except block jobs and migration, which do have commands to query
> > their status).  But the nature of async commands means that they can run
> > in the background for a long time, so it will be necessary.
> >
> >
> If needed, it can be added with this proposal. I will add a
> proof-of-concept patch in the next iteration.

Great.

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 v2 00/25] qmp: add async command type
  2017-01-25 15:16 ` Markus Armbruster
@ 2017-04-24 19:10   ` Markus Armbruster
  2017-04-25  0:06     ` John Snow
                       ` (2 more replies)
  0 siblings, 3 replies; 61+ messages in thread
From: Markus Armbruster @ 2017-04-24 19:10 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, kraxel, Jeff Cody, John Snow, Stefan Hajnoczi, Kevin Wolf

With 2.9 out of the way, how can we make progress on this one?

I can see two ways to get asynchronous QMP commands accepted:

1. We break QMP compatibility in QEMU 3.0 and convert all long-running
   tasks from "synchronous command + event" to "asynchronous command".

   This is design option 1 quoted below.  *If* we decide to leave
   compatibility behind for 3.0, *and* we decide we like the
   asynchronous sufficiently better to put in the work, we can do it.

   I guess there's nothing to do here until we decide on breaking
   compatibility in 3.0.

2. We don't break QMP compatibility, but we add asynchronous commands
   anyway, because we decide that's how we want to do "jobs".

   This is design option 3 quoted below.  As I said, I dislike its lack
   of orthogonality.  But if asynchronous commands help us get jobs
   done, I can bury my dislike.

   I feel this is something you should investigate with John Snow.
   Going through a middleman (me) makes no sense.  So I'm going to dump
   my thoughts, then get out of the way.

   You need to take care not to get bogged down in the jobs project's
   complexity.  This is really only how to package up jobs for QMP.

   With synchronous commands, the job-creating command creates a job,
   jobs state changes trigger events, and job termination is just
   another state change.  Job control commands interact with the job.
 
   Events obviously need to carry a job ID.  We can either require the
   user to pass it as argument to the job-creating command (hopefully
   unique), or have the job-creating command pick one (a unique one) and
   return it.

   With asynchronous commands, we could make the asynchronous command
   the job.  The only difference is that job termination triggers the
   command response.  When termination is of no interest to anyone but
   the job's creator, the termination event can be omitted then.

   Instead of a job ID, we could use the (user-specified and hopefully
   unique) command ID that ties the command response to the command.
   Perhaps throw in a monitor ID.

   To be honest, I'm not sure asynchronous commands buy us much here.
   But my view is from 10,000 feet, and John might have different ideas.

Rejecting asynchronous QMP commands is of course design option 2 quoted
below.


Markus Armbruster <armbru@redhat.com> writes:

> Cc'ing block job people.
>
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> 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.
>
> Correct.
>
> QMP's initial design stipulated that commands are asynchronous.  The
> initial implementation made them all synchronous, with very few
> exceptions (buggy ones, to boot).  Naturally, clients relied on the
> actual rather than the theoretical behavior, i.e. on getting command
> replies synchronously, in order.
>
>> Note that qmp events are asynchronous messages, and must be handled
>> appropriately by the client: dispatch both reply and events after a
>> command is sent for example.
>
> Yes.
>
>> The benefits of async commands that can be trade-off depending on the
>> requirements are:
>>
>> 1) allow 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 tricky
>> (see below) to solve.  Furthermore, many QMP commands do IO and could
>> be considered 'slow' and blocking today.
>>
>> 2) allow concurrent commands and events. This mainly implies hanlding
>> concurrency in qemu and out-of-order replies for the client. As noted
>> earlier, a good qmp client already has to handle dispatching of
>> received messages (reply and events).
>
> We need to distingish two kinds of concurrency.  One, execution of QMP
> commands concurrently with other activities in QEMU, including other QMP
> monitors.  Two, executing multiple QMP commands concurrently in the same
> monitor, which obviously requires all but one of them to be
> asynchronous.
>
>> The traditional approach to solving the above in qemu is the following
>> scheme:
>> -> { "execute": "do-foo" }
>> <- { "return": {} }
>> <- { "event": "FOO_DONE" }
>
> ... where the event may carry additional data, such as the command's
> true result.
>
>> It has several flaws:
>> - FOO_DONE event has no semantic link with do-foo in the qapi
>>   schema. It is not simple to generalize that pattern when writing
>>   qmp clients. It makes documentation and usage harder.
>> - the FOO_DONE event has no clear association with the command that
>>   triggered it: commands/events have to come up with additional
>>   specific association schemes (ids, path etc)
>
> Valid points.  Emulating asynchronous commands with a synchronous
> command + event isn't quite as simple to specify as a native
> asynchronous command could be.
>
>> - FOO_DONE is broadcasted to all clients, but they may have no way to
>>   interprete it or interest in it, or worse it may conflict with their
>>   own commands.
>
> The part about "no interest" is valid in cases where the event signals
> completion of a job without side effects, because then only the job's
> initiator cares (the event has to carry a result for this to make
> sense).  But when the job has side effects, other clients may want to
> know, and broadcast is probably the right thing to do.
>
> We deliberately broadcast events even though some clients may not care
> about some of them.  It's the stupidest solution that could possibly
> work.  Has never been a problem; clients simply ignore events they don't
> need.  If it becomes a problem, we can provide a mechanism to subscribe
> to events.  Adds some interface complexity to save a bit of bandwidth.
>
> The part about "conflict due to broadcast" is weak.  To create a
> conflict, the interface has to be misdesigned so that events can't be
> reliably connected back to their commands.  But then the conflict could
> just as well happen between commands issued by a single client.  I think
> the valid point here is that synchronous command + event offers an
> additional opportunity for screwing up at the command design level.
> Perhaps we should do something about it; more on that below.
>
>> - the arguably useless empty reply return
>
> Valid point, but really, really minor.
>
>> For some cases, it makes sense to use that scheme, or a more complete
>> one: to have an "handler" associated with an on-going operation, that
>> can be queried, modified, cancelled etc (block jobs etc).
>
> Block jobs provide ways to query status and properties, modify
> properties, pause, resume, cancel, and initiate synchronous completion.
>
> I suspect that we could use some of these "job control" features for
> pretty much any long-running activity.
>
> Migration is such an activity, but uses its own job control interfaces.
>
> We hope to unify both under a more generic "job" abstraction.
>
>>                                                           Also, some
>> operations have a global side-effect, in which case that cmd+event
>> scheme is right, as all clients are listening for global events.
>
> Yes.
>
>> However, for the simple case where a client want to perform a "local
>> context" operation (dump, query etc), QAPI can easily do better
>> without resorting to this pattern: it can send the reply when the
>> operation is done. That would make QAPI schema, usage and
>> documentation more obvious.
>
> On the other hand, it creates a second, independent way to do
> asynchronous.
>
> Let me review the design space.
>
> 1. Commands are asynchronous
>
>    We still need events to broadcast state changes of interest.
>
>    Commands that complete "quickly" will probably behave synchronously
>    anyway, because messing with threads or coroutines would be
>    inefficient and needlessly complex then.
>
>    Risk: clients that erroneously rely on synchronous behavior can work
>    in simple testing, yet break in entertaining ways under load, or when
>    a "quick" command becomes "slow" later on.  Not an argument against
>    this design, I'm merely pointing out an opportunity to screw up.  It
>    could make evolving de facto synchronous commands into asynchronous
>    ones impractical, though.
>
>    We still need job control.  A natural way to do it is to provide job
>    control for *any* asynchronous command, i.e. there's no separate
>    concept of "jobs", there are just commands that haven't completed,
>    yet.  Job control commands simply fail when the asynchronous command
>    they target doesn't support them.  I figure only select commands
>    support cancellation, for instance.
>
>    Of course, we could also do job control the way we do it now, with a
>    separate "job" concept.  You can't evolve a mere command into a job
>    then: if you start with a mere command, and it later turns out that
>    it can run for a very long time, and you need to be able to cancel
>    it, you have to start over: create a new command that creates a job.
>
>    While this feels like a perfectly sensible design to me, we can't
>    have it without a massive compatibility break.  Or can we?
>
> 2. Commands are synchronous
>
>    This is what we have now.
>
>    Commands that may not complete "quickly" need to be split into a
>    command to kick off the job, and an event to signal completion and
>    transmit the result.
>
>    If we misjudge "quickly", we have to start over with a new command.
>    With 1., we can change the old command from synchronous to
>    asynchronous instead, but that risks breaking clients, which may
>    force us to start over anyway.
>
>    We currently lack a generic way to connect events back to their
>    commands, and instead leave the problem to each command/event pair to
>    solve.
>
>    A special case of the command+event pattern is "block jobs".  We'd
>    like to evolve them into general job abstraction.  Perhaps any
>    (non-deprecated) command/event combo could be an instance of this job
>    abstraction.  Such a job abstraction should certainly provide an
>    unambiguous connection between event and command.
>
> 3. Both
>
>    Existing commands stay synchronous for compatibility.  New commands
>    that complete "quickly" are synchronous.  New commands that may not
>    complete "quickly" become asynchronous if job control isn't needed,
>    else they start jobs.  Having a single job abstraction for them would
>    be nice.
>
>    If we misjudge "quickly" or "no need for job control", we have to
>    start over with a new command.
>
>    I hope this is a fair description of what you're proposing, please
>    correct misunderstandings.
>
>    While I accept your assertion that the commands we can make
>    asynchronous would be a bit simpler than their synchronous command +
>    event equivalent, I'm afraid adding them to what we have now merely
>    moves the complexity around: three kinds of commands (quick,
>    command+event, async) instead of two.  Whether that's a net win is
>    unclear.  I doubt it.
>
> I'm pretty confident adding a suitable jobs abstraction can make 2. work
> reasonably well.
>
> I can't quite see how we can get from here to 1., but perhaps you can
> show us.
>
> I strongly dislike the lack of orthogonality in 3.
>
>> The following series implements an async solution, by introducing a
>> context associated with a command, it can:
>> - defer the return
>> - return only to the caller (no broadcasted event)
>> - return with the 'id' associated with the call (as originally intended)
>
> Context: 'id' is passed by the client with the command.
>
> As you mentioned elsewhere in this thread, 'id' could conceivably
> ambiguous with multiple QMP monitors.  One way to disambiguate is
> including a monitor-id that uniquely identifies the monitor where 'id'
> comes from.
>
>> - optionnally allow cancellation when the client is gone
>> - track on-going qapi command(s) per client
>
> Inching towards job control...
>
>> 1) existing qemu commands can be gradually replaced by async:true
>> variants when needed, and by carefully reviewing the concurrency
>> aspects.
>
> It's a behavioral change that can conceivably break clients, so
> "reviewing the concurrency aspects" includes reviewing all clients, I'm
> afraid.  I'm not saying it's impossible, but I'm not exactly looking
> forward to it.
>
>>          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.
>>
>> 2) allow concurrent commands when 'async' is negotiated. If the client
>> doesn't support 'async', then the monitor is suspended during command
>> execution (events are still sent). Effectively, async commands behave
>> like normal commands from client POV in this case, giving full
>> backward compatibility.
>
> Aha.  Okay, that makes it more practical.  Converting to async can break
> a client even when it claims to support async, but I guess it's less
> likely.
>
>> 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). HMP remains sync, but it would be worth to make
>> it possible to call async:true qapi commands.
>>
>> The last patch cleans up qmp_dispatch usage to have consistant checks
>> between qga & qemu, and simplify QmpClient/parser_feed usage.
>
> I'm afraid I lack the time to review your actual patches in a reasonable
> time frame; I really need to hunker down and deliver the QemuOpts / QAPI
> work I promised for 2.9, or else my block friends will be sad, Dan
> Berrange will be sad, and my manager will be sad, too.  This is
> unfortunate.  More so since your proposal has been pending for so long.
> My sincere apologies.
>
> Let's at least use the time to discuss the design, in particular how it
> relates to the work on evolving block jobs into a generic jobs
> abstraction.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-24 19:10   ` Markus Armbruster
@ 2017-04-25  0:06     ` John Snow
  2017-04-25  6:55       ` Markus Armbruster
  2017-04-25  9:13     ` Daniel P. Berrange
  2017-04-25 10:22     ` Kevin Wolf
  2 siblings, 1 reply; 61+ messages in thread
From: John Snow @ 2017-04-25  0:06 UTC (permalink / raw)
  To: Markus Armbruster, Marc-André Lureau
  Cc: qemu-devel, kraxel, Jeff Cody, Stefan Hajnoczi, Kevin Wolf,
	ebl >> Eric Blake



On 04/24/2017 03:10 PM, Markus Armbruster wrote:
> With 2.9 out of the way, how can we make progress on this one?
> 

Throw rocks at my window late at night. Refuse to stop until there is
consensus.

> I can see two ways to get asynchronous QMP commands accepted:
> 
> 1. We break QMP compatibility in QEMU 3.0 and convert all long-running
>    tasks from "synchronous command + event" to "asynchronous command".
> 
>    This is design option 1 quoted below.  *If* we decide to leave
>    compatibility behind for 3.0, *and* we decide we like the
>    asynchronous sufficiently better to put in the work, we can do it.
> 
>    I guess there's nothing to do here until we decide on breaking
>    compatibility in 3.0.
> 
> 2. We don't break QMP compatibility, but we add asynchronous commands
>    anyway, because we decide that's how we want to do "jobs".
> 
>    This is design option 3 quoted below.  As I said, I dislike its lack
>    of orthogonality.  But if asynchronous commands help us get jobs
>    done, I can bury my dislike.
> 
>    I feel this is something you should investigate with John Snow.
>    Going through a middleman (me) makes no sense.  So I'm going to dump
>    my thoughts, then get out of the way.
> 

I'd like to discuss this on the KVM call, not this week (because that's
... today, when you read this email) but next week. Let me digest the
async QMP proposal before then and we can discuss the merits of either
approach.

I'd like to invite Marc-Andre, Markus, Stefan, and Eric Blake to join;
Jeff Cody might have some good input here too.

I don't know enough about what problems async QMP is trying to solve yet
to have anything resembling an intelligent comment yet. I'll put next
Tuesday as my deadline for not being a deadbeat.

>    You need to take care not to get bogged down in the jobs project's
>    complexity.  This is really only how to package up jobs for QMP.
> >    With synchronous commands, the job-creating command creates a job,
>    jobs state changes trigger events, and job termination is just
>    another state change.  Job control commands interact with the job.
>  
>    Events obviously need to carry a job ID.  We can either require the
>    user to pass it as argument to the job-creating command (hopefully
>    unique), or have the job-creating command pick one (a unique one) and
>    return it.
> 
>    With asynchronous commands, we could make the asynchronous command
>    the job.  The only difference is that job termination triggers the
>    command response.  When termination is of no interest to anyone but
>    the job's creator, the termination event can be omitted then.
> 

That is, you receive no confirmation that the job is being processed
until it succeeds or fails in the "async QMP-as-jobs" model?

Not even the ACK-return? ('{return: {}}')

>    Instead of a job ID, we could use the (user-specified and hopefully
>    unique) command ID that ties the command response to the command.
>    Perhaps throw in a monitor ID.
> 
>    To be honest, I'm not sure asynchronous commands buy us much here.
>    But my view is from 10,000 feet, and John might have different ideas.
> 

Withholding comment until I give it a fair shake.

> Rejecting asynchronous QMP commands is of course design option 2 quoted
> below.
> 
> 
> Markus Armbruster <armbru@redhat.com> writes:
> 
>> Cc'ing block job people.
>>
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>
>>> 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.
>>
>> Correct.
>>
>> QMP's initial design stipulated that commands are asynchronous.  The
>> initial implementation made them all synchronous, with very few
>> exceptions (buggy ones, to boot).  Naturally, clients relied on the
>> actual rather than the theoretical behavior, i.e. on getting command
>> replies synchronously, in order.
>>
>>> Note that qmp events are asynchronous messages, and must be handled
>>> appropriately by the client: dispatch both reply and events after a
>>> command is sent for example.
>>
>> Yes.
>>
>>> The benefits of async commands that can be trade-off depending on the
>>> requirements are:
>>>
>>> 1) allow 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 tricky
>>> (see below) to solve.  Furthermore, many QMP commands do IO and could
>>> be considered 'slow' and blocking today.
>>>
>>> 2) allow concurrent commands and events. This mainly implies hanlding
>>> concurrency in qemu and out-of-order replies for the client. As noted
>>> earlier, a good qmp client already has to handle dispatching of
>>> received messages (reply and events).
>>
>> We need to distingish two kinds of concurrency.  One, execution of QMP
>> commands concurrently with other activities in QEMU, including other QMP
>> monitors.  Two, executing multiple QMP commands concurrently in the same
>> monitor, which obviously requires all but one of them to be
>> asynchronous.
>>
>>> The traditional approach to solving the above in qemu is the following
>>> scheme:
>>> -> { "execute": "do-foo" }
>>> <- { "return": {} }
>>> <- { "event": "FOO_DONE" }
>>
>> ... where the event may carry additional data, such as the command's
>> true result.
>>
>>> It has several flaws:
>>> - FOO_DONE event has no semantic link with do-foo in the qapi
>>>   schema. It is not simple to generalize that pattern when writing
>>>   qmp clients. It makes documentation and usage harder.
>>> - the FOO_DONE event has no clear association with the command that
>>>   triggered it: commands/events have to come up with additional
>>>   specific association schemes (ids, path etc)
>>
>> Valid points.  Emulating asynchronous commands with a synchronous
>> command + event isn't quite as simple to specify as a native
>> asynchronous command could be.
>>
>>> - FOO_DONE is broadcasted to all clients, but they may have no way to
>>>   interprete it or interest in it, or worse it may conflict with their
>>>   own commands.
>>
>> The part about "no interest" is valid in cases where the event signals
>> completion of a job without side effects, because then only the job's
>> initiator cares (the event has to carry a result for this to make
>> sense).  But when the job has side effects, other clients may want to
>> know, and broadcast is probably the right thing to do.
>>
>> We deliberately broadcast events even though some clients may not care
>> about some of them.  It's the stupidest solution that could possibly
>> work.  Has never been a problem; clients simply ignore events they don't
>> need.  If it becomes a problem, we can provide a mechanism to subscribe
>> to events.  Adds some interface complexity to save a bit of bandwidth.
>>
>> The part about "conflict due to broadcast" is weak.  To create a
>> conflict, the interface has to be misdesigned so that events can't be
>> reliably connected back to their commands.  But then the conflict could
>> just as well happen between commands issued by a single client.  I think
>> the valid point here is that synchronous command + event offers an
>> additional opportunity for screwing up at the command design level.
>> Perhaps we should do something about it; more on that below.
>>
>>> - the arguably useless empty reply return
>>
>> Valid point, but really, really minor.
>>
>>> For some cases, it makes sense to use that scheme, or a more complete
>>> one: to have an "handler" associated with an on-going operation, that
>>> can be queried, modified, cancelled etc (block jobs etc).
>>
>> Block jobs provide ways to query status and properties, modify
>> properties, pause, resume, cancel, and initiate synchronous completion.
>>
>> I suspect that we could use some of these "job control" features for
>> pretty much any long-running activity.
>>
>> Migration is such an activity, but uses its own job control interfaces.
>>
>> We hope to unify both under a more generic "job" abstraction.
>>
>>>                                                           Also, some
>>> operations have a global side-effect, in which case that cmd+event
>>> scheme is right, as all clients are listening for global events.
>>
>> Yes.
>>
>>> However, for the simple case where a client want to perform a "local
>>> context" operation (dump, query etc), QAPI can easily do better
>>> without resorting to this pattern: it can send the reply when the
>>> operation is done. That would make QAPI schema, usage and
>>> documentation more obvious.
>>
>> On the other hand, it creates a second, independent way to do
>> asynchronous.
>>
>> Let me review the design space.
>>
>> 1. Commands are asynchronous
>>
>>    We still need events to broadcast state changes of interest.
>>
>>    Commands that complete "quickly" will probably behave synchronously
>>    anyway, because messing with threads or coroutines would be
>>    inefficient and needlessly complex then.
>>
>>    Risk: clients that erroneously rely on synchronous behavior can work
>>    in simple testing, yet break in entertaining ways under load, or when
>>    a "quick" command becomes "slow" later on.  Not an argument against
>>    this design, I'm merely pointing out an opportunity to screw up.  It
>>    could make evolving de facto synchronous commands into asynchronous
>>    ones impractical, though.
>>
>>    We still need job control.  A natural way to do it is to provide job
>>    control for *any* asynchronous command, i.e. there's no separate
>>    concept of "jobs", there are just commands that haven't completed,
>>    yet.  Job control commands simply fail when the asynchronous command
>>    they target doesn't support them.  I figure only select commands
>>    support cancellation, for instance.
>>
>>    Of course, we could also do job control the way we do it now, with a
>>    separate "job" concept.  You can't evolve a mere command into a job
>>    then: if you start with a mere command, and it later turns out that
>>    it can run for a very long time, and you need to be able to cancel
>>    it, you have to start over: create a new command that creates a job.
>>
>>    While this feels like a perfectly sensible design to me, we can't
>>    have it without a massive compatibility break.  Or can we?
>>
>> 2. Commands are synchronous
>>
>>    This is what we have now.
>>
>>    Commands that may not complete "quickly" need to be split into a
>>    command to kick off the job, and an event to signal completion and
>>    transmit the result.
>>
>>    If we misjudge "quickly", we have to start over with a new command.
>>    With 1., we can change the old command from synchronous to
>>    asynchronous instead, but that risks breaking clients, which may
>>    force us to start over anyway.
>>
>>    We currently lack a generic way to connect events back to their
>>    commands, and instead leave the problem to each command/event pair to
>>    solve.
>>
>>    A special case of the command+event pattern is "block jobs".  We'd
>>    like to evolve them into general job abstraction.  Perhaps any
>>    (non-deprecated) command/event combo could be an instance of this job
>>    abstraction.  Such a job abstraction should certainly provide an
>>    unambiguous connection between event and command.
>>
>> 3. Both
>>
>>    Existing commands stay synchronous for compatibility.  New commands
>>    that complete "quickly" are synchronous.  New commands that may not
>>    complete "quickly" become asynchronous if job control isn't needed,
>>    else they start jobs.  Having a single job abstraction for them would
>>    be nice.
>>
>>    If we misjudge "quickly" or "no need for job control", we have to
>>    start over with a new command.
>>
>>    I hope this is a fair description of what you're proposing, please
>>    correct misunderstandings.
>>
>>    While I accept your assertion that the commands we can make
>>    asynchronous would be a bit simpler than their synchronous command +
>>    event equivalent, I'm afraid adding them to what we have now merely
>>    moves the complexity around: three kinds of commands (quick,
>>    command+event, async) instead of two.  Whether that's a net win is
>>    unclear.  I doubt it.
>>
>> I'm pretty confident adding a suitable jobs abstraction can make 2. work
>> reasonably well.
>>
>> I can't quite see how we can get from here to 1., but perhaps you can
>> show us.
>>
>> I strongly dislike the lack of orthogonality in 3.
>>
>>> The following series implements an async solution, by introducing a
>>> context associated with a command, it can:
>>> - defer the return
>>> - return only to the caller (no broadcasted event)
>>> - return with the 'id' associated with the call (as originally intended)
>>
>> Context: 'id' is passed by the client with the command.
>>
>> As you mentioned elsewhere in this thread, 'id' could conceivably
>> ambiguous with multiple QMP monitors.  One way to disambiguate is
>> including a monitor-id that uniquely identifies the monitor where 'id'
>> comes from.
>>
>>> - optionnally allow cancellation when the client is gone
>>> - track on-going qapi command(s) per client
>>
>> Inching towards job control...
>>
>>> 1) existing qemu commands can be gradually replaced by async:true
>>> variants when needed, and by carefully reviewing the concurrency
>>> aspects.
>>
>> It's a behavioral change that can conceivably break clients, so
>> "reviewing the concurrency aspects" includes reviewing all clients, I'm
>> afraid.  I'm not saying it's impossible, but I'm not exactly looking
>> forward to it.
>>
>>>          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.
>>>
>>> 2) allow concurrent commands when 'async' is negotiated. If the client
>>> doesn't support 'async', then the monitor is suspended during command
>>> execution (events are still sent). Effectively, async commands behave
>>> like normal commands from client POV in this case, giving full
>>> backward compatibility.
>>
>> Aha.  Okay, that makes it more practical.  Converting to async can break
>> a client even when it claims to support async, but I guess it's less
>> likely.
>>
>>> 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). HMP remains sync, but it would be worth to make
>>> it possible to call async:true qapi commands.
>>>
>>> The last patch cleans up qmp_dispatch usage to have consistant checks
>>> between qga & qemu, and simplify QmpClient/parser_feed usage.
>>
>> I'm afraid I lack the time to review your actual patches in a reasonable
>> time frame; I really need to hunker down and deliver the QemuOpts / QAPI
>> work I promised for 2.9, or else my block friends will be sad, Dan
>> Berrange will be sad, and my manager will be sad, too.  This is
>> unfortunate.  More so since your proposal has been pending for so long.
>> My sincere apologies.
>>
>> Let's at least use the time to discuss the design, in particular how it
>> relates to the work on evolving block jobs into a generic jobs
>> abstraction.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-25  0:06     ` John Snow
@ 2017-04-25  6:55       ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2017-04-25  6:55 UTC (permalink / raw)
  To: John Snow
  Cc: Marc-André Lureau, Kevin Wolf, Jeff Cody, qemu-devel,
	kraxel, Stefan Hajnoczi

John Snow <jsnow@redhat.com> writes:

> On 04/24/2017 03:10 PM, Markus Armbruster wrote:
>> With 2.9 out of the way, how can we make progress on this one?
>> 
>
> Throw rocks at my window late at night. Refuse to stop until there is
> consensus.
>
>> I can see two ways to get asynchronous QMP commands accepted:
>> 
>> 1. We break QMP compatibility in QEMU 3.0 and convert all long-running
>>    tasks from "synchronous command + event" to "asynchronous command".
>> 
>>    This is design option 1 quoted below.  *If* we decide to leave
>>    compatibility behind for 3.0, *and* we decide we like the
>>    asynchronous sufficiently better to put in the work, we can do it.
>> 
>>    I guess there's nothing to do here until we decide on breaking
>>    compatibility in 3.0.
>> 
>> 2. We don't break QMP compatibility, but we add asynchronous commands
>>    anyway, because we decide that's how we want to do "jobs".
>> 
>>    This is design option 3 quoted below.  As I said, I dislike its lack
>>    of orthogonality.  But if asynchronous commands help us get jobs
>>    done, I can bury my dislike.
>> 
>>    I feel this is something you should investigate with John Snow.
>>    Going through a middleman (me) makes no sense.  So I'm going to dump
>>    my thoughts, then get out of the way.
>> 
>
> I'd like to discuss this on the KVM call, not this week (because that's
> ... today, when you read this email) but next week. Let me digest the
> async QMP proposal before then and we can discuss the merits of either
> approach.
>
> I'd like to invite Marc-Andre, Markus, Stefan, and Eric Blake to join;
> Jeff Cody might have some good input here too.

Can do.

> I don't know enough about what problems async QMP is trying to solve yet
> to have anything resembling an intelligent comment yet. I'll put next
> Tuesday as my deadline for not being a deadbeat.
>
>>    You need to take care not to get bogged down in the jobs project's
>>    complexity.  This is really only how to package up jobs for QMP.
>> >    With synchronous commands, the job-creating command creates a job,
>>    jobs state changes trigger events, and job termination is just
>>    another state change.  Job control commands interact with the job.
>>  
>>    Events obviously need to carry a job ID.  We can either require the
>>    user to pass it as argument to the job-creating command (hopefully
>>    unique), or have the job-creating command pick one (a unique one) and
>>    return it.
>> 
>>    With asynchronous commands, we could make the asynchronous command
>>    the job.  The only difference is that job termination triggers the
>>    command response.  When termination is of no interest to anyone but
>>    the job's creator, the termination event can be omitted then.
>> 
>
> That is, you receive no confirmation that the job is being processed
> until it succeeds or fails in the "async QMP-as-jobs" model?
>
> Not even the ACK-return? ('{return: {}}')

Nope.  You still receive job events, though.

There can be only one response to a command, obviously.

When the job-creating command is synchronous, we need to send it on job
creation.  The command creates the job, and the job is a separate
entity.

When the job-creating command is asynchronous, we can send it on job
termination instead.  The command *is* the job then.

In both cases, the response goes only to whoever sent the command.  If
other QMP clients need to know, we have to additionally broadcast an
event.

Also in both cases, job control commands can interact with the job while
it exists.  Some job control commands may fail because the job doesn't
support them.  For instance, jobs may not support cancellation.

The special case "job that only the initiator needs to know, and even
the initiator doesn't need to know whether the job was created
successfully until it terminates" becomes simpler with asynchronous
commands: no events.

The general case doesn't, as far as I can tell.

If all commands are conceptually asynchronous (design option 1 quoted
below), and we use "command is the job", then *every* command is a job!
Commands that are actually synchronous below the hood can't be observed
as jobs in the same monitor.  They can be in other monitors unless some
kind of mutual exclusion locks out other monitors while the synchronous
command is running.  Committing to such mutual exclusion seems foolish,
though.  In this design, most "jobs" won't support non-trivial job
control such as cancellation, obviously.

>>    Instead of a job ID, we could use the (user-specified and hopefully
>>    unique) command ID that ties the command response to the command.
>>    Perhaps throw in a monitor ID.
>> 
>>    To be honest, I'm not sure asynchronous commands buy us much here.
>>    But my view is from 10,000 feet, and John might have different ideas.
>> 
>
> Withholding comment until I give it a fair shake.
>
>> Rejecting asynchronous QMP commands is of course design option 2 quoted
>> below.
>> 
>> 
>> Markus Armbruster <armbru@redhat.com> writes:
>> 
>>> Cc'ing block job people.
>>>
>>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>>
>>>> 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.
>>>
>>> Correct.
>>>
>>> QMP's initial design stipulated that commands are asynchronous.  The
>>> initial implementation made them all synchronous, with very few
>>> exceptions (buggy ones, to boot).  Naturally, clients relied on the
>>> actual rather than the theoretical behavior, i.e. on getting command
>>> replies synchronously, in order.
>>>
>>>> Note that qmp events are asynchronous messages, and must be handled
>>>> appropriately by the client: dispatch both reply and events after a
>>>> command is sent for example.
>>>
>>> Yes.
>>>
>>>> The benefits of async commands that can be trade-off depending on the
>>>> requirements are:
>>>>
>>>> 1) allow 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 tricky
>>>> (see below) to solve.  Furthermore, many QMP commands do IO and could
>>>> be considered 'slow' and blocking today.
>>>>
>>>> 2) allow concurrent commands and events. This mainly implies hanlding
>>>> concurrency in qemu and out-of-order replies for the client. As noted
>>>> earlier, a good qmp client already has to handle dispatching of
>>>> received messages (reply and events).
>>>
>>> We need to distingish two kinds of concurrency.  One, execution of QMP
>>> commands concurrently with other activities in QEMU, including other QMP
>>> monitors.  Two, executing multiple QMP commands concurrently in the same
>>> monitor, which obviously requires all but one of them to be
>>> asynchronous.
>>>
>>>> The traditional approach to solving the above in qemu is the following
>>>> scheme:
>>>> -> { "execute": "do-foo" }
>>>> <- { "return": {} }
>>>> <- { "event": "FOO_DONE" }
>>>
>>> ... where the event may carry additional data, such as the command's
>>> true result.
>>>
>>>> It has several flaws:
>>>> - FOO_DONE event has no semantic link with do-foo in the qapi
>>>>   schema. It is not simple to generalize that pattern when writing
>>>>   qmp clients. It makes documentation and usage harder.
>>>> - the FOO_DONE event has no clear association with the command that
>>>>   triggered it: commands/events have to come up with additional
>>>>   specific association schemes (ids, path etc)
>>>
>>> Valid points.  Emulating asynchronous commands with a synchronous
>>> command + event isn't quite as simple to specify as a native
>>> asynchronous command could be.
>>>
>>>> - FOO_DONE is broadcasted to all clients, but they may have no way to
>>>>   interprete it or interest in it, or worse it may conflict with their
>>>>   own commands.
>>>
>>> The part about "no interest" is valid in cases where the event signals
>>> completion of a job without side effects, because then only the job's
>>> initiator cares (the event has to carry a result for this to make
>>> sense).  But when the job has side effects, other clients may want to
>>> know, and broadcast is probably the right thing to do.
>>>
>>> We deliberately broadcast events even though some clients may not care
>>> about some of them.  It's the stupidest solution that could possibly
>>> work.  Has never been a problem; clients simply ignore events they don't
>>> need.  If it becomes a problem, we can provide a mechanism to subscribe
>>> to events.  Adds some interface complexity to save a bit of bandwidth.
>>>
>>> The part about "conflict due to broadcast" is weak.  To create a
>>> conflict, the interface has to be misdesigned so that events can't be
>>> reliably connected back to their commands.  But then the conflict could
>>> just as well happen between commands issued by a single client.  I think
>>> the valid point here is that synchronous command + event offers an
>>> additional opportunity for screwing up at the command design level.
>>> Perhaps we should do something about it; more on that below.
>>>
>>>> - the arguably useless empty reply return
>>>
>>> Valid point, but really, really minor.
>>>
>>>> For some cases, it makes sense to use that scheme, or a more complete
>>>> one: to have an "handler" associated with an on-going operation, that
>>>> can be queried, modified, cancelled etc (block jobs etc).
>>>
>>> Block jobs provide ways to query status and properties, modify
>>> properties, pause, resume, cancel, and initiate synchronous completion.
>>>
>>> I suspect that we could use some of these "job control" features for
>>> pretty much any long-running activity.
>>>
>>> Migration is such an activity, but uses its own job control interfaces.
>>>
>>> We hope to unify both under a more generic "job" abstraction.
>>>
>>>>                                                           Also, some
>>>> operations have a global side-effect, in which case that cmd+event
>>>> scheme is right, as all clients are listening for global events.
>>>
>>> Yes.
>>>
>>>> However, for the simple case where a client want to perform a "local
>>>> context" operation (dump, query etc), QAPI can easily do better
>>>> without resorting to this pattern: it can send the reply when the
>>>> operation is done. That would make QAPI schema, usage and
>>>> documentation more obvious.
>>>
>>> On the other hand, it creates a second, independent way to do
>>> asynchronous.
>>>
>>> Let me review the design space.
>>>
>>> 1. Commands are asynchronous
>>>
>>>    We still need events to broadcast state changes of interest.
>>>
>>>    Commands that complete "quickly" will probably behave synchronously
>>>    anyway, because messing with threads or coroutines would be
>>>    inefficient and needlessly complex then.
>>>
>>>    Risk: clients that erroneously rely on synchronous behavior can work
>>>    in simple testing, yet break in entertaining ways under load, or when
>>>    a "quick" command becomes "slow" later on.  Not an argument against
>>>    this design, I'm merely pointing out an opportunity to screw up.  It
>>>    could make evolving de facto synchronous commands into asynchronous
>>>    ones impractical, though.
>>>
>>>    We still need job control.  A natural way to do it is to provide job
>>>    control for *any* asynchronous command, i.e. there's no separate
>>>    concept of "jobs", there are just commands that haven't completed,
>>>    yet.  Job control commands simply fail when the asynchronous command
>>>    they target doesn't support them.  I figure only select commands
>>>    support cancellation, for instance.
>>>
>>>    Of course, we could also do job control the way we do it now, with a
>>>    separate "job" concept.  You can't evolve a mere command into a job
>>>    then: if you start with a mere command, and it later turns out that
>>>    it can run for a very long time, and you need to be able to cancel
>>>    it, you have to start over: create a new command that creates a job.
>>>
>>>    While this feels like a perfectly sensible design to me, we can't
>>>    have it without a massive compatibility break.  Or can we?
>>>
>>> 2. Commands are synchronous
>>>
>>>    This is what we have now.
>>>
>>>    Commands that may not complete "quickly" need to be split into a
>>>    command to kick off the job, and an event to signal completion and
>>>    transmit the result.
>>>
>>>    If we misjudge "quickly", we have to start over with a new command.
>>>    With 1., we can change the old command from synchronous to
>>>    asynchronous instead, but that risks breaking clients, which may
>>>    force us to start over anyway.
>>>
>>>    We currently lack a generic way to connect events back to their
>>>    commands, and instead leave the problem to each command/event pair to
>>>    solve.
>>>
>>>    A special case of the command+event pattern is "block jobs".  We'd
>>>    like to evolve them into general job abstraction.  Perhaps any
>>>    (non-deprecated) command/event combo could be an instance of this job
>>>    abstraction.  Such a job abstraction should certainly provide an
>>>    unambiguous connection between event and command.
>>>
>>> 3. Both
>>>
>>>    Existing commands stay synchronous for compatibility.  New commands
>>>    that complete "quickly" are synchronous.  New commands that may not
>>>    complete "quickly" become asynchronous if job control isn't needed,
>>>    else they start jobs.  Having a single job abstraction for them would
>>>    be nice.
>>>
>>>    If we misjudge "quickly" or "no need for job control", we have to
>>>    start over with a new command.
>>>
>>>    I hope this is a fair description of what you're proposing, please
>>>    correct misunderstandings.
>>>
>>>    While I accept your assertion that the commands we can make
>>>    asynchronous would be a bit simpler than their synchronous command +
>>>    event equivalent, I'm afraid adding them to what we have now merely
>>>    moves the complexity around: three kinds of commands (quick,
>>>    command+event, async) instead of two.  Whether that's a net win is
>>>    unclear.  I doubt it.
>>>
>>> I'm pretty confident adding a suitable jobs abstraction can make 2. work
>>> reasonably well.
>>>
>>> I can't quite see how we can get from here to 1., but perhaps you can
>>> show us.
>>>
>>> I strongly dislike the lack of orthogonality in 3.
>>>
>>>> The following series implements an async solution, by introducing a
>>>> context associated with a command, it can:
>>>> - defer the return
>>>> - return only to the caller (no broadcasted event)
>>>> - return with the 'id' associated with the call (as originally intended)
>>>
>>> Context: 'id' is passed by the client with the command.
>>>
>>> As you mentioned elsewhere in this thread, 'id' could conceivably
>>> ambiguous with multiple QMP monitors.  One way to disambiguate is
>>> including a monitor-id that uniquely identifies the monitor where 'id'
>>> comes from.
>>>
>>>> - optionnally allow cancellation when the client is gone
>>>> - track on-going qapi command(s) per client
>>>
>>> Inching towards job control...
>>>
>>>> 1) existing qemu commands can be gradually replaced by async:true
>>>> variants when needed, and by carefully reviewing the concurrency
>>>> aspects.
>>>
>>> It's a behavioral change that can conceivably break clients, so
>>> "reviewing the concurrency aspects" includes reviewing all clients, I'm
>>> afraid.  I'm not saying it's impossible, but I'm not exactly looking
>>> forward to it.
>>>
>>>>          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.
>>>>
>>>> 2) allow concurrent commands when 'async' is negotiated. If the client
>>>> doesn't support 'async', then the monitor is suspended during command
>>>> execution (events are still sent). Effectively, async commands behave
>>>> like normal commands from client POV in this case, giving full
>>>> backward compatibility.
>>>
>>> Aha.  Okay, that makes it more practical.  Converting to async can break
>>> a client even when it claims to support async, but I guess it's less
>>> likely.
>>>
>>>> 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). HMP remains sync, but it would be worth to make
>>>> it possible to call async:true qapi commands.
>>>>
>>>> The last patch cleans up qmp_dispatch usage to have consistant checks
>>>> between qga & qemu, and simplify QmpClient/parser_feed usage.
>>>
>>> I'm afraid I lack the time to review your actual patches in a reasonable
>>> time frame; I really need to hunker down and deliver the QemuOpts / QAPI
>>> work I promised for 2.9, or else my block friends will be sad, Dan
>>> Berrange will be sad, and my manager will be sad, too.  This is
>>> unfortunate.  More so since your proposal has been pending for so long.
>>> My sincere apologies.
>>>
>>> Let's at least use the time to discuss the design, in particular how it
>>> relates to the work on evolving block jobs into a generic jobs
>>> abstraction.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-24 19:10   ` Markus Armbruster
  2017-04-25  0:06     ` John Snow
@ 2017-04-25  9:13     ` Daniel P. Berrange
  2017-04-25 10:22     ` Kevin Wolf
  2 siblings, 0 replies; 61+ messages in thread
From: Daniel P. Berrange @ 2017-04-25  9:13 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Marc-André Lureau, Kevin Wolf, Jeff Cody, qemu-devel,
	kraxel, Stefan Hajnoczi, John Snow

On Mon, Apr 24, 2017 at 09:10:22PM +0200, Markus Armbruster wrote:
> With 2.9 out of the way, how can we make progress on this one?
> 
> I can see two ways to get asynchronous QMP commands accepted:
> 
> 1. We break QMP compatibility in QEMU 3.0 and convert all long-running
>    tasks from "synchronous command + event" to "asynchronous command".
> 
>    This is design option 1 quoted below.  *If* we decide to leave
>    compatibility behind for 3.0, *and* we decide we like the
>    asynchronous sufficiently better to put in the work, we can do it.
> 
>    I guess there's nothing to do here until we decide on breaking
>    compatibility in 3.0.

>From the libvirt POV we'll generally be against QEMU breaking back
compatibility, if there's a viable option which can avoid the back
compat breakage.

Is it possible to do option 1, but have it be an opt-in. ie when
libvirt does the initial QMP greeting, it could issue a command
to active async mode. For simplicity that could be an all-or-nothing
switch - ie makes all commands be async. That way we avoid breaking
any existing libvirt, but give new libvirt the chance to opt-in to
the new way.

Regardless new libvirt will end up having to support both modes of
QMP for 5-10 years...

> 2. We don't break QMP compatibility, but we add asynchronous commands
>    anyway, because we decide that's how we want to do "jobs".
> 
>    This is design option 3 quoted below.  As I said, I dislike its lack
>    of orthogonality.  But if asynchronous commands help us get jobs
>    done, I can bury my dislike.
> 
>    I feel this is something you should investigate with John Snow.
>    Going through a middleman (me) makes no sense.  So I'm going to dump
>    my thoughts, then get out of the way.
> 
>    You need to take care not to get bogged down in the jobs project's
>    complexity.  This is really only how to package up jobs for QMP.
> 
>    With synchronous commands, the job-creating command creates a job,
>    jobs state changes trigger events, and job termination is just
>    another state change.  Job control commands interact with the job.
>  
>    Events obviously need to carry a job ID.  We can either require the
>    user to pass it as argument to the job-creating command (hopefully
>    unique), or have the job-creating command pick one (a unique one) and
>    return it.
> 
>    With asynchronous commands, we could make the asynchronous command
>    the job.  The only difference is that job termination triggers the
>    command response.  When termination is of no interest to anyone but
>    the job's creator, the termination event can be omitted then.
> 
>    Instead of a job ID, we could use the (user-specified and hopefully
>    unique) command ID that ties the command response to the command.
>    Perhaps throw in a monitor ID.
> 
>    To be honest, I'm not sure asynchronous commands buy us much here.
>    But my view is from 10,000 feet, and John might have different ideas.
> 
> Rejecting asynchronous QMP commands is of course design option 2 quoted
> below.

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

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-24 19:10   ` Markus Armbruster
  2017-04-25  0:06     ` John Snow
  2017-04-25  9:13     ` Daniel P. Berrange
@ 2017-04-25 10:22     ` Kevin Wolf
  2017-04-28 15:55       ` Marc-André Lureau
  2 siblings, 1 reply; 61+ messages in thread
From: Kevin Wolf @ 2017-04-25 10:22 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Marc-André Lureau, qemu-devel, kraxel, Jeff Cody, John Snow,
	Stefan Hajnoczi

Am 24.04.2017 um 21:10 hat Markus Armbruster geschrieben:
> With 2.9 out of the way, how can we make progress on this one?
> 
> I can see two ways to get asynchronous QMP commands accepted:
> 
> 1. We break QMP compatibility in QEMU 3.0 and convert all long-running
>    tasks from "synchronous command + event" to "asynchronous command".
> 
>    This is design option 1 quoted below.  *If* we decide to leave
>    compatibility behind for 3.0, *and* we decide we like the
>    asynchronous sufficiently better to put in the work, we can do it.
> 
>    I guess there's nothing to do here until we decide on breaking
>    compatibility in 3.0.
> 
> 2. We don't break QMP compatibility, but we add asynchronous commands
>    anyway, because we decide that's how we want to do "jobs".
> 
>    This is design option 3 quoted below.  As I said, I dislike its lack
>    of orthogonality.  But if asynchronous commands help us get jobs
>    done, I can bury my dislike.

I don't think async commands are attractive at all for doing jobs. I
feel they bring up more questions that they answer, for example, what
happens if libvirt crashes and then reconnects? Which monitor connection
does get the reply for an async command sent on the now disconnected
one?

We already have a model for doing long-running jobs, and as far as I'm
aware, it's working and we're not fighting limitations of the design. So
what are we even trying to solve here? In the context of jobs, async
commands feel like a solution in need of a problem to me.

Things may look a bit different in typically quick, but potentially
long-running commands. That is, anything that we currently execute
synchronously while holding the BQL, but that involves I/O and could
therefore take a while (impacting the performance of the VM) or even
block indefinitely.

The first problem (we're holding the lock too long) can be addressed by
making things async just inside qemu and we don't need to expose the
change on the QMP level. The second one (blocking indefinitely) requires
being async on the QMP level if we want the monitor to be responsive
even if we're using an image on an NFS server that went down.

On the other hand, using the traditional job infrastructure is way over
the top if all you want to do is 'query-block', so we need something
different for making it async. And if a client disconnects, the
'query-block' result can just be thrown away, it's much simpler than
actual jobs.

So where I can see advantages for a new async command type is not for
converting real long-running commands like block jobs, but only for the
typically, but not necessarily quick operations. At the same time it is
where you're rightfully afraid that the less common case might not
receive much testing in management tools.

In the end, I'm unsure whether async commands are a good idea, I can see
good arguments for both stances. But I'm almost certain that they are
the wrong tool for jobs.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-25 10:22     ` Kevin Wolf
@ 2017-04-28 15:55       ` Marc-André Lureau
  2017-04-28 19:13         ` Kevin Wolf
  0 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-04-28 15:55 UTC (permalink / raw)
  To: Kevin Wolf, Markus Armbruster
  Cc: Jeff Cody, qemu-devel, kraxel, Stefan Hajnoczi, John Snow

Hi

On Tue, Apr 25, 2017 at 2:23 PM Kevin Wolf <kwolf@redhat.com> wrote:

> Am 24.04.2017 um 21:10 hat Markus Armbruster geschrieben:
> > With 2.9 out of the way, how can we make progress on this one?
> >
> > I can see two ways to get asynchronous QMP commands accepted:
> >
> > 1. We break QMP compatibility in QEMU 3.0 and convert all long-running
> >    tasks from "synchronous command + event" to "asynchronous command".
> >
> >    This is design option 1 quoted below.  *If* we decide to leave
> >    compatibility behind for 3.0, *and* we decide we like the
> >    asynchronous sufficiently better to put in the work, we can do it.
> >
> >    I guess there's nothing to do here until we decide on breaking
> >    compatibility in 3.0.
> >
> > 2. We don't break QMP compatibility, but we add asynchronous commands
> >    anyway, because we decide that's how we want to do "jobs".
> >
> >    This is design option 3 quoted below.  As I said, I dislike its lack
> >    of orthogonality.  But if asynchronous commands help us get jobs
> >    done, I can bury my dislike.
>
> I don't think async commands are attractive at all for doing jobs. I
>

It's still a bit obscure to me what we mean by "jobs".

feel they bring up more questions that they answer, for example, what
> happens if libvirt crashes and then reconnects? Which monitor connection
> does get the reply for an async command sent on the now disconnected
> one?
>

The monitor to receive a reply is the one that sent the command (just like
return today)

As explained in the cover letter, an async command may cancel the ongoing
operation on disconnect.

If there is a global state change, a separate event should be broadcasted
(no change proposed here)


> We already have a model for doing long-running jobs, and as far as I'm
> aware, it's working and we're not fighting limitations of the design. So
> what are we even trying to solve here? In the context of jobs, async
> commands feel like a solution in need of a problem to me.
>
>
See the cover letter for the 2 main reasons for this proposal. If your
domain API is fine, you don't have to opt-in and you may continue to use
the current sync model. However, I believe there is benefit in using this
work to have a more consitent async API.

Things may look a bit different in typically quick, but potentially
> long-running commands. That is, anything that we currently execute
> synchronously while holding the BQL, but that involves I/O and could
> therefore take a while (impacting the performance of the VM) or even
> block indefinitely.
>
> The first problem (we're holding the lock too long) can be addressed by
> making things async just inside qemu and we don't need to expose the
> change on the QMP level. The second one (blocking indefinitely) requires
>

That's what I propose as 1)


> being async on the QMP level if we want the monitor to be responsive
> even if we're using an image on an NFS server that went down.
>

That's the 2)


>
> On the other hand, using the traditional job infrastructure is way over
> the top if all you want to do is 'query-block', so we need something
> different for making it async. And if a client disconnects, the
> 'query-block' result can just be thrown away, it's much simpler than
> actual jobs.
>

I agree a fully-featured job infrastructure is way over the top, and I
believe I propose a minimal change to make optionnally some QMP commands
async.

>
> So where I can see advantages for a new async command type is not for
> converting real long-running commands like block jobs, but only for the
> typically, but not necessarily quick operations. At the same time it is
> where you're rightfully afraid that the less common case might not
> receive much testing in management tools.
>

I believe management tools / libvirt will want to use the async variant if
available. (the sync version is a one-command at a time constrained version
of 'async')

>
> In the end, I'm unsure whether async commands are a good idea, I can see
> good arguments for both stances. But I'm almost certain that they are
> the wrong tool for jobs.
>
>
Well, we already have 'async' commands, they are just hidden. They do not
use QAPI/QMP facility and lack consistency.

This series addresses the problem 1), internal to qemu.

And also proposes to replace the idiomatic:

    -> { "execute": "do-foo",  "id": 42
}

    <- { "return": {}, "id": 42 }            (this is a dummy useless
return)
    (foo is in fact async, you may do other commands here)


    <- { "event": "FOO_DONE" }     (this is a broadcasted event that other
monitor may not know how to deal with, lack of consistency with naming for
various async op, "id" field may be lost, no facilities in generated code
etc etc)

with a streamlined:

    -> { "execute": "do-foo", "id": 42 }
    (you may do other commands here)


    <- { "return": {}, "id": 42 }       (returned only to the caller)
    (if there is a global state change, there should also be a FOO_DONE
event)

As pointed out in the cover letter, existing client *have to* deal with
dispatching unrelated messages when sending commands, because events may
come before a return message. So they have facilities to handle async
replies.

But in any case, this streamlined version is behind a "async" QMP
capability.

I have been careful to not expose this change to qemu internal or qemu
client if they don't want or need it.

thanks

I hope reviewing the series can help clarify the intent, and not put
various other ideas/dreams behind the "async" term.
-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-28 15:55       ` Marc-André Lureau
@ 2017-04-28 19:13         ` Kevin Wolf
  2017-05-02  8:30           ` Gerd Hoffmann
  2017-05-02  9:05           ` Marc-André Lureau
  0 siblings, 2 replies; 61+ messages in thread
From: Kevin Wolf @ 2017-04-28 19:13 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Markus Armbruster, Jeff Cody, qemu-devel, kraxel,
	Stefan Hajnoczi, John Snow

Am 28.04.2017 um 17:55 hat Marc-André Lureau geschrieben:
> On Tue, Apr 25, 2017 at 2:23 PM Kevin Wolf <kwolf@redhat.com> wrote:
> 
> > Am 24.04.2017 um 21:10 hat Markus Armbruster geschrieben:
> > > With 2.9 out of the way, how can we make progress on this one?
> > >
> > > I can see two ways to get asynchronous QMP commands accepted:
> > >
> > > 1. We break QMP compatibility in QEMU 3.0 and convert all long-running
> > >    tasks from "synchronous command + event" to "asynchronous command".
> > >
> > >    This is design option 1 quoted below.  *If* we decide to leave
> > >    compatibility behind for 3.0, *and* we decide we like the
> > >    asynchronous sufficiently better to put in the work, we can do it.
> > >
> > >    I guess there's nothing to do here until we decide on breaking
> > >    compatibility in 3.0.
> > >
> > > 2. We don't break QMP compatibility, but we add asynchronous commands
> > >    anyway, because we decide that's how we want to do "jobs".
> > >
> > >    This is design option 3 quoted below.  As I said, I dislike its lack
> > >    of orthogonality.  But if asynchronous commands help us get jobs
> > >    done, I can bury my dislike.
> >
> > I don't think async commands are attractive at all for doing jobs. I
> 
> It's still a bit obscure to me what we mean by "jobs".

I guess the best definition that we have is: Image streaming, mirroring,
live backup, live commit and future "similar things".

> feel they bring up more questions that they answer, for example, what
> > happens if libvirt crashes and then reconnects? Which monitor connection
> > does get the reply for an async command sent on the now disconnected
> > one?
> >
> 
> The monitor to receive a reply is the one that sent the command (just
> like return today)
> 
> As explained in the cover letter, an async command may cancel the
> ongoing operation on disconnect.

But that's not what you generally want. You don't want to abort your
backup just because libvirt lost its monitor connection, but qemu should
continue to copy the data, and when libvirt reconnects it should be able
to get back control of this background operation and bring it to
successful completion.

> If there is a global state change, a separate event should be
> broadcasted (no change proposed here)

In a way, the existence of a block job is global state today. Not sure
if this is what you mean, though.

> > We already have a model for doing long-running jobs, and as far as I'm
> > aware, it's working and we're not fighting limitations of the design. So
> > what are we even trying to solve here? In the context of jobs, async
> > commands feel like a solution in need of a problem to me.
> 
> See the cover letter for the 2 main reasons for this proposal. If your
> domain API is fine, you don't have to opt-in and you may continue to use
> the current sync model. However, I believe there is benefit in using this
> work to have a more consitent async API.

I think we need a clear understanding of what the potential use cases
are that could make good use a new infrastructure. We don't generally
add infrastructure if we don't have a concrete idea what its users could
be. I only ruled out that the current users of block jobs are a good fit
for it, but there may be other use cases for which it works great.

If commands can opt-in or opt-out of the new model, consistency isn't a
particularly good argument, though.

> > Things may look a bit different in typically quick, but potentially
> > long-running commands. That is, anything that we currently execute
> > synchronously while holding the BQL, but that involves I/O and could
> > therefore take a while (impacting the performance of the VM) or even
> > block indefinitely.
> >
> > The first problem (we're holding the lock too long) can be addressed
> > by making things async just inside qemu and we don't need to expose
> > the change on the QMP level. The second one (blocking indefinitely)
> > requires
> >
> 
> That's what I propose as 1)
> 
> 
> > being async on the QMP level if we want the monitor to be responsive
> > even if we're using an image on an NFS server that went down.
> >
> 
> That's the 2)
> 
> > On the other hand, using the traditional job infrastructure is way
> > over the top if all you want to do is 'query-block', so we need
> > something different for making it async. And if a client
> > disconnects, the 'query-block' result can just be thrown away, it's
> > much simpler than actual jobs.
> 
> I agree a fully-featured job infrastructure is way over the top, and I
> believe I propose a minimal change to make optionnally some QMP
> commands async.

So are commands like 'query-block' (which are typically _not_ considered
long-running) what you're aiming for with your proposal? This is a case
where I think we could consider the use of async QMP commands, but I
didn't have the impression that this kind of commands was your primary
target.

> > So where I can see advantages for a new async command type is not for
> > converting real long-running commands like block jobs, but only for the
> > typically, but not necessarily quick operations. At the same time it is
> > where you're rightfully afraid that the less common case might not
> > receive much testing in management tools.
> >
> 
> I believe management tools / libvirt will want to use the async variant if
> available. (the sync version is a one-command at a time constrained version
> of 'async')

The point here is rather that even async commands degenerate into sync
commands if the management tool doesn't send multiple commands in
parallel.

If sending only a single command at a time is the common case (which
appears quite plausible to me), then race conditions that exist when
multiple commands are used in a rarer case might go unnoticed because
nobody gave the scenario real testing.

> > In the end, I'm unsure whether async commands are a good idea, I can
> > see good arguments for both stances. But I'm almost certain that
> > they are the wrong tool for jobs.
> >
> >
> Well, we already have 'async' commands, they are just hidden. They do
> not use QAPI/QMP facility and lack consistency.
> 
> This series addresses the problem 1), internal to qemu.
> 
> And also proposes to replace the idiomatic:
> 
>     -> { "execute": "do-foo",  "id": 42
> }
> 
>     <- { "return": {}, "id": 42 }            (this is a dummy useless
> return)
>     (foo is in fact async, you may do other commands here)

I know you like to insist on its uselessness, but no, it's not useless.
It tells the management tool that the background job has successfully
been started and block job management commands can be used with it now.

> 
>     <- { "event": "FOO_DONE" }     (this is a broadcasted event that other
> monitor may not know how to deal with, lack of consistency with naming for
> various async op, "id" field may be lost, no facilities in generated code
> etc etc)

Are these theoretical concerns or do you see them confirmed with
actually existing commands?

The broadcast is actually a feature, as mentioned above, because it
allows libvirt to reconnect after losing the connection and continue to
control the background operation.

> with a streamlined:
> 
>     -> { "execute": "do-foo", "id": 42 }
>     (you may do other commands here)
> 
> 
>     <- { "return": {}, "id": 42 }       (returned only to the caller)
>     (if there is a global state change, there should also be a FOO_DONE
> event)
> 
> As pointed out in the cover letter, existing client *have to* deal with
> dispatching unrelated messages when sending commands, because events may
> come before a return message. So they have facilities to handle async
> replies.
> 
> But in any case, this streamlined version is behind a "async" QMP
> capability.
> 
> I have been careful to not expose this change to qemu internal or qemu
> client if they don't want or need it.

The question is whether enough users (command implementations and
clients) need the change to justify maintaining another type of commands
long term. Just not breaking existing users doesn't justify a new
feature, it's only the most basic requirement for it to even be
considered.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-28 19:13         ` Kevin Wolf
@ 2017-05-02  8:30           ` Gerd Hoffmann
  2017-05-02  9:05           ` Marc-André Lureau
  1 sibling, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2017-05-02  8:30 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Marc-André Lureau, Markus Armbruster, Jeff Cody, qemu-devel,
	Stefan Hajnoczi, John Snow

  Hi,

> > As explained in the cover letter, an async command may cancel the
> > ongoing operation on disconnect.
> 
> But that's not what you generally want. You don't want to abort your
> backup just because libvirt lost its monitor connection, but qemu should
> continue to copy the data, and when libvirt reconnects it should be able
> to get back control of this background operation and bring it to
> successful completion.

Sure.  We can't move the existing block jobs to async commands, block
jobs need more features.

> I think we need a clear understanding of what the potential use cases
> are that could make good use a new infrastructure. We don't generally
> add infrastructure if we don't have a concrete idea what its users could
> be. I only ruled out that the current users of block jobs are a good fit
> for it, but there may be other use cases for which it works great.

One case at hand is the screendump command, driving this discussion
since years.

Today it writes out a dump to a file, synchronously.  I wouldn't be
surprised if this is measurable as latency spike.  Also specifically
with qxl we have the problem that spice-server renders locally only on
demand (because it can skip rendering altogether in many cases), so it
would be very nice if we can ask spice-server thread to render the
screen for us before writing the screen dump.

With async qmp commands we could actually do that.  Kick spice-server
(if needed), write out the screen dump in a separate thread so we don't
block the main loop while writing it.

There is no need to query status / progress.  Usually it'll finish in
fractions of a second (if not we probably have bigger problems like a
hanging nfs server ...).  Can be canceled without loosing important
data, for example in case the monitor connection goes down, client can
just ask for a new screen dump after reconnect.  Nobody but the client
which submitted the command is interested in the reply.

> > I agree a fully-featured job infrastructure is way over the top, and I
> > believe I propose a minimal change to make optionnally some QMP
> > commands async.
> 
> So are commands like 'query-block' (which are typically _not_ considered
> long-running) what you're aiming for with your proposal?

I think pretty much everything in the query-* category which doesn't
just dump out internal qemu state but has to go gather information
before returning a reply could profit from async command support.

Not sure whenever that is the case for query-block.  If it is just a
list of block devices then no.  If it possibly does I/O to get and
return some image statistics then yes.

> The point here is rather that even async commands degenerate into sync
> commands if the management tool doesn't send multiple commands in
> parallel.

Allowing to submit multiple commands is one (externally visible)
benefit.  The other is internal to qemu:  We don't have to block
main-loop while running the command.

> >     -> { "execute": "do-foo",  "id": 42 }
> >     <- { "return": {}, "id": 42 }   (this is a dummy useless return)

> I know you like to insist on its uselessness, but no, it's not useless.
> It tells the management tool that the background job has successfully
> been started and block job management commands can be used with it now.

See above, block jobs are a different story.

> The question is whether enough users (command implementations and
> clients) need the change to justify maintaining another type of commands
> long term. Just not breaking existing users doesn't justify a new
> feature, it's only the most basic requirement for it to even be
> considered.

I think the question is which route we want go long-term.  I basically
see three options:

  (1) continue to abuse events as async reply.

  (2) implement async commands, roughly as suggested by Marc.

  (3) move jobs out of the block corner so they can be used everywhere
      in qemu (which is in discussion for a while too, don't know what
      the current state is though).  Then implement async commands using
      that infrastructure, as some kind of "simple job".

Disclaimer: I'm not very familiar with the block jobs code base.

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-04-28 19:13         ` Kevin Wolf
  2017-05-02  8:30           ` Gerd Hoffmann
@ 2017-05-02  9:05           ` Marc-André Lureau
  2017-05-02 10:42             ` Kevin Wolf
  1 sibling, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-05-02  9:05 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Markus Armbruster, Jeff Cody, qemu-devel, kraxel,
	Stefan Hajnoczi, John Snow

Hi

On Fri, Apr 28, 2017 at 11:13 PM Kevin Wolf <kwolf@redhat.com> wrote:

> Am 28.04.2017 um 17:55 hat Marc-André Lureau geschrieben:
> > On Tue, Apr 25, 2017 at 2:23 PM Kevin Wolf <kwolf@redhat.com> wrote:
> >
> > > Am 24.04.2017 um 21:10 hat Markus Armbruster geschrieben:
> > > > With 2.9 out of the way, how can we make progress on this one?
> > > >
> > > > I can see two ways to get asynchronous QMP commands accepted:
> > > >
> > > > 1. We break QMP compatibility in QEMU 3.0 and convert all
> long-running
> > > >    tasks from "synchronous command + event" to "asynchronous
> command".
> > > >
> > > >    This is design option 1 quoted below.  *If* we decide to leave
> > > >    compatibility behind for 3.0, *and* we decide we like the
> > > >    asynchronous sufficiently better to put in the work, we can do it.
> > > >
> > > >    I guess there's nothing to do here until we decide on breaking
> > > >    compatibility in 3.0.
> > > >
> > > > 2. We don't break QMP compatibility, but we add asynchronous commands
> > > >    anyway, because we decide that's how we want to do "jobs".
> > > >
> > > >    This is design option 3 quoted below.  As I said, I dislike its
> lack
> > > >    of orthogonality.  But if asynchronous commands help us get jobs
> > > >    done, I can bury my dislike.
> > >
> > > I don't think async commands are attractive at all for doing jobs. I
> >
> > It's still a bit obscure to me what we mean by "jobs".
>
> I guess the best definition that we have is: Image streaming, mirroring,
> live backup, live commit and future "similar things".
>

What does it mean in terms of QAPI/QMP protocol ? If I need to write a new
"job" (for something else than block op), is there some doc or guideline?


> > feel they bring up more questions that they answer, for example, what
> > > happens if libvirt crashes and then reconnects? Which monitor
> connection
> > > does get the reply for an async command sent on the now disconnected
> > > one?
> > >
> >
> > The monitor to receive a reply is the one that sent the command (just
> > like return today)
> >
> > As explained in the cover letter, an async command may cancel the
> > ongoing operation on disconnect.
>
> But that's not what you generally want. You don't want to abort your
> backup just because libvirt lost its monitor connection, but qemu should
> continue to copy the data, and when libvirt reconnects it should be able
> to get back control of this background operation and bring it to
> successful completion.
>

I said "may", and I make a difference between "local" (to the client) and
"global" (to qemu) operation.


>
> > If there is a global state change, a separate event should be
> > broadcasted (no change proposed here)
>
> In a way, the existence of a block job is global state today. Not sure
> if this is what you mean, though.
>

Yes. Global is probably the most common case.


>
> > > We already have a model for doing long-running jobs, and as far as I'm
> > > aware, it's working and we're not fighting limitations of the design.
> So
> > > what are we even trying to solve here? In the context of jobs, async
> > > commands feel like a solution in need of a problem to me.
> >
> > See the cover letter for the 2 main reasons for this proposal. If your
> > domain API is fine, you don't have to opt-in and you may continue to use
> > the current sync model. However, I believe there is benefit in using this
> > work to have a more consitent async API.
>
> I think we need a clear understanding of what the potential use cases
> are that could make good use a new infrastructure. We don't generally
> add infrastructure if we don't have a concrete idea what its users could
> be. I only ruled out that the current users of block jobs are a good fit
> for it, but there may be other use cases for which it works great.
>
>
The proposal mainly aims to improve "local" blocking commands, the one that
don't make qemu global state change but are still blocking.


> If commands can opt-in or opt-out of the new model, consistency isn't a
> particularly good argument, though.
>

The consistency is external, the client interact similarly with a sync or
async operation, it doesn't have to know.

Internally, I propose two different kind of callbacks: the sync variant is
a helper version of the async.


>
> > > Things may look a bit different in typically quick, but potentially
> > > long-running commands. That is, anything that we currently execute
> > > synchronously while holding the BQL, but that involves I/O and could
> > > therefore take a while (impacting the performance of the VM) or even
> > > block indefinitely.
> > >
> > > The first problem (we're holding the lock too long) can be addressed
> > > by making things async just inside qemu and we don't need to expose
> > > the change on the QMP level. The second one (blocking indefinitely)
> > > requires
> > >
> >
> > That's what I propose as 1)
> >
> >
> > > being async on the QMP level if we want the monitor to be responsive
> > > even if we're using an image on an NFS server that went down.
> > >
> >
> > That's the 2)
> >
> > > On the other hand, using the traditional job infrastructure is way
> > > over the top if all you want to do is 'query-block', so we need
> > > something different for making it async. And if a client
> > > disconnects, the 'query-block' result can just be thrown away, it's
> > > much simpler than actual jobs.
> >
> > I agree a fully-featured job infrastructure is way over the top, and I
> > believe I propose a minimal change to make optionnally some QMP
> > commands async.
>
> So are commands like 'query-block' (which are typically _not_ considered
> long-running) what you're aiming for with your proposal? This is a case
> where I think we could consider the use of async QMP commands, but I
> didn't have the impression that this kind of commands was your primary
> target.
>

Typically, I would like to improve the case described in the cover letter
where we have:

-> { "execute": "do-foo" }
<- { "return": {} }
<- { "event": "FOO_DONE" }

Let's call this an "hidden-async" (I will refer to this pattern later). And
do instead:

-> { "execute": "do-foo" }
<- { "return": {} }

(I won't repeat the flaws of the current status quo here, see cover and
thread)

But any blocking (even shortly) operation could also benefit from this
series by using the async variant to allow reentering the loop. This is the
1). I suppose 'query-block' is a good candidate, and typically could cancel
itself it the client is gone.

2) is an extra, if the client supports concurrent commands.


> > > So where I can see advantages for a new async command type is not for
> > > converting real long-running commands like block jobs, but only for the
> > > typically, but not necessarily quick operations. At the same time it is
> > > where you're rightfully afraid that the less common case might not
> > > receive much testing in management tools.
> > >
> >
> > I believe management tools / libvirt will want to use the async variant
> if
> > available. (the sync version is a one-command at a time constrained
> version
> > of 'async')
>
> The point here is rather that even async commands degenerate into sync
> commands if the management tool doesn't send multiple commands in
> parallel.
>
> If sending only a single command at a time is the common case (which
> appears quite plausible to me), then race conditions that exist when
> multiple commands are used in a rarer case might go unnoticed because
> nobody gave the scenario real testing.
>

I think the problem exists today regardless of my proposal for the
'hidden-async' commands (and block jobs?)


>
> > > In the end, I'm unsure whether async commands are a good idea, I can
> > > see good arguments for both stances. But I'm almost certain that
> > > they are the wrong tool for jobs.
> > >
> > >
> > Well, we already have 'async' commands, they are just hidden. They do
> > not use QAPI/QMP facility and lack consistency.
> >
> > This series addresses the problem 1), internal to qemu.
> >
> > And also proposes to replace the idiomatic:
> >
> >     -> { "execute": "do-foo",  "id": 42
> > }
> >
> >     <- { "return": {}, "id": 42 }            (this is a dummy useless
> > return)
> >     (foo is in fact async, you may do other commands here)
>
> I know you like to insist on its uselessness, but no, it's not useless.
> It tells the management tool that the background job has successfully
> been started and block job management commands can be used with it now.
>

Yes, some commands/API may return to indicate something started, and that
some state change happened.

But for many commands that doesn't make sense to have an intermediary
reply, it's really a dummy/empty return. The caller waits for a result.


> >
> >     <- { "event": "FOO_DONE" }     (this is a broadcasted event that
> other
> > monitor may not know how to deal with, lack of consistency with naming
> for
> > various async op, "id" field may be lost, no facilities in generated code
> > etc etc)
>
> Are these theoretical concerns or do you see them confirmed with
> actually existing commands?
>
>
I think existing commands using this event pattern are all global. The
problems raise if we start using events for local commands (such as
screendump, dump-guest-memory, query-* etc), then various peers may
conflict the completion event from a different client command.


> The broadcast is actually a feature, as mentioned above, because it
> allows libvirt to reconnect after losing the connection and continue to
> control the background operation.
>
>
For global state change, yes, broadcast events are necessary.


> > with a streamlined:
> >
> >     -> { "execute": "do-foo", "id": 42 }
> >     (you may do other commands here)
> >
> >
> >     <- { "return": {}, "id": 42 }       (returned only to the caller)
> >     (if there is a global state change, there should also be a FOO_DONE
> > event)
> >
> > As pointed out in the cover letter, existing client *have to* deal with
> > dispatching unrelated messages when sending commands, because events may
> > come before a return message. So they have facilities to handle async
> > replies.
> >
> > But in any case, this streamlined version is behind a "async" QMP
> > capability.
> >
> > I have been careful to not expose this change to qemu internal or qemu
> > client if they don't want or need it.
>
> The question is whether enough users (command implementations and
> clients) need the change to justify maintaining another type of commands
> long term. Just not breaking existing users doesn't justify a new
> feature, it's only the most basic requirement for it to even be
> considered.
>

The proposal is pretty limited. It's not intended to replace the "global"
existing commands API. It's:

1) help blocking commands:
a) internal qapi improvement to allow reentering the main-loop
b) allow to cancel if the client is disconnected

2) protocol improvement:
a) to avoid an unnecessary dummy return and the broadcast of a potentially
conflicting event for "local" commands
b) if the client support 'async', allow to run concurrent async commands

Your concern regarding async testing exist at a different protocol level
when commands use the cmd + event pattern (hidden-async), regardless of
this proposal.

-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-02  9:05           ` Marc-André Lureau
@ 2017-05-02 10:42             ` Kevin Wolf
  0 siblings, 0 replies; 61+ messages in thread
From: Kevin Wolf @ 2017-05-02 10:42 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Markus Armbruster, Jeff Cody, qemu-devel, kraxel,
	Stefan Hajnoczi, John Snow

Am 02.05.2017 um 11:05 hat Marc-André Lureau geschrieben:
> On Fri, Apr 28, 2017 at 11:13 PM Kevin Wolf <kwolf@redhat.com> wrote:
> 
> > Am 28.04.2017 um 17:55 hat Marc-André Lureau geschrieben:
> > > On Tue, Apr 25, 2017 at 2:23 PM Kevin Wolf <kwolf@redhat.com> wrote:
> > >
> > > > Am 24.04.2017 um 21:10 hat Markus Armbruster geschrieben:
> > > > > With 2.9 out of the way, how can we make progress on this one?
> > > > >
> > > > > I can see two ways to get asynchronous QMP commands accepted:
> > > > >
> > > > > 1. We break QMP compatibility in QEMU 3.0 and convert all
> > long-running
> > > > >    tasks from "synchronous command + event" to "asynchronous
> > command".
> > > > >
> > > > >    This is design option 1 quoted below.  *If* we decide to leave
> > > > >    compatibility behind for 3.0, *and* we decide we like the
> > > > >    asynchronous sufficiently better to put in the work, we can do it.
> > > > >
> > > > >    I guess there's nothing to do here until we decide on breaking
> > > > >    compatibility in 3.0.
> > > > >
> > > > > 2. We don't break QMP compatibility, but we add asynchronous commands
> > > > >    anyway, because we decide that's how we want to do "jobs".
> > > > >
> > > > >    This is design option 3 quoted below.  As I said, I dislike its
> > lack
> > > > >    of orthogonality.  But if asynchronous commands help us get jobs
> > > > >    done, I can bury my dislike.
> > > >
> > > > I don't think async commands are attractive at all for doing jobs. I
> > >
> > > It's still a bit obscure to me what we mean by "jobs".
> >
> > I guess the best definition that we have is: Image streaming, mirroring,
> > live backup, live commit and future "similar things".
> 
> What does it mean in terms of QAPI/QMP protocol ? If I need to write a new
> "job" (for something else than block op), is there some doc or guideline?

Well, we don't have a generic job API yet, so there can't be one. The
problem with using the current block job API for other things is that
block jobs are tied to one owner BlockDriverState (which made sense for
the very first block job, but already since the second one it doesn't
really match reality any more, because more than one image file is
involved in the other block job types).

John is working on generalising things so that we get a job API that can
be used for more than just block jobs.

> > > feel they bring up more questions that they answer, for example, what
> > > > happens if libvirt crashes and then reconnects? Which monitor
> > connection
> > > > does get the reply for an async command sent on the now disconnected
> > > > one?
> > > >
> > >
> > > The monitor to receive a reply is the one that sent the command (just
> > > like return today)
> > >
> > > As explained in the cover letter, an async command may cancel the
> > > ongoing operation on disconnect.
> >
> > But that's not what you generally want. You don't want to abort your
> > backup just because libvirt lost its monitor connection, but qemu should
> > continue to copy the data, and when libvirt reconnects it should be able
> > to get back control of this background operation and bring it to
> > successful completion.
> 
> I said "may", and I make a difference between "local" (to the client) and
> "global" (to qemu) operation.

The "may" doesn't help you because it's your only option as long as you
don't have a mechanism to attach an already running command to a new
monitor.

But the local vs. global thing that you detailed below makes sense and
now I think we were really talking past each other. Block jobs are very
much global, and so we actually agree that this proposal has nothing to
do with the operations that are currently block jobs. I guess what I'm
really arguing against then is what Markus made of your proposal in his
reply (which is when I got CCed).

> > > > On the other hand, using the traditional job infrastructure is way
> > > > over the top if all you want to do is 'query-block', so we need
> > > > something different for making it async. And if a client
> > > > disconnects, the 'query-block' result can just be thrown away, it's
> > > > much simpler than actual jobs.
> > >
> > > I agree a fully-featured job infrastructure is way over the top, and I
> > > believe I propose a minimal change to make optionnally some QMP
> > > commands async.
> >
> > So are commands like 'query-block' (which are typically _not_ considered
> > long-running) what you're aiming for with your proposal? This is a case
> > where I think we could consider the use of async QMP commands, but I
> > didn't have the impression that this kind of commands was your primary
> > target.
> >
> 
> Typically, I would like to improve the case described in the cover
> letter where we have:
> 
> -> { "execute": "do-foo" }
> <- { "return": {} }
> <- { "event": "FOO_DONE" }
> 
> Let's call this an "hidden-async" (I will refer to this pattern later).

This is not a good description of what you really seem to be after,
because the hidden-async pattern is what is used for real long-running,
global impact commands like the block jobs, too.

You only seem to want to replace it if 'do-foo' is a "local" operation,
and then that's much more agreeable than if we were to apply it to every
operation, including "global" ones.

> And do instead:
> 
> -> { "execute": "do-foo" }
> <- { "return": {} }
> 
> (I won't repeat the flaws of the current status quo here, see cover and
> thread)
> 
> But any blocking (even shortly) operation could also benefit from this
> series by using the async variant to allow reentering the loop. This
> is the 1). I suppose 'query-block' is a good candidate, and typically
> could cancel itself it the client is gone.
> 
> 2) is an extra, if the client supports concurrent commands.

I believe allowing 1) is a good idea anyway. Whether or not we need 2)
is a different discussion, but given the scope of the proposal that I
understand now, possibly not one in which I need to participate.

> > >     <- { "event": "FOO_DONE" }     (this is a broadcasted event that
> > other
> > > monitor may not know how to deal with, lack of consistency with naming
> > for
> > > various async op, "id" field may be lost, no facilities in generated code
> > > etc etc)
> >
> > Are these theoretical concerns or do you see them confirmed with
> > actually existing commands?
> >
> I think existing commands using this event pattern are all global. The
> problems raise if we start using events for local commands (such as
> screendump, dump-guest-memory, query-* etc), then various peers may
> conflict the completion event from a different client command.

So what you're really trying is not to replace existing hidden-async
patterns (which are for global operations, so events are wanted), but
to avoid introducing the pattern for new, local operations.

I think this is one of the most important points where the
misunderstandings came from.

> Your concern regarding async testing exist at a different protocol
> level when commands use the cmd + event pattern (hidden-async),
> regardless of this proposal.

This was Markus' concern, I was just trying to explain how I understand
it. And I still think it's a valid concern, but you're right that cmd +
event isn't much different. It's mostly the comparison between sync and
either of the async models that is interesting here.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
                   ` (27 preceding siblings ...)
  2017-01-25 15:16 ` Markus Armbruster
@ 2017-05-04 19:01 ` Markus Armbruster
  2017-05-05  9:00   ` Marc-André Lureau
  2017-05-05 12:27   ` Kevin Wolf
  28 siblings, 2 replies; 61+ messages in thread
From: Markus Armbruster @ 2017-05-04 19:01 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, kraxel, John Snow, Kevin Wolf, Stefan Hajnoczi

I figure everyone interested has had his say.  Let me try to summarize
and draw my conclusions.

Commands + events can replace asynchronous commands (they did).

Asynchronous commands cannot replace events, because "interesting" side
effects of commands need to be broadcast.  Doesn't mean asynchronous
commands can't make sense for us.  Does mean that we need to address any
serious flaws in the existing commands + event mechanism even if we
adopt asynchronous commands.  The cover letter lists multiple flaws,
which I'll discuss inline.

If an operation satisfies certain conditions, then implementing it as
asynchronous command provides certain benefits.  If the operation

(C1) does not need to broadcast state changes, including start and end
     of operation, and

(C2) even the initiating client needs no state change notifications
     except for end of operation, and

(C3) even that isn't needed when the client loses the connection and
     reconnects, and

(C4) the operation doesn't have to be examined or controlled while it
     runs,

then making it an asynchronous command

(B1) saves you the trouble of defining an event together with its link
     to the command, and

(B2) saves you the trouble of sending the event, and

(B3) saves a bit of QMP traffic, namely the event broadcast.

Letting clients opt into the asynchronousness as this series does
provides an additional benefit:

(B4) when you find one of your synchronous commands is at times taking
     too long, you can compatibly evolve it.

We can remove (C3) and (C4) by providing suitable ways to examine and
control asynchronous commands while they run.

We could remove (C1) and (C2) by sending events, but that would also
lose pretty much all benefits.

The operation chosen to showcase asynchronous commands is taking
screenshots.  It obviously satisfies (C1).  I guess for (C2) and (C4) we
have to assume that it completes "quickly".  I'm willing to buy that.
(C3) seems pretty dubious to me, however.

The tradeoff to judge is desirability of the benefits vs. cost to get
them.

Desirability depends on how many commands satisfy these conditions, and
how much trouble exactly is saved.

A list of commands that is more complete than just "screendump" would
help with the former.  query- commands that need to gather information
in ways that could block are among the candidates.

On the latter, I figure (B1) dwarves (B2), (B3) is a relatively minor
optimization unless proven otherwise, and (B4) is real, but asynchronous
commands are not the only way to get it; we can equally well evolve
synchronous commands compatibly into synchronous + event.

The cost is interface and implementation complexity.

Interface complexity increases because we add the concept "asynchronous
command" and the concept "synchronous or asynchronous command, client's
choice".  This is my main concern.

Implementation complexity isn't prohibitive according to diffstat, but
it's not neglible, either: with the last six patches peeled off, we get
some 500 additional lines plus some 300 in tests/.  The last six patches
put the new infrastructure to work, which takes another 200.  Ways to
examine and control asynchronous commands while they run would add some
more, but we don't know how much exactly.

Now let me take a step back: we need to crack the "jobs" problem anyway.
Merging this series now would in a way add another special case of the
general case "jobs" before adding the general case.  In other words,
create more stuff to unify.  I'm afraid that's a bad idea, not least
since it's an external interface.  I think we should do "jobs" first.
Once we got at least a prototype, we can

* judge how onerous defining and implementing jobs really is, i.e. have
  a clearer idea of the potential benefits of asynchronous commands, and

* explore asynchronous commands as a special case of "jobs" optimized
  for operations that satisfy the conditions above, i.e. get a clearer
  idea of the *actual* additional implementation complexity.

Bottom line:

1. I still don't want to merge this.

2. I want us to tackle jobs sooner rather than later.

3. Once we got at least a jobs prototype, I'm willing to reconsider
   asynchronous commands implemented as special case of jobs.

One of the most important maintainer duties is saying "no".  It's also
one of the least fun duties.


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

> 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.
>
> Note that qmp events are asynchronous messages, and must be handled
> appropriately by the client: dispatch both reply and events after a
> command is sent for example.
>
> The benefits of async commands that can be trade-off depending on the
> requirements are:
>
> 1) allow 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 tricky
> (see below) to solve.  Furthermore, many QMP commands do IO and could
> be considered 'slow' and blocking today.
>
> 2) allow concurrent commands and events. This mainly implies hanlding
> concurrency in qemu and out-of-order replies for the client. As noted
> earlier, a good qmp client already has to handle dispatching of
> received messages (reply and events).
>
> The traditional approach to solving the above in qemu is the following
> scheme:
> -> { "execute": "do-foo" }
> <- { "return": {} }
> <- { "event": "FOO_DONE" }
>
> It has several flaws:

Since asynchronous commands can't replace events outright, all of these
flaws stay even if we adopt asynchronous commands.  Any serious flaws
need fixing in other ways.

> - FOO_DONE event has no semantic link with do-foo in the qapi
>   schema. It is not simple to generalize that pattern when writing
>   qmp clients. It makes documentation and usage harder.

I consider this serious enough to be worth fixing.  We can either adopt
suitable naming and documentation conventions, or have commands declare
the events they can trigger.  I think the latter makes sense only if we
can flag violations somehow.

> - the FOO_DONE event has no clear association with the command that
>   triggered it: commands/events have to come up with additional
>   specific association schemes (ids, path etc)

Existing events that need to be linked certainly have one.  But there is
no single documented convention for such links.  Well worth fixing; I'd
love to have a single convention for linking events to commands.

We could then assert that an event's linked command declares the event.

> - FOO_DONE is broadcasted to all clients, but they may have no way to
>   interprete it or interest in it, or worse it may conflict with their
>   own commands.

An event that can be "mislinked" by clients is a design flaw that needs
fixing.  A convention for linking (fix for the previous item) needs to
avoid this flaw.

> - the arguably useless empty reply return

Useless only if the client doesn't need to know that the (possibly
long-running) job has been started successfully.

> For some cases, it makes sense to use that scheme, or a more complete
> one: to have an "handler" associated with an on-going operation, that
> can be queried, modified, cancelled etc (block jobs etc). Also, some
> operations have a global side-effect, in which case that cmd+event
> scheme is right, as all clients are listening for global events.

I'm leaning more and more towards the idea that *any* long-running
operation implemented as command + event should be made an instance of
the future "job" abstraction, to give us a *uniform* way to examine and
control them all.

> However, for the simple case where a client want to perform a "local
> context" operation (dump, query etc), QAPI can easily do better
> without resorting to this pattern: it can send the reply when the
> operation is done. That would make QAPI schema, usage and
> documentation more obvious.
>
> The following series implements an async solution, by introducing a
> context associated with a command, it can:
> - defer the return
> - return only to the caller (no broadcasted event)
> - return with the 'id' associated with the call (as originally intended)
> - optionnally allow cancellation when the client is gone
> - track on-going qapi command(s) per client
>
> 1) 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.
>
> 2) allow concurrent commands when 'async' is negotiated. If the client
> doesn't support 'async', then the monitor is suspended during command
> execution (events are still sent). Effectively, async commands behave
> like normal commands from client POV in this case, giving full
> backward compatibility.
>
> 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). HMP remains sync, but it would be worth to make
> it possible to call async:true qapi commands.
>
> The last patch cleans up qmp_dispatch usage to have consistant checks
> between qga & qemu, and simplify QmpClient/parser_feed usage.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-04 19:01 ` Markus Armbruster
@ 2017-05-05  9:00   ` Marc-André Lureau
  2017-05-05 12:35     ` Markus Armbruster
  2017-05-05 12:27   ` Kevin Wolf
  1 sibling, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-05-05  9:00 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, John Snow, qemu-devel, Stefan Hajnoczi, kraxel

Hi

On Thu, May 4, 2017 at 11:02 PM Markus Armbruster <armbru@redhat.com> wrote:

> I figure everyone interested has had his say.  Let me try to summarize
> and draw my conclusions.
>
> Commands + events can replace asynchronous commands (they did).
>
> Asynchronous commands cannot replace events, because "interesting" side
> effects of commands need to be broadcast.  Doesn't mean asynchronous
> commands can't make sense for us.  Does mean that we need to address any
> serious flaws in the existing commands + event mechanism even if we
> adopt asynchronous commands.  The cover letter lists multiple flaws,
> which I'll discuss inline.
>
> If an operation satisfies certain conditions, then implementing it as
> asynchronous command provides certain benefits.  If the operation
>
> (C1) does not need to broadcast state changes, including start and end
>      of operation, and
>
> (C2) even the initiating client needs no state change notifications
>      except for end of operation, and
>
> (C3) even that isn't needed when the client loses the connection and
>      reconnects, and
>
> (C4) the operation doesn't have to be examined or controlled while it
>      runs,
>
> then making it an asynchronous command
>
> (B1) saves you the trouble of defining an event together with its link
>      to the command, and
>
> (B2) saves you the trouble of sending the event, and
>
> (B3) saves a bit of QMP traffic, namely the event broadcast.
>
> Letting clients opt into the asynchronousness as this series does
> provides an additional benefit:
>
> (B4) when you find one of your synchronous commands is at times taking
>      too long, you can compatibly evolve it.
>
> We can remove (C3) and (C4) by providing suitable ways to examine and
> control asynchronous commands while they run.
>
> We could remove (C1) and (C2) by sending events, but that would also
> lose pretty much all benefits.
>
> The operation chosen to showcase asynchronous commands is taking
> screenshots.  It obviously satisfies (C1).  I guess for (C2) and (C4) we
> have to assume that it completes "quickly".  I'm willing to buy that.
> (C3) seems pretty dubious to me, however.
>
> The tradeoff to judge is desirability of the benefits vs. cost to get
> them.
>
> Desirability depends on how many commands satisfy these conditions, and
> how much trouble exactly is saved.
>
> A list of commands that is more complete than just "screendump" would
> help with the former.  query- commands that need to gather information
> in ways that could block are among the candidates.
>
> On the latter, I figure (B1) dwarves (B2), (B3) is a relatively minor
> optimization unless proven otherwise, and (B4) is real, but asynchronous
> commands are not the only way to get it; we can equally well evolve
> synchronous commands compatibly into synchronous + event.
>
> The cost is interface and implementation complexity.
>
> Interface complexity increases because we add the concept "asynchronous
> command" and the concept "synchronous or asynchronous command, client's
> choice".  This is my main concern.
>

Since we already have client dispatch of unrelated reply and hidden-async
pattern, this is less of a concern in practice, most of the complexity has
to be already handled.

Note it is a bit simpler for a client to handle a generic async return
rather than various events.


> Implementation complexity isn't prohibitive according to diffstat, but
> it's not neglible, either: with the last six patches peeled off, we get
> some 500 additional lines plus some 300 in tests/.  The last six patches
> put the new infrastructure to work, which takes another 200.  Ways to
> examine and control asynchronous commands while they run would add some
> more, but we don't know how much exactly.
>
> Now let me take a step back: we need to crack the "jobs" problem anyway.
> Merging this series now would in a way add another special case of the
> general case "jobs" before adding the general case.  In other words,
> create more stuff to unify.  I'm afraid that's a bad idea, not least
> since it's an external interface.  I think we should do "jobs" first.
> Once we got at least a prototype, we can
>
> * judge how onerous defining and implementing jobs really is, i.e. have
>   a clearer idea of the potential benefits of asynchronous commands, and
>
> * explore asynchronous commands as a special case of "jobs" optimized
>   for operations that satisfy the conditions above, i.e. get a clearer
>   idea of the *actual* additional implementation complexity.
>

That's what I have been told for over 1.5y :) I would like to know the list
of requirements / features "jobs" would have. I am willing to help
implementing it.

>
> Bottom line:
>
> 1. I still don't want to merge this.
>
> 2. I want us to tackle jobs sooner rather than later.
>
> 3. Once we got at least a jobs prototype, I'm willing to reconsider
>    asynchronous commands implemented as special case of jobs.
>
>
Who is going to work on it?


> One of the most important maintainer duties is saying "no".  It's also
> one of the least fun duties.
>
>
It doesn't sound like a "no" :)


>
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
> > 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.
> >
> > Note that qmp events are asynchronous messages, and must be handled
> > appropriately by the client: dispatch both reply and events after a
> > command is sent for example.
> >
> > The benefits of async commands that can be trade-off depending on the
> > requirements are:
> >
> > 1) allow 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 tricky
> > (see below) to solve.  Furthermore, many QMP commands do IO and could
> > be considered 'slow' and blocking today.
> >
> > 2) allow concurrent commands and events. This mainly implies hanlding
> > concurrency in qemu and out-of-order replies for the client. As noted
> > earlier, a good qmp client already has to handle dispatching of
> > received messages (reply and events).
> >
> > The traditional approach to solving the above in qemu is the following
> > scheme:
> > -> { "execute": "do-foo" }
> > <- { "return": {} }
> > <- { "event": "FOO_DONE" }
> >
> > It has several flaws:
>
> Since asynchronous commands can't replace events outright, all of these
> flaws stay even if we adopt asynchronous commands.  Any serious flaws
> need fixing in other ways.
>
> > - FOO_DONE event has no semantic link with do-foo in the qapi
> >   schema. It is not simple to generalize that pattern when writing
> >   qmp clients. It makes documentation and usage harder.
>
> I consider this serious enough to be worth fixing.  We can either adopt
> suitable naming and documentation conventions, or have commands declare
> the events they can trigger.  I think the latter makes sense only if we
> can flag violations somehow.
>
> > - the FOO_DONE event has no clear association with the command that
> >   triggered it: commands/events have to come up with additional
> >   specific association schemes (ids, path etc)
>
> Existing events that need to be linked certainly have one.  But there is
> no single documented convention for such links.  Well worth fixing; I'd
> love to have a single convention for linking events to commands.
>
> We could then assert that an event's linked command declares the event.
>
> > - FOO_DONE is broadcasted to all clients, but they may have no way to
> >   interprete it or interest in it, or worse it may conflict with their
> >   own commands.
>
> An event that can be "mislinked" by clients is a design flaw that needs
> fixing.  A convention for linking (fix for the previous item) needs to
> avoid this flaw.
>
> > - the arguably useless empty reply return
>
> Useless only if the client doesn't need to know that the (possibly
> long-running) job has been started successfully.
>
> > For some cases, it makes sense to use that scheme, or a more complete
> > one: to have an "handler" associated with an on-going operation, that
> > can be queried, modified, cancelled etc (block jobs etc). Also, some
> > operations have a global side-effect, in which case that cmd+event
> > scheme is right, as all clients are listening for global events.
>
> I'm leaning more and more towards the idea that *any* long-running
> operation implemented as command + event should be made an instance of
> the future "job" abstraction, to give us a *uniform* way to examine and
> control them all.
>
> > However, for the simple case where a client want to perform a "local
> > context" operation (dump, query etc), QAPI can easily do better
> > without resorting to this pattern: it can send the reply when the
> > operation is done. That would make QAPI schema, usage and
> > documentation more obvious.
> >
> > The following series implements an async solution, by introducing a
> > context associated with a command, it can:
> > - defer the return
> > - return only to the caller (no broadcasted event)
> > - return with the 'id' associated with the call (as originally intended)
> > - optionnally allow cancellation when the client is gone
> > - track on-going qapi command(s) per client
> >
> > 1) 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.
> >
> > 2) allow concurrent commands when 'async' is negotiated. If the client
> > doesn't support 'async', then the monitor is suspended during command
> > execution (events are still sent). Effectively, async commands behave
> > like normal commands from client POV in this case, giving full
> > backward compatibility.
> >
> > 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). HMP remains sync, but it would be worth to make
> > it possible to call async:true qapi commands.
> >
> > The last patch cleans up qmp_dispatch usage to have consistant checks
> > between qga & qemu, and simplify QmpClient/parser_feed usage.
>
> --
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-04 19:01 ` Markus Armbruster
  2017-05-05  9:00   ` Marc-André Lureau
@ 2017-05-05 12:27   ` Kevin Wolf
  2017-05-05 12:51     ` Markus Armbruster
  1 sibling, 1 reply; 61+ messages in thread
From: Kevin Wolf @ 2017-05-05 12:27 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Marc-André Lureau, qemu-devel, kraxel, John Snow, Stefan Hajnoczi

Am 04.05.2017 um 21:01 hat Markus Armbruster geschrieben:
> Now let me take a step back: we need to crack the "jobs" problem anyway.
> Merging this series now would in a way add another special case of the
> general case "jobs" before adding the general case.  In other words,
> create more stuff to unify.

It's actually not obvious to me that both cases should be using the same
infrastructure. The primary target for jobs as we discussed them in the
past are true long running operations (and in some common cases even
indefinitely, until the user stops them), whereas for async commands the
primary target are "quick, but not that quick" operations.

Today, all jobs have a unique job ID, all of them can be paused, all of
them send completion/cancellation events, and similar things that make a
lot of sense for true long running operations, but are either useless
overhead or can't even be implemented for quick operations. The
unification would potentially lead to many special cases in the job
infrastructure to allow e.g. anonymous jobs, jobs that aren't listed in
query-jobs, jobs that don't accept basic management commands like pause,
jobs that don't send completion events, etc. Would the (superficially)
unified infrastructure really be worth the special cases?

Just to be clear, I am not necessarily against unifying these two
classes of operations in our infrastructure if it makes sense, but they
seem to be distinct enough that I feel we should have a little more
arguments for it than just "they are the same anyway".

> > The benefits of async commands that can be trade-off depending on the
> > requirements are:
> >
> > 1) allow 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 tricky
> > (see below) to solve.  Furthermore, many QMP commands do IO and could
> > be considered 'slow' and blocking today.

In any case, I think we can go forward with this one, right? This should
be useful work no matter what we end up doing with the external
interface. I've long wished that QMP handlers could be executed in a
coroutine and yield while they are doing I/O.

> > 2) allow concurrent commands and events. This mainly implies hanlding
> > concurrency in qemu and out-of-order replies for the client. As noted
> > earlier, a good qmp client already has to handle dispatching of
> > received messages (reply and events).

And it's only this one that should wait for generic jobs.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-05  9:00   ` Marc-André Lureau
@ 2017-05-05 12:35     ` Markus Armbruster
  2017-05-05 12:54       ` Marc-André Lureau
  0 siblings, 1 reply; 61+ messages in thread
From: Markus Armbruster @ 2017-05-05 12:35 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Kevin Wolf, John Snow, qemu-devel, Stefan Hajnoczi, kraxel

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

> Hi
>
> On Thu, May 4, 2017 at 11:02 PM Markus Armbruster <armbru@redhat.com> wrote:
>
>> I figure everyone interested has had his say.  Let me try to summarize
>> and draw my conclusions.
>>
>> Commands + events can replace asynchronous commands (they did).
>>
>> Asynchronous commands cannot replace events, because "interesting" side
>> effects of commands need to be broadcast.  Doesn't mean asynchronous
>> commands can't make sense for us.  Does mean that we need to address any
>> serious flaws in the existing commands + event mechanism even if we
>> adopt asynchronous commands.  The cover letter lists multiple flaws,
>> which I'll discuss inline.
>>
>> If an operation satisfies certain conditions, then implementing it as
>> asynchronous command provides certain benefits.  If the operation
>>
>> (C1) does not need to broadcast state changes, including start and end
>>      of operation, and
>>
>> (C2) even the initiating client needs no state change notifications
>>      except for end of operation, and
>>
>> (C3) even that isn't needed when the client loses the connection and
>>      reconnects, and
>>
>> (C4) the operation doesn't have to be examined or controlled while it
>>      runs,
>>
>> then making it an asynchronous command
>>
>> (B1) saves you the trouble of defining an event together with its link
>>      to the command, and
>>
>> (B2) saves you the trouble of sending the event, and
>>
>> (B3) saves a bit of QMP traffic, namely the event broadcast.
>>
>> Letting clients opt into the asynchronousness as this series does
>> provides an additional benefit:
>>
>> (B4) when you find one of your synchronous commands is at times taking
>>      too long, you can compatibly evolve it.
>>
>> We can remove (C3) and (C4) by providing suitable ways to examine and
>> control asynchronous commands while they run.
>>
>> We could remove (C1) and (C2) by sending events, but that would also
>> lose pretty much all benefits.
>>
>> The operation chosen to showcase asynchronous commands is taking
>> screenshots.  It obviously satisfies (C1).  I guess for (C2) and (C4) we
>> have to assume that it completes "quickly".  I'm willing to buy that.
>> (C3) seems pretty dubious to me, however.
>>
>> The tradeoff to judge is desirability of the benefits vs. cost to get
>> them.
>>
>> Desirability depends on how many commands satisfy these conditions, and
>> how much trouble exactly is saved.
>>
>> A list of commands that is more complete than just "screendump" would
>> help with the former.  query- commands that need to gather information
>> in ways that could block are among the candidates.
>>
>> On the latter, I figure (B1) dwarves (B2), (B3) is a relatively minor
>> optimization unless proven otherwise, and (B4) is real, but asynchronous
>> commands are not the only way to get it; we can equally well evolve
>> synchronous commands compatibly into synchronous + event.
>>
>> The cost is interface and implementation complexity.
>>
>> Interface complexity increases because we add the concept "asynchronous
>> command" and the concept "synchronous or asynchronous command, client's
>> choice".  This is my main concern.
>>
>
> Since we already have client dispatch of unrelated reply and hidden-async
> pattern, this is less of a concern in practice, most of the complexity has
> to be already handled.

Yes, we already handle the abstract concept of kicking off operations
and getting notified when they change state.  But we handle it in *one*
abstract way: command + event(s).  Adding a second way (asynchronous
commands) can only increase complexity.

> Note it is a bit simpler for a client to handle a generic async return
> rather than various events.

I posit that the complexitity difference between zero and one instances
of command + event far exceeds the one between one and multiple.

Same for asynchronous commands.

The increase in conceptual complexity might be offset by a decrease in
individual operations' complexity.  That's (B1).

Your best estimate of the overall complexity change is more favourable
than mine.  That's okay, you're as entitled to your opinion as I am.
But my duty is to come up with my own best estimate, and act on it.

>> Implementation complexity isn't prohibitive according to diffstat, but
>> it's not neglible, either: with the last six patches peeled off, we get
>> some 500 additional lines plus some 300 in tests/.  The last six patches
>> put the new infrastructure to work, which takes another 200.  Ways to
>> examine and control asynchronous commands while they run would add some
>> more, but we don't know how much exactly.
>>
>> Now let me take a step back: we need to crack the "jobs" problem anyway.
>> Merging this series now would in a way add another special case of the
>> general case "jobs" before adding the general case.  In other words,
>> create more stuff to unify.  I'm afraid that's a bad idea, not least
>> since it's an external interface.  I think we should do "jobs" first.
>> Once we got at least a prototype, we can
>>
>> * judge how onerous defining and implementing jobs really is, i.e. have
>>   a clearer idea of the potential benefits of asynchronous commands, and
>>
>> * explore asynchronous commands as a special case of "jobs" optimized
>>   for operations that satisfy the conditions above, i.e. get a clearer
>>   idea of the *actual* additional implementation complexity.
>>
>
> That's what I have been told for over 1.5y :) I would like to know the list
> of requirements / features "jobs" would have. I am willing to help
> implementing it.

We have multiple use cases for generic jobs infrastructure in various
subsystems, but the ones driving the work are the block subsystem's,
simply because the existing block jobs need a major revamp anyway.  The
people most familiar with the requirements are John Snow, Kevin Wolf,
Stefan Hajnoczi, and to a lesser degree myself.  Recommend to meet John
in front of a big whiteboard, or else the next best way to talk things
over you two can find.

>> Bottom line:
>>
>> 1. I still don't want to merge this.
>>
>> 2. I want us to tackle jobs sooner rather than later.
>>
>> 3. Once we got at least a jobs prototype, I'm willing to reconsider
>>    asynchronous commands implemented as special case of jobs.
>>
>>
> Who is going to work on it?

I hope John can work on jobs.

>> One of the most important maintainer duties is saying "no".  It's also
>> one of the least fun duties.
>>
>>
> It doesn't sound like a "no" :)

Well, it's as close to "no" as you can get in a situation that's going
to change!  It's a straight "no" for the current situation, and a
"maybe" for a future situation that will be different in ways we don't
yet understand.

I'm *not* encouraging you to pursue asynchronous QMP commands.  In fact,
I never did, at least not knowingly.  It's your decision.  All I offer
is what I offer to all patch submitters: my best effort at a fair
hearing.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-05 12:27   ` Kevin Wolf
@ 2017-05-05 12:51     ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2017-05-05 12:51 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Marc-André Lureau, John Snow, qemu-devel, Stefan Hajnoczi, kraxel

Kevin Wolf <kwolf@redhat.com> writes:

> Am 04.05.2017 um 21:01 hat Markus Armbruster geschrieben:
>> Now let me take a step back: we need to crack the "jobs" problem anyway.
>> Merging this series now would in a way add another special case of the
>> general case "jobs" before adding the general case.  In other words,
>> create more stuff to unify.
>
> It's actually not obvious to me that both cases should be using the same
> infrastructure. The primary target for jobs as we discussed them in the
> past are true long running operations (and in some common cases even
> indefinitely, until the user stops them), whereas for async commands the
> primary target are "quick, but not that quick" operations.
>
> Today, all jobs have a unique job ID, all of them can be paused, all of
> them send completion/cancellation events, and similar things that make a
> lot of sense for true long running operations, but are either useless
> overhead or can't even be implemented for quick operations. The
> unification would potentially lead to many special cases in the job
> infrastructure to allow e.g. anonymous jobs, jobs that aren't listed in
> query-jobs, jobs that don't accept basic management commands like pause,
> jobs that don't send completion events, etc. Would the (superficially)
> unified infrastructure really be worth the special cases?
>
> Just to be clear, I am not necessarily against unifying these two
> classes of operations in our infrastructure if it makes sense, but they
> seem to be distinct enough that I feel we should have a little more
> arguments for it than just "they are the same anyway".

No, the best degree of sharing between asynchronous commands and jobs is
not obvious, simply because jobs do not exist, yet.  Once they do, we
can figure it out.

>> > The benefits of async commands that can be trade-off depending on the
>> > requirements are:
>> >
>> > 1) allow 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 tricky
>> > (see below) to solve.  Furthermore, many QMP commands do IO and could
>> > be considered 'slow' and blocking today.
>
> In any case, I think we can go forward with this one, right? This should
> be useful work no matter what we end up doing with the external
> interface. I've long wished that QMP handlers could be executed in a
> coroutine and yield while they are doing I/O.
>
>> > 2) allow concurrent commands and events. This mainly implies hanlding
>> > concurrency in qemu and out-of-order replies for the client. As noted
>> > earlier, a good qmp client already has to handle dispatching of
>> > received messages (reply and events).
>
> And it's only this one that should wait for generic jobs.

I think so.  Making synchronous QMP commands block only their QMP
monitor, not the whole main loop would be an implementation detail, not
part of the external interface.

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-05 12:35     ` Markus Armbruster
@ 2017-05-05 12:54       ` Marc-André Lureau
  2017-05-05 13:50         ` Markus Armbruster
  0 siblings, 1 reply; 61+ messages in thread
From: Marc-André Lureau @ 2017-05-05 12:54 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, John Snow, qemu-devel, Stefan Hajnoczi, kraxel

On Fri, May 5, 2017 at 4:35 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
> >> One of the most important maintainer duties is saying "no".  It's also
> >> one of the least fun duties.
> >>
> >>
> > It doesn't sound like a "no" :)
>
> Well, it's as close to "no" as you can get in a situation that's going
> to change!  It's a straight "no" for the current situation, and a
> "maybe" for a future situation that will be different in ways we don't
> yet understand.
>
> I'm *not* encouraging you to pursue asynchronous QMP commands.  In fact,
> I never did, at least not knowingly.  It's your decision.  All I offer
> is what I offer to all patch submitters: my best effort at a fair
> hearing.
>

My understanding is that you are mainly against the new client 'async'
capability. We disagree on the added complexity for the client though, as
in my opinion it already exists today in some hidden form. So would you
revisit the conclusion if the client 'async' capability is removed? The
series would still bring internal async capability, fix screendump bug and
do a bit of cleanup.


-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v2 00/25] qmp: add async command type
  2017-05-05 12:54       ` Marc-André Lureau
@ 2017-05-05 13:50         ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2017-05-05 13:50 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Kevin Wolf, John Snow, qemu-devel, Stefan Hajnoczi, kraxel

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

> On Fri, May 5, 2017 at 4:35 PM Markus Armbruster <armbru@redhat.com> wrote:
>
>> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>>
>> >> One of the most important maintainer duties is saying "no".  It's also
>> >> one of the least fun duties.
>> >>
>> >>
>> > It doesn't sound like a "no" :)
>>
>> Well, it's as close to "no" as you can get in a situation that's going
>> to change!  It's a straight "no" for the current situation, and a
>> "maybe" for a future situation that will be different in ways we don't
>> yet understand.
>>
>> I'm *not* encouraging you to pursue asynchronous QMP commands.  In fact,
>> I never did, at least not knowingly.  It's your decision.  All I offer
>> is what I offer to all patch submitters: my best effort at a fair
>> hearing.
>
> My understanding is that you are mainly against the new client 'async'
> capability. We disagree on the added complexity for the client though, as
> in my opinion it already exists today in some hidden form. So would you
> revisit the conclusion if the client 'async' capability is removed? The
> series would still bring internal async capability, fix screendump bug and
> do a bit of cleanup.

No, I'm concerned about the additional *concepts*.  How exactly they're
exposed in QMP is secondary.

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

end of thread, other threads:[~2017-05-05 13:51 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-18 16:03 [Qemu-devel] [PATCH v2 00/25] qmp: add async command type Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 01/25] tests: start generic qemu-qmp tests Marc-André Lureau
2017-01-18 16:14   ` Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 02/25] tests: change /0.15/* tests to /qmp/* Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 03/25] qmp: teach qmp_dispatch() to take a pre-filled QDict Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 04/25] qmp: use a return callback for the command reply Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 05/25] qmp: add QmpClient Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 06/25] qmp: add qmp_return_is_cancelled() Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 07/25] qmp: introduce async command type Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 08/25] qapi: ignore top-level 'id' field Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 09/25] qmp: take 'id' from request Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 10/25] qmp: check that async command have an 'id' Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 11/25] scripts: learn 'async' qapi commands Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 12/25] tests: add dispatch async tests Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 13/25] monitor: add 'async' capability Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 14/25] monitor: add !qmp pre-conditions Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 15/25] monitor: suspend when running async and client has no async Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 16/25] qmp: update qmp-spec about async capability Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 17/25] qtest: add qtest-timeout Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 18/25] qtest: add qtest_init_qmp_caps() Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 19/25] tests: add tests for async and non-async clients Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 20/25] qapi: improve 'screendump' documentation Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 21/25] console: graphic_hw_update return true if async Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 22/25] console: add graphic_hw_update_done() Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 23/25] console: make screendump async Marc-André Lureau
2017-01-19  8:20   ` Gerd Hoffmann
2017-01-20 13:07     ` Marc-André Lureau
2017-01-23 12:04       ` Gerd Hoffmann
2017-01-23 12:35         ` Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 24/25] qtest: add /qemu-qmp/screendump test Marc-André Lureau
2017-01-18 16:03 ` [Qemu-devel] [PATCH v2 25/25] qmp: move json-message-parser and check to QmpClient Marc-André Lureau
2017-01-18 17:35 ` [Qemu-devel] [PATCH v2 00/25] qmp: add async command type no-reply
2017-01-23 10:55 ` Stefan Hajnoczi
2017-01-23 11:27   ` Marc-André Lureau
2017-01-24 11:43     ` Stefan Hajnoczi
2017-01-24 18:43       ` Marc-André Lureau
2017-01-30 13:43         ` Stefan Hajnoczi
2017-01-30 18:18           ` Marc-André Lureau
2017-01-31  7:43             ` Gerd Hoffmann
2017-01-31  8:18               ` Markus Armbruster
2017-02-01 16:25             ` Stefan Hajnoczi
2017-02-01 20:25               ` Marc-André Lureau
2017-02-02 10:13                 ` Stefan Hajnoczi
2017-01-25 15:16 ` Markus Armbruster
2017-04-24 19:10   ` Markus Armbruster
2017-04-25  0:06     ` John Snow
2017-04-25  6:55       ` Markus Armbruster
2017-04-25  9:13     ` Daniel P. Berrange
2017-04-25 10:22     ` Kevin Wolf
2017-04-28 15:55       ` Marc-André Lureau
2017-04-28 19:13         ` Kevin Wolf
2017-05-02  8:30           ` Gerd Hoffmann
2017-05-02  9:05           ` Marc-André Lureau
2017-05-02 10:42             ` Kevin Wolf
2017-05-04 19:01 ` Markus Armbruster
2017-05-05  9:00   ` Marc-André Lureau
2017-05-05 12:35     ` Markus Armbruster
2017-05-05 12:54       ` Marc-André Lureau
2017-05-05 13:50         ` Markus Armbruster
2017-05-05 12:27   ` Kevin Wolf
2017-05-05 12:51     ` 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.