All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5
@ 2011-07-05 13:02 Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 01/18] Add hard build dependency on glib Michael Roth
                   ` (18 more replies)
  0 siblings, 19 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

This is Set 2/3 of the QAPI+QGA patchsets.

These patches apply on top of master (set1 merged), and can also be obtained
from:
git://repo.or.cz/qemu/mdroth.git qapi-backport-set2-v5

(Set1+2 are a backport of some of the QAPI-related work from Anthony's
glib tree. The main goal is to get the basic code generation infrastructure in
place so that it can be used by the guest agent to implement a QMP-like guest
interface, and so that future work regarding the QMP conversion to QAPI can be
decoupled from the infrastructure bits. Set3 is the Qemu Guest Agent
(virtagent), rebased on the new code QAPI code generation infrastructure. This
is the first user of QAPI, QMP will follow.)
___

This patchset introduces the following:

 - Hard dependency on GLib. This has been floating around the list for a while.
   Currently the only users are the unit tests for this patchset and the guest
   agent. We can make both of these a configure option, but based on previous
   discussions a hard dependency will likely be introduced with subsequent
   QAPI patches.

 - A couple additional qlist utility functions used by QAPI.

 - QAPI schema-based code generation for synchronous QMP/QGA commands
   and types, and Visitor/dispatch infrastructure to handle
   marshaling/unmarshaling/dispatch between QAPI and the QMP/QGA wire protocols.

 - Documentation and unit tests for visitor functions and synchronous
   command/type generation.

CHANGES SINCE V4:
 - Fix segfault in output visitor when dealing with QAPI-defined C structs
   with NULL pointers

CHANGES SINCE V3:
 - Added copyright headers for generated code and remaining files
 - Added checking for required/extra parameters in top-level of QMP QObject
 - Made QDict arg to input visitor constructor a const
 - Renamed qmp_dispatch_err() -> do_qmp_dispatch()
 - Changed QERR_QAPI_STACK_OVERRUN to QERR_BUFFER_OVERRUN
 - Moved configure changes to create QAPI directory when using a different build
   root to first patch which uses it.
 - Squashed Makefile changes for test-visitor/test-qmp-commands into single
   commits
 - Removed redundant NULL checks for qemu_free() in dealloc visitor

CHANGES SINCE V2:
 - Added cleanup functions for input/output visitor types and fixed a leak in
   dispatch path.
 - Corrected spelling from visiter->visitor and updated filenames accordingly.
 - Re-organized patches so that each new C file can be built as part of the
   introducting commit (for instances where there were no users of the
   qapi-obj-y target yet a test build was done by adding the target as a
   superficial dependency on other tools), and moved code generator patches
   after the required dependencies.
 - Made qlist_first/qlist_next accept/return const types.
 - Moved Visitor interface inline wrapper functions to real ones.
 - Fixed error-reporting for invalid parameters when parameter name is null.
 - Removed hard-coded size for QAPI-type allocations done by the input visitor,
   using generated code to pass in a sizeof() now.
 - Replaced assert()'s on visitor stack overruns, replaced with an error
   indication.
 - Fixed build issue when using a separate build directory.
 - Added missing copyright headers for scripts, moved external code in
   ordereddict.py to a seperate patch.
 - Many thanks to Luiz, Anthony, and everyone else for the excellent
   review/testing.

CHANGES SINCE V1:
 - Fixed build issue that was missed due to deprecated files being present in
   source tree. Thanks to Matsuda Daiki for sending fixes.
 - Fixed grammatical errors in documentation pointed out by Luiz.
 - Added generated code to the make clean target.

CHANGES SINCE V0 ("QAPI Infrastructure Round 1"):
 - Fixed known memory leaks in generated code
 - Stricter error-handling in generated code
 - Removed currently unused code (generators for events and async/proxied
   QMP/QGA commands and definition used by the not-yet-introduced QMP server
   replacement)
 - Added documentation for code generation scripts/schemas/usage
 - Addressed review comments from Luiz and Stefan

 Makefile                    |   24 +++-
 Makefile.objs               |    9 +
 Makefile.target             |    1 +
 configure                   |   14 ++
 docs/qapi-code-gen.txt      |  316 +++++++++++++++++++++++++++++++++++
 module.h                    |    2 +
 qapi-schema-test.json       |   22 +++
 qapi/qapi-dealloc-visitor.c |  138 ++++++++++++++++
 qapi/qapi-dealloc-visitor.h |   26 +++
 qapi/qapi-types-core.h      |   21 +++
 qapi/qapi-visit-core.c      |  114 +++++++++++++
 qapi/qapi-visit-core.h      |   68 ++++++++
 qapi/qmp-core.h             |   41 +++++
 qapi/qmp-dispatch.c         |  124 ++++++++++++++
 qapi/qmp-input-visitor.c    |  264 ++++++++++++++++++++++++++++++
 qapi/qmp-input-visitor.h    |   27 +++
 qapi/qmp-output-visitor.c   |  216 ++++++++++++++++++++++++
 qapi/qmp-output-visitor.h   |   28 +++
 qapi/qmp-registry.c         |   40 +++++
 qerror.h                    |    3 +
 qlist.h                     |   11 ++
 scripts/ordereddict.py      |  128 +++++++++++++++
 scripts/qapi-commands.py    |  381 +++++++++++++++++++++++++++++++++++++++++++
 scripts/qapi-types.py       |  258 +++++++++++++++++++++++++++++
 scripts/qapi-visit.py       |  261 +++++++++++++++++++++++++++++
 scripts/qapi.py             |  203 +++++++++++++++++++++++
 test-qmp-commands.c         |  113 +++++++++++++
 test-visitor.c              |  305 ++++++++++++++++++++++++++++++++++
 28 files changed, 3157 insertions(+), 1 deletions(-)

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

* [Qemu-devel] [PATCH v5 01/18] Add hard build dependency on glib
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 02/18] qlist: add qlist_first()/qlist_next() Michael Roth
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

From: Anthony Liguori <aliguori@us.ibm.com>

GLib is an extremely common library that has a portable thread implementation
along with tons of other goodies.

GLib and GObject have a fantastic amount of infrastructure we can leverage in
QEMU including an object oriented programming infrastructure.

Short term, it has a very nice thread pool implementation that we could leverage
in something like virtio-9p.  It also has a test harness implementation that
this series will use.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile        |    2 ++
 Makefile.objs   |    2 ++
 Makefile.target |    1 +
 configure       |   13 +++++++++++++
 4 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index b3ffbe2..42ae4e5 100644
--- a/Makefile
+++ b/Makefile
@@ -106,6 +106,8 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
 QEMU_CFLAGS+=$(CURL_CFLAGS)
 
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
 ui/cocoa.o: ui/cocoa.m
 
 ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
diff --git a/Makefile.objs b/Makefile.objs
index cea15e4..493c988 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -376,3 +376,5 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 
+vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
diff --git a/Makefile.target b/Makefile.target
index a53a2ff..b8256ae 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -203,6 +203,7 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
+QEMU_CFLAGS += $(GLIB_CFLAGS)
 
 # xen backend driver support
 obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
diff --git a/configure b/configure
index 88159ac..63156a2 100755
--- a/configure
+++ b/configure
@@ -1803,6 +1803,18 @@ EOF
 fi
 
 ##########################################
+# glib support probe
+if $pkg_config --modversion gthread-2.0 gio-2.0 > /dev/null 2>&1 ; then
+    glib_cflags=`$pkg_config --cflags gthread-2.0 gio-2.0 2>/dev/null`
+    glib_libs=`$pkg_config --libs gthread-2.0 gio-2.0 2>/dev/null`
+    libs_softmmu="$glib_libs $libs_softmmu"
+    libs_tools="$glib_libs $libs_tools"
+else
+    echo "glib-2.0 required to compile QEMU"
+    exit 1
+fi
+
+##########################################
 # pthread probe
 PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
 
@@ -2849,6 +2861,7 @@ if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ=y" >> $config_host_mak
   echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
 fi
+echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
 if test "$xen" = "yes" ; then
   echo "CONFIG_XEN=y" >> $config_host_mak
   echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 02/18] qlist: add qlist_first()/qlist_next()
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 01/18] Add hard build dependency on glib Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 03/18] qapi: add module init types for qapi Michael Roth
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qlist.h |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/qlist.h b/qlist.h
index dbe7b92..d426bd4 100644
--- a/qlist.h
+++ b/qlist.h
@@ -16,6 +16,7 @@
 #include "qobject.h"
 #include "qemu-queue.h"
 #include "qemu-common.h"
+#include "qemu-queue.h"
 
 typedef struct QListEntry {
     QObject *value;
@@ -50,4 +51,14 @@ QObject *qlist_peek(QList *qlist);
 int qlist_empty(const QList *qlist);
 QList *qobject_to_qlist(const QObject *obj);
 
+static inline const QListEntry *qlist_first(const QList *qlist)
+{
+    return QTAILQ_FIRST(&qlist->head);
+}
+
+static inline const QListEntry *qlist_next(const QListEntry *entry)
+{
+    return QTAILQ_NEXT(entry, next);
+}
+
 #endif /* QLIST_H */
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 03/18] qapi: add module init types for qapi
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 01/18] Add hard build dependency on glib Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 02/18] qlist: add qlist_first()/qlist_next() Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core Michael Roth
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 module.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/module.h b/module.h
index 9263f1c..ef66730 100644
--- a/module.h
+++ b/module.h
@@ -24,12 +24,14 @@ typedef enum {
     MODULE_INIT_BLOCK,
     MODULE_INIT_DEVICE,
     MODULE_INIT_MACHINE,
+    MODULE_INIT_QAPI,
     MODULE_INIT_MAX
 } module_init_type;
 
 #define block_init(function) module_init(function, MODULE_INIT_BLOCK)
 #define device_init(function) module_init(function, MODULE_INIT_DEVICE)
 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
+#define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
 
 void register_module_init(void (*fn)(void), module_init_type type);
 
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (2 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 03/18] qapi: add module init types for qapi Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-07 14:32   ` Luiz Capitulino
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor Michael Roth
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

Base definitions/includes for Visiter interface used by generated
visiter/marshalling code.

Includes a GenericList type. Our lists require an embedded element.
Since these types are generated, if you want to use them in a different
type of data structure, there's no easy way to add another embedded
element. The solution is to have non-embedded lists and that what this is.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs          |    6 +++
 configure              |    1 +
 qapi/qapi-types-core.h |   21 +++++++++
 qapi/qapi-visit-core.c |  114 ++++++++++++++++++++++++++++++++++++++++++++++++
 qapi/qapi-visit-core.h |   68 ++++++++++++++++++++++++++++
 5 files changed, 210 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qapi-types-core.h
 create mode 100644 qapi/qapi-visit-core.c
 create mode 100644 qapi/qapi-visit-core.h

diff --git a/Makefile.objs b/Makefile.objs
index 493c988..0077014 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -372,6 +372,12 @@ endif
 
 libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
 
+######################################################################
+# qapi
+
+qapi-nested-y = qapi-visit-core.o
+qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
+
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
diff --git a/configure b/configure
index 63156a2..02c552e 100755
--- a/configure
+++ b/configure
@@ -3486,6 +3486,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
 DIRS="$DIRS pc-bios/spapr-rtas"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
+DIRS="$DIRS qapi"
 FILES="Makefile tests/Makefile"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
new file mode 100644
index 0000000..de733ab
--- /dev/null
+++ b/qapi/qapi-types-core.h
@@ -0,0 +1,21 @@
+/*
+ * Core Definitions for QAPI-generated Types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_TYPES_CORE_H
+#define QAPI_TYPES_CORE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "error.h"
+
+#endif
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
new file mode 100644
index 0000000..c8a7805
--- /dev/null
+++ b/qapi/qapi-visit-core.c
@@ -0,0 +1,114 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-visit-core.h"
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    if (!error_is_set(errp) && v->start_handle) {
+        v->start_handle(v, obj, kind, name, errp);
+    }
+}
+
+void visit_end_handle(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp) && v->end_handle) {
+        v->end_handle(v, errp);
+    }
+}
+
+void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->start_struct(v, obj, kind, name, size, errp);
+    }
+}
+
+void visit_end_struct(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->end_struct(v, errp);
+    }
+}
+
+void visit_start_list(Visitor *v, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->start_list(v, name, errp);
+    }
+}
+
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        return v->next_list(v, list, errp);
+    }
+
+    return 0;
+}
+
+void visit_end_list(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->end_list(v, errp);
+    }
+}
+
+void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp)
+{
+    if (!error_is_set(errp) && v->start_optional) {
+        v->start_optional(v, present, name, errp);
+    }
+}
+
+void visit_end_optional(Visitor *v, Error **errp)
+{
+    if (!error_is_set(errp) && v->end_optional) {
+        v->end_optional(v, errp);
+    }
+}
+
+void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_enum(v, obj, kind, name, errp);
+    }
+}
+
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_int(v, obj, name, errp);
+    }
+}
+
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_bool(v, obj, name, errp);
+    }
+}
+
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_str(v, obj, name, errp);
+    }
+}
+
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+    if (!error_is_set(errp)) {
+        v->type_number(v, obj, name, errp);
+    }
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
new file mode 100644
index 0000000..8350a6d
--- /dev/null
+++ b/qapi/qapi-visit-core.h
@@ -0,0 +1,68 @@
+/*
+ * Core Definitions for QAPI Visitor Classes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+#ifndef QAPI_VISITOR_CORE_H
+#define QAPI_VISITOR_CORE_H
+
+#include "qapi/qapi-types-core.h"
+#include "error.h"
+#include <stdlib.h>
+
+typedef struct GenericList
+{
+    void *value;
+    struct GenericList *next;
+} GenericList;
+
+typedef struct Visitor Visitor;
+
+struct Visitor
+{
+    /* Must be set */
+    void (*start_struct)(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
+    void (*end_struct)(Visitor *v, Error **errp);
+
+    void (*start_list)(Visitor *v, const char *name, Error **errp);
+    GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
+    void (*end_list)(Visitor *v, Error **errp);
+
+    void (*type_enum)(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
+
+    void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
+    void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
+    void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
+    void (*type_number)(Visitor *v, double *obj, const char *name, Error **errp);
+
+    /* May be NULL */
+    void (*start_optional)(Visitor *v, bool *present, const char *name, Error **errp);
+    void (*end_optional)(Visitor *v, Error **errp);
+
+    void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
+    void (*end_handle)(Visitor *v, Error **errp);
+};
+
+void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
+void visit_end_handle(Visitor *v, Error **errp);
+void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
+void visit_end_struct(Visitor *v, Error **errp);
+void visit_start_list(Visitor *v, const char *name, Error **errp);
+GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
+void visit_end_list(Visitor *v, Error **errp);
+void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp);
+void visit_end_optional(Visitor *v, Error **errp);
+void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
+void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
+void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
+void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
+void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (3 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-07 14:32   ` Luiz Capitulino
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 06/18] qapi: add QMP output visitor Michael Roth
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

A type of Visiter class that is used to walk a qobject's
structure and assign each entry to the corresponding native C type.
Command marshaling function will use this to pull out QMP command
parameters recieved over the wire and pass them as native arguments
to the corresponding C functions.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs            |    2 +-
 qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-input-visitor.h |   27 +++++
 qerror.h                 |    3 +
 4 files changed, 295 insertions(+), 1 deletions(-)
 create mode 100644 qapi/qmp-input-visitor.c
 create mode 100644 qapi/qmp-input-visitor.h

diff --git a/Makefile.objs b/Makefile.objs
index 0077014..997ecef 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
 ######################################################################
 # qapi
 
-qapi-nested-y = qapi-visit-core.o
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
new file mode 100644
index 0000000..80912bb
--- /dev/null
+++ b/qapi/qmp-input-visitor.c
@@ -0,0 +1,264 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qmp-input-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+#define QIV_STACK_SIZE 1024
+
+typedef struct StackObject
+{
+    const QObject *obj;
+    const  QListEntry *entry;
+} StackObject;
+
+struct QmpInputVisitor
+{
+    Visitor visitor;
+    const QObject *obj;
+    StackObject stack[QIV_STACK_SIZE];
+    int nb_stack;
+};
+
+static QmpInputVisitor *to_qiv(Visitor *v)
+{
+    return container_of(v, QmpInputVisitor, visitor);
+}
+
+static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
+{
+    const QObject *qobj;
+
+    if (qiv->nb_stack == 0) {
+        qobj = qiv->obj;
+    } else {
+        qobj = qiv->stack[qiv->nb_stack - 1].obj;
+    }
+
+    if (name && qobject_type(qobj) == QTYPE_QDICT) {
+        return qdict_get(qobject_to_qdict(qobj), name);
+    } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
+    }
+
+    return qobj;
+}
+
+static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
+{
+    qiv->stack[qiv->nb_stack].obj = obj;
+    if (qobject_type(obj) == QTYPE_QLIST) {
+        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
+    }
+    qiv->nb_stack++;
+
+    if (qiv->nb_stack >= QIV_STACK_SIZE) {
+        error_set(errp, QERR_BUFFER_OVERRUN);
+        return;
+    }
+}
+
+static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
+{
+    qiv->nb_stack--;
+    if (qiv->nb_stack < 0) {
+        error_set(errp, QERR_BUFFER_OVERRUN);
+        return;
+    }
+}
+
+static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (obj) {
+        *obj = qemu_mallocz(size);
+    }
+}
+
+static void qmp_input_end_struct(Visitor *v, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj, errp);
+}
+
+static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    GenericList *entry;
+    StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+
+    if (so->entry == NULL) {
+        return NULL;
+    }
+
+    entry = qemu_mallocz(sizeof(*entry));
+    if (*list) {
+        so->entry = qlist_next(so->entry);
+        if (so->entry == NULL) {
+            qemu_free(entry);
+            return NULL;
+        }
+        (*list)->next = entry;
+    }
+    *list = entry;
+
+
+    return entry;
+}
+
+static void qmp_input_end_list(Visitor *v, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv, errp);
+}
+
+static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
+        return;
+    }
+
+    *obj = qint_get_int(qobject_to_qint(qobj));
+}
+
+static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
+        return;
+    }
+
+    *obj = qbool_get_int(qobject_to_qbool(qobj));
+}
+
+static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
+        return;
+    }
+
+    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
+}
+
+static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
+        return;
+    }
+
+    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+}
+
+static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    int64_t value;
+    qmp_input_type_int(v, &value, name, errp);
+    *obj = value;
+}
+
+static void qmp_input_start_optional(Visitor *v, bool *present,
+                                     const char *name, Error **errp)
+{
+    QmpInputVisitor *qiv = to_qiv(v);
+    const QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj) {
+        *present = false;
+        return;
+    }
+
+    *present = true;
+}
+
+static void qmp_input_end_optional(Visitor *v, Error **errp)
+{
+}
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qmp_input_visitor_cleanup(QmpInputVisitor *v)
+{
+    qemu_free(v);
+}
+
+QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
+{
+    QmpInputVisitor *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visitor.start_struct = qmp_input_start_struct;
+    v->visitor.end_struct = qmp_input_end_struct;
+    v->visitor.start_list = qmp_input_start_list;
+    v->visitor.next_list = qmp_input_next_list;
+    v->visitor.end_list = qmp_input_end_list;
+    v->visitor.type_enum = qmp_input_type_enum;
+    v->visitor.type_int = qmp_input_type_int;
+    v->visitor.type_bool = qmp_input_type_bool;
+    v->visitor.type_str = qmp_input_type_str;
+    v->visitor.type_number = qmp_input_type_number;
+    v->visitor.start_optional = qmp_input_start_optional;
+    v->visitor.end_optional = qmp_input_end_optional;
+
+    v->obj = obj;
+
+    return v;
+}
diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
new file mode 100644
index 0000000..0f77916
--- /dev/null
+++ b/qapi/qmp-input-visitor.h
@@ -0,0 +1,27 @@
+/*
+ * Input Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_INPUT_VISITOR_H
+#define QMP_INPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpInputVisitor QmpInputVisitor;
+
+QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
+void qmp_input_visitor_cleanup(QmpInputVisitor *v);
+
+Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
+
+#endif
diff --git a/qerror.h b/qerror.h
index 16c830d..9a9fa5b 100644
--- a/qerror.h
+++ b/qerror.h
@@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_JSON_PARSE_ERROR \
     "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
 
+#define QERR_BUFFER_OVERRUN \
+    "{ 'class': 'BufferOverrun', 'data': {} }"
+
 #define QERR_KVM_MISSING_CAP \
     "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
 
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 06/18] qapi: add QMP output visitor
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (4 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 07/18] qapi: add QAPI dealloc visitor Michael Roth
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

Type of Visiter class that serves as the inverse of the input visitor:
it takes a series of native C types and uses their values to construct a
corresponding QObject. The command marshaling/dispatcher functions will
use this to convert the output of QMP functions into a QObject that can
be sent over the wire.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs             |    2 +-
 qapi/qmp-output-visitor.c |  216 +++++++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-output-visitor.h |   28 ++++++
 3 files changed, 245 insertions(+), 1 deletions(-)
 create mode 100644 qapi/qmp-output-visitor.c
 create mode 100644 qapi/qmp-output-visitor.h

diff --git a/Makefile.objs b/Makefile.objs
index 997ecef..7f9cba5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
 ######################################################################
 # qapi
 
-qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
new file mode 100644
index 0000000..03a481c
--- /dev/null
+++ b/qapi/qmp-output-visitor.c
@@ -0,0 +1,216 @@
+/*
+ * Core Definitions for QAPI/QMP Command Registry
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qmp-output-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct QStackEntry
+{
+    QObject *value;
+    QTAILQ_ENTRY(QStackEntry) node;
+} QStackEntry;
+
+typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
+
+struct QmpOutputVisitor
+{
+    Visitor visitor;
+    QStack stack;
+};
+
+#define qmp_output_add(qov, name, value) qmp_output_add_obj(qov, name, QOBJECT(value))
+#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
+
+static QmpOutputVisitor *to_qov(Visitor *v)
+{
+    return container_of(v, QmpOutputVisitor, visitor);
+}
+
+static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
+{
+    QStackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static QObject *qmp_output_pop(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    QObject *value;
+    QTAILQ_REMOVE(&qov->stack, e, node);
+    value = e->value;
+    qemu_free(e);
+    return value;
+}
+
+static QObject *qmp_output_first(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+    return e->value;
+}
+
+static QObject *qmp_output_last(QmpOutputVisitor *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    return e->value;
+}
+
+static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, QObject *value)
+{
+    QObject *cur;
+
+    if (QTAILQ_EMPTY(&qov->stack)) {
+        qmp_output_push_obj(qov, value);
+        return;
+    }
+
+    cur = qmp_output_last(qov);
+
+    switch (qobject_type(cur)) {
+    case QTYPE_QDICT:
+        qdict_put_obj(qobject_to_qdict(cur), name, value);
+        break;
+    case QTYPE_QLIST:
+        qlist_append_obj(qobject_to_qlist(cur), value);
+        break;
+    default:
+        qobject_decref(qmp_output_pop(qov));
+        qmp_output_push_obj(qov, value);
+        break;
+    }
+}
+
+static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t unused, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    QDict *dict = qdict_new();
+
+    qmp_output_add(qov, name, dict);
+    qmp_output_push(qov, dict);
+}
+
+static void qmp_output_end_struct(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    QList *list = qlist_new();
+
+    qmp_output_add(qov, name, list);
+    qmp_output_push(qov, list);
+}
+
+static GenericList *qmp_output_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    GenericList *retval = *list;
+    *list = retval->next;
+    return retval;
+}
+
+static void qmp_output_end_list(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qint_from_int(*obj));
+}
+
+static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qbool_from_int(*obj));
+}
+
+static void qmp_output_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    if (*obj) {
+        qmp_output_add(qov, name, qstring_from_str(*obj));
+    } else {
+        qmp_output_add(qov, name, qstring_from_str(""));
+    }
+}
+
+static void qmp_output_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_add(qov, name, qfloat_from_double(*obj));
+}
+
+static void qmp_output_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    int64_t value = *obj;
+    qmp_output_type_int(v, &value, name, errp);
+}
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
+{
+    QObject *obj = qmp_output_first(qov);
+    if (obj) {
+        qobject_incref(obj);
+    }
+    return obj;
+}
+
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
+{
+    QStackEntry *e, *tmp;
+
+    QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
+        QTAILQ_REMOVE(&v->stack, e, node);
+        if (e->value) {
+            qobject_decref(e->value);
+        }
+        qemu_free(e);
+    }
+
+    qemu_free(v);
+}
+
+QmpOutputVisitor *qmp_output_visitor_new(void)
+{
+    QmpOutputVisitor *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visitor.start_struct = qmp_output_start_struct;
+    v->visitor.end_struct = qmp_output_end_struct;
+    v->visitor.start_list = qmp_output_start_list;
+    v->visitor.next_list = qmp_output_next_list;
+    v->visitor.end_list = qmp_output_end_list;
+    v->visitor.type_enum = qmp_output_type_enum;
+    v->visitor.type_int = qmp_output_type_int;
+    v->visitor.type_bool = qmp_output_type_bool;
+    v->visitor.type_str = qmp_output_type_str;
+    v->visitor.type_number = qmp_output_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qmp-output-visitor.h b/qapi/qmp-output-visitor.h
new file mode 100644
index 0000000..4a649c2
--- /dev/null
+++ b/qapi/qmp-output-visitor.h
@@ -0,0 +1,28 @@
+/*
+ * Output Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_OUTPUT_VISITOR_H
+#define QMP_OUTPUT_VISITOR_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpOutputVisitor QmpOutputVisitor;
+
+QmpOutputVisitor *qmp_output_visitor_new(void);
+void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
+
+QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
+Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 07/18] qapi: add QAPI dealloc visitor
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (5 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 06/18] qapi: add QMP output visitor Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 08/18] qapi: add QMP command registration/lookup functions Michael Roth
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

Type of Visitor class that can be passed into a qapi-generated C
type's visitor function to free() any heap-allocated data types.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs               |    2 +-
 qapi/qapi-dealloc-visitor.c |  138 +++++++++++++++++++++++++++++++++++++++++++
 qapi/qapi-dealloc-visitor.h |   26 ++++++++
 3 files changed, 165 insertions(+), 1 deletions(-)
 create mode 100644 qapi/qapi-dealloc-visitor.c
 create mode 100644 qapi/qapi-dealloc-visitor.h

diff --git a/Makefile.objs b/Makefile.objs
index 7f9cba5..08f69e5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
 ######################################################################
 # qapi
 
-qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o
+qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
new file mode 100644
index 0000000..7525df3
--- /dev/null
+++ b/qapi/qapi-dealloc-visitor.c
@@ -0,0 +1,138 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth   <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi-dealloc-visitor.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct StackEntry
+{
+    void *value;
+    QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QapiDeallocVisitor
+{
+    Visitor visitor;
+    QTAILQ_HEAD(, StackEntry) stack;
+};
+
+static QapiDeallocVisitor *to_qov(Visitor *v)
+{
+    return container_of(v, QapiDeallocVisitor, visitor);
+}
+
+static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
+{
+    StackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
+{
+    StackEntry *e = QTAILQ_FIRST(&qov->stack);
+    QObject *value;
+    QTAILQ_REMOVE(&qov->stack, e, node);
+    value = e->value;
+    qemu_free(e);
+    return value;
+}
+
+static void qapi_dealloc_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t unused, Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    qapi_dealloc_push(qov, obj);
+}
+
+static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
+{
+    QapiDeallocVisitor *qov = to_qov(v);
+    void **obj = qapi_dealloc_pop(qov);
+    if (obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
+{
+}
+
+static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    GenericList *retval = *list;
+    qemu_free(retval->value);
+    *list = retval->next;
+    return retval;
+}
+
+static void qapi_dealloc_end_list(Visitor *v, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    if (obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+}
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
+{
+    return &v->visitor;
+}
+
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
+{
+    qemu_free(v);
+}
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
+{
+    QapiDeallocVisitor *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visitor.start_struct = qapi_dealloc_start_struct;
+    v->visitor.end_struct = qapi_dealloc_end_struct;
+    v->visitor.start_list = qapi_dealloc_start_list;
+    v->visitor.next_list = qapi_dealloc_next_list;
+    v->visitor.end_list = qapi_dealloc_end_list;
+    v->visitor.type_enum = qapi_dealloc_type_enum;
+    v->visitor.type_int = qapi_dealloc_type_int;
+    v->visitor.type_bool = qapi_dealloc_type_bool;
+    v->visitor.type_str = qapi_dealloc_type_str;
+    v->visitor.type_number = qapi_dealloc_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qapi-dealloc-visitor.h b/qapi/qapi-dealloc-visitor.h
new file mode 100644
index 0000000..5842bc7
--- /dev/null
+++ b/qapi/qapi-dealloc-visitor.h
@@ -0,0 +1,26 @@
+/*
+ * Dealloc Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Michael Roth   <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QAPI_DEALLOC_VISITOR_H
+#define QAPI_DEALLOC_VISITOR_H
+
+#include "qapi-visit-core.h"
+
+typedef struct QapiDeallocVisitor QapiDeallocVisitor;
+
+QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
+void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
+
+Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 08/18] qapi: add QMP command registration/lookup functions
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (6 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 07/18] qapi: add QAPI dealloc visitor Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 09/18] qapi: add QMP dispatch functions Michael Roth
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

Registration/lookup functions for that provide a lookup table for
dispatching QMP commands.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs       |    1 +
 qapi/qmp-core.h     |   40 ++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-registry.c |   40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-core.h
 create mode 100644 qapi/qmp-registry.c

diff --git a/Makefile.objs b/Makefile.objs
index 08f69e5..55a94e4 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -376,6 +376,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
 # qapi
 
 qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
+qapi-nested-y += qmp-registry.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
new file mode 100644
index 0000000..99e929f
--- /dev/null
+++ b/qapi/qmp-core.h
@@ -0,0 +1,40 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QMP_CORE_H
+#define QMP_CORE_H
+
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
+
+typedef enum QmpCommandType
+{
+    QCT_NORMAL,
+} QmpCommandType;
+
+typedef struct QmpCommand
+{
+    const char *name;
+    QmpCommandType type;
+    QmpCommandFunc *fn;
+    QTAILQ_ENTRY(QmpCommand) node;
+} QmpCommand;
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn);
+QmpCommand *qmp_find_command(const char *name);
+
+#endif
+
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
new file mode 100644
index 0000000..3fe8866
--- /dev/null
+++ b/qapi/qmp-registry.c
@@ -0,0 +1,40 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Michael Roth      <mdroth@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qmp-core.h"
+
+static QTAILQ_HEAD(, QmpCommand) qmp_commands =
+    QTAILQ_HEAD_INITIALIZER(qmp_commands);
+
+void qmp_register_command(const char *name, QmpCommandFunc *fn)
+{
+    QmpCommand *cmd = qemu_mallocz(sizeof(*cmd));
+
+    cmd->name = name;
+    cmd->type = QCT_NORMAL;
+    cmd->fn = fn;
+    QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
+}
+
+QmpCommand *qmp_find_command(const char *name)
+{
+    QmpCommand *i;
+
+    QTAILQ_FOREACH(i, &qmp_commands, node) {
+        if (strcmp(i->name, name) == 0) {
+            return i;
+        }
+    }
+    return NULL;
+}
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 09/18] qapi: add QMP dispatch functions
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (7 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 08/18] qapi: add QMP command registration/lookup functions Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 10/18] qapi: add ordereddict.py helper library Michael Roth
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

Given an object recieved via QMP, this code uses the dispatch table
provided by qmp_registry.c to call the corresponding marshalling/dispatch
function and format return values/errors for delivery to the QMP.
Currently only synchronous QMP functions are supported, but this will
also be used for async QMP functions and QMP guest proxy dispatch as
well.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile.objs       |    2 +-
 qapi/qmp-core.h     |    1 +
 qapi/qmp-dispatch.c |  124 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+), 1 deletions(-)
 create mode 100644 qapi/qmp-dispatch.c

diff --git a/Makefile.objs b/Makefile.objs
index 55a94e4..d7c4cec 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -376,7 +376,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
 # qapi
 
 qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
-qapi-nested-y += qmp-registry.o
+qapi-nested-y += qmp-registry.o qmp-dispatch.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
index 99e929f..f1c26e4 100644
--- a/qapi/qmp-core.h
+++ b/qapi/qmp-core.h
@@ -35,6 +35,7 @@ typedef struct QmpCommand
 
 void qmp_register_command(const char *name, QmpCommandFunc *fn);
 QmpCommand *qmp_find_command(const char *name);
+QObject *qmp_dispatch(QObject *request);
 
 #endif
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
new file mode 100644
index 0000000..5584693
--- /dev/null
+++ b/qapi/qmp-dispatch.c
@@ -0,0 +1,124 @@
+/*
+ * Core Definitions for QAPI/QMP Dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "json-parser.h"
+#include "error.h"
+#include "error_int.h"
+#include "qerror.h"
+
+static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
+{
+    const QDictEntry *ent;
+    const char *arg_name;
+    const QObject *arg_obj;
+    bool has_exec_key = false;
+    QDict *dict = NULL;
+
+    if (qobject_type(request) != QTYPE_QDICT) {
+        error_set(errp, QERR_QMP_BAD_INPUT_OBJECT,
+                  "request is not a dictionary");
+        return NULL;
+    }
+
+    dict = qobject_to_qdict(request);
+
+    for (ent = qdict_first(dict); ent;
+         ent = qdict_next(dict, ent)) {
+        arg_name = qdict_entry_key(ent);
+        arg_obj = qdict_entry_value(ent);
+
+        if (!strcmp(arg_name, "execute")) {
+            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
+                error_set(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
+                          "string");
+                return NULL;
+            }
+            has_exec_key = true;
+        } else if (strcmp(arg_name, "arguments")) {
+            error_set(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
+            return NULL;
+        }
+    }
+
+    if (!has_exec_key) {
+        error_set(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
+        return NULL;
+    }
+
+    return dict;
+}
+
+static QObject *do_qmp_dispatch(QObject *request, Error **errp)
+{
+    const char *command;
+    QDict *args, *dict;
+    QmpCommand *cmd;
+    QObject *ret = NULL;
+
+
+    dict = qmp_dispatch_check_obj(request, errp);
+    if (!dict || error_is_set(errp)) {
+        return NULL;
+    }
+
+    command = qdict_get_str(dict, "execute");
+    cmd = qmp_find_command(command);
+    if (cmd == NULL) {
+        error_set(errp, QERR_COMMAND_NOT_FOUND, command);
+        return NULL;
+    }
+
+    if (!qdict_haskey(dict, "arguments")) {
+        args = qdict_new();
+    } else {
+        args = qdict_get_qdict(dict, "arguments");
+        QINCREF(args);
+    }
+
+    switch (cmd->type) {
+    case QCT_NORMAL:
+        cmd->fn(args, &ret, errp);
+        if (!error_is_set(errp) && ret == NULL) {
+            ret = QOBJECT(qdict_new());
+        }
+        break;
+    }
+
+    QDECREF(args);
+
+    return ret;
+}
+
+QObject *qmp_dispatch(QObject *request)
+{
+    Error *err = NULL;
+    QObject *ret;
+    QDict *rsp;
+
+    ret = do_qmp_dispatch(request, &err);
+
+    rsp = qdict_new();
+    if (err) {
+        qdict_put_obj(rsp, "error", error_get_qobject(err));
+        error_free(err);
+    } else if (ret) {
+        qdict_put_obj(rsp, "return", ret);
+    } else {
+        QDECREF(rsp);
+        return NULL;
+    }
+
+    return QOBJECT(rsp);
+}
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 10/18] qapi: add ordereddict.py helper library
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (8 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 09/18] qapi: add QMP dispatch functions Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 11/18] qapi: add qapi.py helper libraries Michael Roth
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

We need this to parse dictionaries with schema ordering intact so that C
prototypes can be generated deterministically.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/ordereddict.py |  128 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 128 insertions(+), 0 deletions(-)
 create mode 100644 scripts/ordereddict.py

diff --git a/scripts/ordereddict.py b/scripts/ordereddict.py
new file mode 100644
index 0000000..e17269f
--- /dev/null
+++ b/scripts/ordereddict.py
@@ -0,0 +1,128 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+#     The above copyright notice and this permission notice shall be
+#     included in all copies or substantial portions of the Software.
+#
+#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#     OTHER DEALINGS IN THE SOFTWARE.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__end
+        except AttributeError:
+            self.clear()
+        self.update(*args, **kwds)
+
+    def clear(self):
+        self.__end = end = []
+        end += [None, end, end]         # sentinel node for doubly linked list
+        self.__map = {}                 # key --> [key, prev, next]
+        dict.clear(self)
+
+    def __setitem__(self, key, value):
+        if key not in self:
+            end = self.__end
+            curr = end[1]
+            curr[2] = end[1] = self.__map[key] = [key, curr, end]
+        dict.__setitem__(self, key, value)
+
+    def __delitem__(self, key):
+        dict.__delitem__(self, key)
+        key, prev, next = self.__map.pop(key)
+        prev[2] = next
+        next[1] = prev
+
+    def __iter__(self):
+        end = self.__end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.__end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def popitem(self, last=True):
+        if not self:
+            raise KeyError('dictionary is empty')
+        if last:
+            key = reversed(self).next()
+        else:
+            key = iter(self).next()
+        value = self.pop(key)
+        return key, value
+
+    def __reduce__(self):
+        items = [[k, self[k]] for k in self]
+        tmp = self.__map, self.__end
+        del self.__map, self.__end
+        inst_dict = vars(self).copy()
+        self.__map, self.__end = tmp
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def keys(self):
+        return list(self)
+
+    setdefault = DictMixin.setdefault
+    update = DictMixin.update
+    pop = DictMixin.pop
+    values = DictMixin.values
+    items = DictMixin.items
+    iterkeys = DictMixin.iterkeys
+    itervalues = DictMixin.itervalues
+    iteritems = DictMixin.iteritems
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, self.items())
+
+    def copy(self):
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedDict):
+            if len(self) != len(other):
+                return False
+            for p, q in  zip(self.items(), other.items()):
+                if p != q:
+                    return False
+            return True
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other
+
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 11/18] qapi: add qapi.py helper libraries
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (9 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 10/18] qapi: add ordereddict.py helper library Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 12/18] qapi: add qapi-types.py code generator Michael Roth
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi.py |  203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 203 insertions(+), 0 deletions(-)
 create mode 100644 scripts/qapi.py

diff --git a/scripts/qapi.py b/scripts/qapi.py
new file mode 100644
index 0000000..56af232
--- /dev/null
+++ b/scripts/qapi.py
@@ -0,0 +1,203 @@
+#
+# QAPI helper library
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+
+def tokenize(data):
+    while len(data):
+        if data[0] in ['{', '}', ':', ',', '[', ']']:
+            yield data[0]
+            data = data[1:]
+        elif data[0] in ' \n':
+            data = data[1:]
+        elif data[0] == "'":
+            data = data[1:]
+            string = ''
+            while data[0] != "'":
+                string += data[0]
+                data = data[1:]
+            data = data[1:]
+            yield string
+
+def parse(tokens):
+    if tokens[0] == '{':
+        ret = OrderedDict()
+        tokens = tokens[1:]
+        while tokens[0] != '}':
+            key = tokens[0]
+            tokens = tokens[1:]
+
+            tokens = tokens[1:] # :
+
+            value, tokens = parse(tokens)
+
+            if tokens[0] == ',':
+                tokens = tokens[1:]
+
+            ret[key] = value
+        tokens = tokens[1:]
+        return ret, tokens
+    elif tokens[0] == '[':
+        ret = []
+        tokens = tokens[1:]
+        while tokens[0] != ']':
+            value, tokens = parse(tokens)
+            if tokens[0] == ',':
+                tokens = tokens[1:]
+            ret.append(value)
+        tokens = tokens[1:]
+        return ret, tokens
+    else:
+        return tokens[0], tokens[1:]
+
+def evaluate(string):
+    return parse(map(lambda x: x, tokenize(string)))[0]
+
+def parse_schema(fp):
+    exprs = []
+    expr = ''
+    expr_eval = None
+
+    for line in fp:
+        if line.startswith('#') or line == '\n':
+            continue
+
+        if line.startswith(' '):
+            expr += line
+        elif expr:
+            expr_eval = evaluate(expr)
+            if expr_eval.has_key('enum'):
+                add_enum(expr_eval['enum'])
+            elif expr_eval.has_key('union'):
+                add_enum('%sKind' % expr_eval['union'])
+            exprs.append(expr_eval)
+            expr = line
+        else:
+            expr += line
+
+    if expr:
+        expr_eval = evaluate(expr)
+        if expr_eval.has_key('enum'):
+            add_enum(expr_eval['enum'])
+        elif expr_eval.has_key('union'):
+            add_enum('%sKind' % expr_eval['union'])
+        exprs.append(expr_eval)
+
+    return exprs
+
+def parse_args(typeinfo):
+    for member in typeinfo:
+        argname = member
+        argentry = typeinfo[member]
+        optional = False
+        structured = False
+        if member.startswith('*'):
+            argname = member[1:]
+            optional = True
+        if isinstance(argentry, OrderedDict):
+            structured = True
+        yield (argname, argentry, optional, structured)
+
+def de_camel_case(name):
+    new_name = ''
+    for ch in name:
+        if ch.isupper() and new_name:
+            new_name += '_'
+        if ch == '-':
+            new_name += '_'
+        else:
+            new_name += ch.lower()
+    return new_name
+
+def camel_case(name):
+    new_name = ''
+    first = True
+    for ch in name:
+        if ch in ['_', '-']:
+            first = True
+        elif first:
+            new_name += ch.upper()
+            first = False
+        else:
+            new_name += ch.lower()
+    return new_name
+
+def c_var(name):
+    return '_'.join(name.split('-')).lstrip("*")
+
+def c_list_type(name):
+    return '%sList' % name
+
+def type_name(name):
+    if type(name) == list:
+        return c_list_type(name[0])
+    return name
+
+enum_types = []
+
+def add_enum(name):
+    global enum_types
+    enum_types.append(name)
+
+def is_enum(name):
+    global enum_types
+    return (name in enum_types)
+
+def c_type(name):
+    if name == 'str':
+        return 'char *'
+    elif name == 'int':
+        return 'int64_t'
+    elif name == 'bool':
+        return 'bool'
+    elif name == 'number':
+        return 'double'
+    elif type(name) == list:
+        return '%s *' % c_list_type(name[0])
+    elif is_enum(name):
+        return name
+    elif name == None or len(name) == 0:
+        return 'void'
+    elif name == name.upper():
+        return '%sEvent *' % camel_case(name)
+    else:
+        return '%s *' % name
+
+def genindent(count):
+    ret = ""
+    for i in range(count):
+        ret += " "
+    return ret
+
+indent_level = 0
+
+def push_indent(indent_amount=4):
+    global indent_level
+    indent_level += indent_amount
+
+def pop_indent(indent_amount=4):
+    global indent_level
+    indent_level -= indent_amount
+
+def cgen(code, **kwds):
+    indent = genindent(indent_level)
+    lines = code.split('\n')
+    lines = map(lambda x: indent + x, lines)
+    return '\n'.join(lines) % kwds + '\n'
+
+def mcgen(code, **kwds):
+    return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
+
+def basename(filename):
+    return filename.split("/")[-1]
+
+def guardname(filename):
+    return filename.replace("/", "_").replace("-", "_").split(".")[0].upper()
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 12/18] qapi: add qapi-types.py code generator
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (10 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 11/18] qapi: add qapi.py helper libraries Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 13/18] qapi: add qapi-visit.py " Michael Roth
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

This is the code generator for qapi types. It will generation the
following files:

  $(prefix)qapi-types.h - C types corresponding to types defined in
                          the schema you pass in
  $(prefix)qapi-types.c - Cleanup functions for the above C types

The $(prefix) is used to as a namespace to keep the generated code from
one schema/code-generation separated from others so code and be
generated from multiple schemas with clobbering previously created code.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi-types.py |  258 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 258 insertions(+), 0 deletions(-)
 create mode 100644 scripts/qapi-types.py

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
new file mode 100644
index 0000000..be0fecf
--- /dev/null
+++ b/scripts/qapi-types.py
@@ -0,0 +1,258 @@
+#
+# QAPI types generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_fwd_struct(name, members):
+    return mcgen('''
+typedef struct %(name)s %(name)s;
+
+typedef struct %(name)sList
+{
+    %(name)s *value;
+    struct %(name)sList *next;
+} %(name)sList;
+''',
+                 name=name)
+
+def generate_struct(structname, fieldname, members):
+    ret = mcgen('''
+struct %(name)s
+{
+''',
+          name=structname)
+
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+    bool has_%(c_name)s;
+''',
+                         c_name=c_var(argname))
+        if structured:
+            push_indent()
+            ret += generate_struct("", argname, argentry)
+            pop_indent()
+        else:
+            ret += mcgen('''
+    %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(argentry), c_name=c_var(argname))
+
+    if len(fieldname):
+        fieldname = " " + fieldname
+    ret += mcgen('''
+}%(field)s;
+''',
+            field=fieldname)
+
+    return ret
+
+def generate_handle(name, typeinfo):
+    return mcgen('''
+typedef struct %(name)s
+{
+    %(c_type)s handle;
+} %(name)s;
+
+typedef struct %(name)sList
+{
+    %(name)s *value;
+    struct %(name)sList *next;
+} %(name)sList;
+''',
+                 name=name, c_type=c_type(typeinfo))
+
+def generate_enum(name, values):
+    ret = mcgen('''
+typedef enum %(name)s
+{
+''',
+                name=name)
+
+    i = 1
+    for value in values:
+        ret += mcgen('''
+    %(abbrev)s_%(value)s = %(i)d,
+''',
+                     abbrev=de_camel_case(name).upper(),
+                     value=c_var(value).upper(),
+                     i=i)
+        i += 1
+
+    ret += mcgen('''
+} %(name)s;
+''',
+                 name=name)
+
+    return ret
+
+def generate_union(name, typeinfo):
+    ret = mcgen('''
+struct %(name)s
+{
+    %(name)sKind kind;
+    union {
+''',
+                name=name)
+
+    for key in typeinfo:
+        ret += mcgen('''
+        %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(typeinfo[key]),
+                     c_name=c_var(key))
+
+    ret += mcgen('''
+    };
+};
+''')
+
+    return ret
+
+def generate_type_cleanup_decl(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj);
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+def generate_type_cleanup(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj)
+{
+    QapiDeallocVisitor *md;
+    Visitor *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visitor_new();
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-types.c'
+h_file = 'qapi-types.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+    os.makedirs(output_dir)
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * deallocation functions for schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Michael Roth      <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',             prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-types-core.h"
+''',
+                  guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_fwd_struct(expr['type'], expr['data'])
+    elif expr.has_key('enum'):
+        ret += generate_enum(expr['enum'], expr['data'])
+    elif expr.has_key('union'):
+        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+    else:
+        continue
+    fdecl.write(ret)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+        ret += generate_type_cleanup_decl(expr['type'])
+        fdef.write(generate_type_cleanup(expr['type']) + "\n")
+    elif expr.has_key('handle'):
+        ret += generate_handle(expr['handle'], expr['data'])
+    elif expr.has_key('union'):
+        ret += generate_union(expr['union'], expr['data'])
+    else:
+        continue
+    fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 13/18] qapi: add qapi-visit.py code generator
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (11 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 12/18] qapi: add qapi-types.py code generator Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 14/18] qapi: add qapi-commands.py " Michael Roth
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

This is the code generator for qapi visiter functions used to
marshal/unmarshal/dealloc qapi types. It generates the following 2
files:

  $(prefix)qapi-visit.c: visiter function for a particular c type, used
                         to automagically convert qobjects into the
                         corresponding C type and vice-versa, and well
                         as for deallocation memory for an existing C
                         type

  $(prefix)qapi-visit.h: declarations for previously mentioned visiter
                         functions

$(prefix) is used as decribed for qapi-types.py

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi-visit.py |  261 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 261 insertions(+), 0 deletions(-)
 create mode 100644 scripts/qapi-visit.py

diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
new file mode 100644
index 0000000..a1a2d33
--- /dev/null
+++ b/scripts/qapi-visit.py
@@ -0,0 +1,261 @@
+#
+# QAPI visitor generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_visit_struct_body(field_prefix, members):
+    ret = ""
+    if len(field_prefix):
+        field_prefix = field_prefix + "."
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(m, (obj && *obj) ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp);
+if ((*obj)->%(prefix)shas_%(c_name)s) {
+''',
+                         c_prefix=c_var(field_prefix), prefix=field_prefix,
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+
+        if structured:
+            ret += mcgen('''
+visit_start_struct(m, NULL, "", "%(name)s", 0, errp);
+''',
+                         name=argname)
+            ret += generate_visit_struct_body(field_prefix + argname, argentry)
+            ret += mcgen('''
+visit_end_struct(m, errp);
+''')
+        else:
+            ret += mcgen('''
+visit_type_%(type)s(m, (obj && *obj) ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp);
+''',
+                         c_prefix=c_var(field_prefix), prefix=field_prefix,
+                         type=type_name(argentry), c_name=c_var(argname),
+                         name=argname)
+
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(m, errp);
+''')
+    return ret
+
+def generate_visit_struct(name, members):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
+''',
+                name=name)
+    push_indent()
+    ret += generate_visit_struct_body("", members)
+    pop_indent()
+
+    ret += mcgen('''
+    visit_end_struct(m, errp);
+}
+''')
+    return ret
+
+def generate_visit_list(name, members):
+    return mcgen('''
+
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
+{
+    GenericList *i;
+
+    visit_start_list(m, name, errp);
+
+    for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+        %(name)sList *native_i = (%(name)sList *)i;
+        visit_type_%(name)s(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+''',
+                name=name)
+
+def generate_visit_handle(name, typeinfo):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_handle(m, (void **)obj, "%(name)s", name, errp);
+    visit_type_%(type_name)s(m, &(*obj)->handle, "handle", errp);
+    visit_end_handle(m, errp);
+}
+''',
+                name=name, type_name=type_name(typeinfo))
+
+def generate_visit_enum(name, members):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
+{
+    visit_type_enum(m, (int *)obj, "%(name)s", name, errp);
+}
+''',
+                 name=name)
+
+def generate_visit_union(name, members):
+    ret = generate_visit_enum('%sKind' % name, members.keys())
+
+    ret += mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+}
+''',
+                 name=name)
+
+    return ret
+
+def generate_declaration(name, members, genlist=True):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+''',
+                 name=name)
+
+    return ret
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                name=name)
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-visit.c'
+h_file = 'qapi-visit.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+    os.makedirs(output_dir)
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor functions
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "%(header)s"
+''',
+                 header=basename(h_file)))
+
+fdecl.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor function
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-visit-core.h"
+#include "%(prefix)sqapi-types.h"
+''',
+                  prefix=prefix, guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    if expr.has_key('type'):
+        ret = generate_visit_struct(expr['type'], expr['data'])
+        ret += generate_visit_list(expr['type'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_declaration(expr['type'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('union'):
+        ret = generate_visit_union(expr['union'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
+        ret += generate_declaration(expr['union'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('enum'):
+        ret = generate_visit_enum(expr['enum'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_decl_enum(expr['enum'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('handle'):
+        ret = generate_visit_handle(expr['handle'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_declaration(expr['handle'], expr['data'], False)
+        fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
+
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 14/18] qapi: add qapi-commands.py code generator
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (12 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 13/18] qapi: add qapi-visit.py " Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 15/18] qapi: test schema used for unit tests Michael Roth
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

This is the code generator for qapi command marshaling/dispatch.
Currently only generators for synchronous qapi/qmp functions are
supported. This script generates the following files:

  $(prefix)qmp-marshal.c: command marshal/dispatch functions for each
                          QMP command defined in the schema. Functions
                          generated by qapi-visit.py are used to
                          convert qobjects recieved from the wire into
                          function parameters, and uses the same
                          visiter functions to convert native C return
                          values to qobjects from transmission back
                          over the wire.

  $(prefix)qmp-commands.h: Function prototypes for the QMP commands
                           specified in the schema.

$(prefix) is used in the same manner as with qapi-types.py

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi-commands.py |  381 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 381 insertions(+), 0 deletions(-)
 create mode 100644 scripts/qapi-commands.py

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
new file mode 100644
index 0000000..5c06bfa
--- /dev/null
+++ b/scripts/qapi-commands.py
@@ -0,0 +1,381 @@
+#
+# QAPI command marshaller generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                name=name)
+
+def generate_command_decl(name, args, ret_type):
+    arglist=""
+    for argname, argtype, optional, structured in parse_args(args):
+        argtype = c_type(argtype)
+        if argtype == "char *":
+            argtype = "const char *"
+        if optional:
+            arglist += "bool has_%s, " % c_var(argname)
+        arglist += "%s %s, " % (argtype, c_var(argname))
+    return mcgen('''
+%(ret_type)s qmp_%(name)s(%(args)sError **errp);
+''',
+                 ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
+
+def gen_sync_call(name, args, ret_type, indent=0):
+    ret = ""
+    arglist=""
+    retval=""
+    if ret_type:
+        retval = "retval = "
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            arglist += "has_%s, " % c_var(argname)
+        arglist += "%s, " % (c_var(argname))
+    push_indent(indent)
+    ret = mcgen('''
+%(retval)sqmp_%(name)s(%(args)serrp);
+
+''',
+                name=c_var(name), args=arglist, retval=retval).rstrip()
+    if ret_type:
+        ret += "\n" + mcgen(''''
+%(marshal_output_call)s
+''',
+                            marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
+    pop_indent(indent)
+    return ret.rstrip()
+
+
+def gen_marshal_output_call(name, ret_type):
+    if not ret_type:
+        return ""
+    return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
+
+def gen_visitor_output_containers_decl(ret_type):
+    ret = ""
+    push_indent()
+    if ret_type:
+        ret += mcgen('''
+QmpOutputVisitor *mo;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret
+
+def gen_visitor_input_containers_decl(args):
+    ret = ""
+
+    push_indent()
+    if len(args) > 0:
+        ret += mcgen('''
+QmpInputVisitor *mi;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret.rstrip()
+
+def gen_visitor_input_vars_decl(args):
+    ret = ""
+    push_indent()
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+bool has_%(argname)s = false;
+''',
+                         argname=c_var(argname))
+        if c_type(argtype).endswith("*"):
+            ret += mcgen('''
+%(argtype)s %(argname)s = NULL;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+        else:
+            ret += mcgen('''
+%(argtype)s %(argname)s;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+
+    pop_indent()
+    return ret.rstrip()
+
+def gen_visitor_input_block(args, obj, dealloc=False):
+    ret = ""
+    if len(args) == 0:
+        return ret
+
+    push_indent()
+
+    if dealloc:
+        ret += mcgen('''
+md = qapi_dealloc_visitor_new();
+v = qapi_dealloc_get_visitor(md);
+''')
+    else:
+        ret += mcgen('''
+mi = qmp_input_visitor_new(%(obj)s);
+v = qmp_input_get_visitor(mi);
+''',
+                     obj=obj)
+
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
+if (has_%(c_name)s) {
+''',
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+        ret += mcgen('''
+visit_type_%(argtype)s(v, &%(c_name)s, "%(name)s", errp);
+''',
+                      c_name=c_var(argname), name=argname, argtype=argtype)
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(v, errp);
+''')
+
+    if dealloc:
+        ret += mcgen('''
+qapi_dealloc_visitor_cleanup(md);
+''')
+    else:
+        ret += mcgen('''
+qmp_input_visitor_cleanup(mi);
+''')
+    pop_indent()
+    return ret.rstrip()
+
+def gen_marshal_output(name, args, ret_type):
+    if not ret_type:
+        return ""
+    ret = mcgen('''
+static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
+{
+    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+    QmpOutputVisitor *mo = qmp_output_visitor_new();
+    Visitor *v;
+
+    v = qmp_output_get_visitor(mo);
+    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    if (!error_is_set(errp)) {
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+    qmp_output_visitor_cleanup(mo);
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+            c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type)
+
+    return ret
+
+def gen_marshal_input(name, args, ret_type):
+    ret = mcgen('''
+static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp)
+{
+''',
+                c_name=c_var(name))
+
+    if ret_type:
+        if c_type(ret_type).endswith("*"):
+            retval = "    %s retval = NULL;" % c_type(ret_type)
+        else:
+            retval = "    %s retval;" % c_type(ret_type)
+        ret += mcgen('''
+%(retval)s
+''',
+                     retval=retval)
+
+    if len(args) > 0:
+        ret += mcgen('''
+%(visitor_input_containers_decl)s
+%(visitor_input_vars_decl)s
+
+%(visitor_input_block)s
+
+''',
+                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
+                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
+                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
+
+    ret += mcgen('''
+    if (error_is_set(errp)) {
+        goto out;
+    }
+%(sync_call)s
+''',
+                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
+    ret += mcgen('''
+
+out:
+''')
+    ret += mcgen('''
+%(visitor_input_block_cleanup)s
+    return;
+}
+''',
+                 visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True))
+    return ret
+
+def gen_registry(commands):
+    registry=""
+    push_indent()
+    for cmd in commands:
+        registry += mcgen('''
+qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
+''',
+                     name=cmd['command'], c_name=c_var(cmd['command']))
+    pop_indent()
+    ret = mcgen('''
+static void qmp_init_marshal(void)
+{
+%(registry)s
+}
+
+qapi_init(qmp_init_marshal);
+''',
+                registry=registry.rstrip())
+    return ret
+
+def gen_command_decl_prologue(header, guard, prefix=""):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI function prototypes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "%(prefix)sqapi-types.h"
+#include "error.h"
+
+''',
+                 header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+    return ret
+
+def gen_command_def_prologue(prefix="", proxy=False):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QMP->QAPI command dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',
+                prefix=prefix)
+    if not proxy:
+        ret += '#include "%sqmp-commands.h"' % prefix
+    return ret + "\n"
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+dispatch_type = "sync"
+c_file = 'qmp-marshal.c'
+h_file = 'qmp-commands.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+    elif o in ("-t", "--type"):
+        dispatch_type = a
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+    os.makedirs(output_dir)
+
+exprs = parse_schema(sys.stdin)
+commands = filter(lambda expr: expr.has_key('command'), exprs)
+
+if dispatch_type == "sync":
+    fdecl = open(h_file, 'w')
+    fdef = open(c_file, 'w')
+    ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+    fdecl.write(ret)
+    ret = gen_command_def_prologue(prefix=prefix)
+    fdef.write(ret)
+
+    for cmd in commands:
+        arglist = []
+        ret_type = None
+        if cmd.has_key('data'):
+            arglist = cmd['data']
+        if cmd.has_key('returns'):
+            ret_type = cmd['returns']
+        ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
+        fdecl.write(ret)
+        if ret_type:
+            ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n"
+            fdef.write(ret)
+        ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n"
+        fdef.write(ret)
+
+    fdecl.write("\n#endif");
+    ret = gen_registry(commands)
+    fdef.write(ret)
+
+    fdef.flush()
+    fdef.close()
+    fdecl.flush()
+    fdecl.close()
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 15/18] qapi: test schema used for unit tests
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (13 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 14/18] qapi: add qapi-commands.py " Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 16/18] qapi: add test-visitor, tests for gen. visitor code Michael Roth
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

This is how QMP commands/parameters/types would be defined. We use a
subset of that functionality here to implement functions/types for unit
testing.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi-schema-test.json |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
 create mode 100644 qapi-schema-test.json

diff --git a/qapi-schema-test.json b/qapi-schema-test.json
new file mode 100644
index 0000000..3acedad
--- /dev/null
+++ b/qapi-schema-test.json
@@ -0,0 +1,22 @@
+# *-*- Mode: Python -*-*
+
+# for testing enums
+{ 'enum': 'EnumOne',
+  'data': [ 'value1', 'value2', 'value3' ] }
+{ 'type': 'NestedEnumsOne',
+  'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
+
+# for testing nested structs
+{ 'type': 'UserDefOne',
+  'data': { 'integer': 'int', 'string': 'str' } }
+
+{ 'type': 'UserDefTwo',
+  'data': { 'string': 'str',
+            'dict': { 'string': 'str',
+                      'dict': { 'userdef': 'UserDefOne', 'string': 'str' },
+                      '*dict2': { 'userdef': 'UserDefOne', 'string': 'str' } } } }
+
+# testing commands
+{ 'command': 'user_def_cmd', 'data': {} }
+{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
+{ 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', 'ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' }
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 16/18] qapi: add test-visitor, tests for gen. visitor code
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (14 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 15/18] qapi: test schema used for unit tests Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 17/18] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile       |   18 +++-
 test-visitor.c |  305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 321 insertions(+), 2 deletions(-)
 create mode 100644 test-visitor.c

diff --git a/Makefile b/Makefile
index 42ae4e5..a243c24 100644
--- a/Makefile
+++ b/Makefile
@@ -162,6 +162,19 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
 check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
 check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
 
+qapi-dir := qapi-generated
+$(qapi-obj-y) test-visitor.o: QEMU_CFLAGS += -I $(qapi-dir)
+
+$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
+$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
+	$(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
+$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
+	$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+
+test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
+test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
 QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 
 clean:
@@ -170,11 +183,12 @@ clean:
 	rm -f qemu-options.def
 	rm -f *.o *.d *.a *.lo $(TOOLS) TAGS cscope.* *.pod *~ */*~
 	rm -Rf .libs
-	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
+	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d
 	rm -f qemu-img-cmds.h
 	rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
 	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
 	rm -f trace-dtrace.h trace-dtrace.h-timestamp
+	rm -rf $(qapi-dir)
 	$(MAKE) -C tests clean
 	for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
 	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
@@ -363,4 +377,4 @@ tarbin:
 	$(mandir)/man8/qemu-nbd.8
 
 # Include automatically generated dependency files
--include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
+-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d)
diff --git a/test-visitor.c b/test-visitor.c
new file mode 100644
index 0000000..5b2f138
--- /dev/null
+++ b/test-visitor.c
@@ -0,0 +1,305 @@
+#include <glib.h>
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestStruct
+{
+    int64_t x;
+    int64_t y;
+} TestStruct;
+
+typedef struct TestStructList
+{
+    TestStruct *value;
+    struct TestStructList *next;
+} TestStructList;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp)
+{
+    visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), errp);
+    visit_type_int(v, &(*obj)->x, "x", errp);
+    visit_type_int(v, &(*obj)->y, "y", errp);
+    visit_end_struct(v, errp);
+}
+
+static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp)
+{
+    GenericList *i;
+
+    visit_start_list(m, name, errp);
+
+    for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+        TestStructList *native_i = (TestStructList *)i;
+        visit_type_TestStruct(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+
+/* test core visitor methods */
+static void test_visitor_core(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    TestStruct ts = { 42, 82 };
+    TestStruct *pts = &ts;
+    TestStructList *lts = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+    int64_t value = 0;
+
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+
+    obj = qmp_output_get_qobject(mo);
+
+    str = qobject_to_json(obj);
+
+    printf("%s\n", qstring_get_str(str));
+
+    QDECREF(str);
+
+    obj = QOBJECT(qint_from_int(0x42));
+
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    visit_type_int(v, &value, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(value == 0x42);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("{'x': 42, 'y': 84}");
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    pts = NULL;
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(pts != NULL);
+    g_assert(pts->x == 42);
+    g_assert(pts->y == 84);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(lts != NULL);
+    g_assert(lts->value->x == 42);
+    g_assert(lts->value->y == 84);
+
+    lts = lts->next;
+    g_assert(lts != NULL);
+    g_assert(lts->value->x == 12);
+    g_assert(lts->value->y == 24);
+
+    g_assert(lts->next == NULL);
+
+    qobject_decref(obj);
+}
+
+/* test deep nesting with refs to other user-defined types */
+static void test_nested_structs(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    UserDefOne ud1;
+    UserDefOne *ud1_p = &ud1, *ud1c_p = NULL;
+    UserDefTwo ud2;
+    UserDefTwo *ud2_p = &ud2, *ud2c_p = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    ud1.integer = 42;
+    ud1.string = strdup("fourty two");
+
+    /* sanity check */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_UserDefOne(v, &ud1_p, "o_O", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    qobject_decref(obj);
+
+    ud2.string = strdup("fourty three");
+    ud2.dict.string = strdup("fourty four");
+    ud2.dict.dict.userdef = ud1_p;
+    ud2.dict.dict.string = strdup("fourty five");
+    ud2.dict.has_dict2 = true;
+    ud2.dict.dict2.userdef = ud1_p;
+    ud2.dict.dict2.string = strdup("fourty six");
+
+    /* c type -> qobject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_UserDefTwo(v, &ud2_p, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+
+    /* qobject -> c type, should match original struct */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_UserDefTwo(v, &ud2c_p, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+
+    g_assert(!g_strcmp0(ud2c_p->string, ud2.string));
+    g_assert(!g_strcmp0(ud2c_p->dict.string, ud2.dict.string));
+
+    ud1c_p = ud2c_p->dict.dict.userdef;
+    g_assert(ud1c_p->integer == ud1_p->integer);
+    g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+    g_assert(!g_strcmp0(ud2c_p->dict.dict.string, ud2.dict.dict.string));
+
+    ud1c_p = ud2c_p->dict.dict2.userdef;
+    g_assert(ud1c_p->integer == ud1_p->integer);
+    g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
+
+    g_assert(!g_strcmp0(ud2c_p->dict.dict2.string, ud2.dict.dict2.string));
+    qemu_free(ud1.string);
+    qemu_free(ud2.string);
+    qemu_free(ud2.dict.string);
+    qemu_free(ud2.dict.dict.string);
+    qemu_free(ud2.dict.dict2.string);
+
+    qapi_free_UserDefTwo(ud2c_p);
+
+    qobject_decref(obj);
+}
+
+/* test enum values */
+static void test_enums(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    EnumOne enum1 = ENUM_ONE_VALUE1, enum1_cpy = ENUM_ONE_VALUE2;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    /* C type -> QObject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_EnumOne(v, &enum1, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+    g_assert(qint_get_int(qobject_to_qint(obj)) == ENUM_ONE_VALUE1);
+
+    /* QObject -> C type */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_EnumOne(v, &enum1_cpy, "unused", &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    g_assert(enum1_cpy == enum1);
+
+    qobject_decref(obj);
+}
+
+/* test enum values nested in schema-defined structs */
+static void test_nested_enums(void)
+{
+    QmpOutputVisitor *mo;
+    QmpInputVisitor *mi;
+    Visitor *v;
+    NestedEnumsOne *nested_enums, *nested_enums_cpy = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    nested_enums = qemu_mallocz(sizeof(NestedEnumsOne));
+    nested_enums->enum1 = ENUM_ONE_VALUE1;
+    nested_enums->enum2 = ENUM_ONE_VALUE2;
+    nested_enums->enum3 = ENUM_ONE_VALUE3;
+    nested_enums->enum4 = ENUM_ONE_VALUE3;
+    nested_enums->has_enum2 = false;
+    nested_enums->has_enum4 = true;
+
+    /* C type -> QObject */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_NestedEnumsOne(v, &nested_enums, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_assert(obj);
+    str = qobject_to_json_pretty(obj);
+    g_print("%s\n", qstring_get_str(str));
+    QDECREF(str);
+
+    /* QObject -> C type */
+    mi = qmp_input_visitor_new(obj);
+    v = qmp_input_get_visitor(mi);
+    visit_type_NestedEnumsOne(v, &nested_enums_cpy, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    g_assert(nested_enums_cpy);
+    g_assert(nested_enums_cpy->enum1 == nested_enums->enum1);
+    g_assert(nested_enums_cpy->enum3 == nested_enums->enum3);
+    g_assert(nested_enums_cpy->enum4 == nested_enums->enum4);
+    g_assert(nested_enums_cpy->has_enum2 == false);
+    g_assert(nested_enums_cpy->has_enum4 == true);
+
+    qobject_decref(obj);
+    qapi_free_NestedEnumsOne(nested_enums);
+    qapi_free_NestedEnumsOne(nested_enums_cpy);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/0.15/visitor_core", test_visitor_core);
+    g_test_add_func("/0.15/nested_structs", test_nested_structs);
+    g_test_add_func("/0.15/enums", test_enums);
+    g_test_add_func("/0.15/nested_enums", test_nested_enums);
+
+    g_test_run();
+
+    return 0;
+}
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 17/18] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (15 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 16/18] qapi: add test-visitor, tests for gen. visitor code Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 18/18] qapi: add QAPI code generation documentation Michael Roth
  2011-07-07 14:37 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Luiz Capitulino
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile            |    8 +++-
 test-qmp-commands.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 1 deletions(-)
 create mode 100644 test-qmp-commands.c

diff --git a/Makefile b/Makefile
index a243c24..cbd2d77 100644
--- a/Makefile
+++ b/Makefile
@@ -163,7 +163,7 @@ check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
 check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
 
 qapi-dir := qapi-generated
-$(qapi-obj-y) test-visitor.o: QEMU_CFLAGS += -I $(qapi-dir)
+$(qapi-obj-y) test-visitor.o test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
 
 $(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
 $(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
@@ -171,10 +171,16 @@ $(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scr
 $(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
 $(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
 	$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
+$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
+	    $(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
 
 test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
 test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
 
+test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h)
+test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+
 QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 
 clean:
diff --git a/test-qmp-commands.c b/test-qmp-commands.c
new file mode 100644
index 0000000..7752904
--- /dev/null
+++ b/test-qmp-commands.c
@@ -0,0 +1,113 @@
+#include <glib.h>
+#include "qemu-objects.h"
+#include "test-qmp-commands.h"
+#include "qapi/qmp-core.h"
+#include "module.h"
+
+void qmp_user_def_cmd(Error **errp)
+{
+}
+
+void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
+{
+}
+
+UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
+{
+    UserDefTwo *ret;
+    UserDefOne *ud1c = qemu_mallocz(sizeof(UserDefOne));
+    UserDefOne *ud1d = qemu_mallocz(sizeof(UserDefOne));
+
+    ud1c->string = strdup(ud1a->string);
+    ud1c->integer = ud1a->integer;
+    ud1d->string = strdup(ud1b->string);
+    ud1d->integer = ud1b->integer;
+
+    ret = qemu_mallocz(sizeof(UserDefTwo));
+    ret->string = strdup("blah1");
+    ret->dict.string = strdup("blah2");
+    ret->dict.dict.userdef = ud1c;
+    ret->dict.dict.string = strdup("blah3");
+    ret->dict.has_dict2 = true;
+    ret->dict.dict2.userdef = ud1d;
+    ret->dict.dict2.string = strdup("blah4");
+
+    return ret;
+}
+
+/* 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));
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_error(void)
+{
+    QDict *req = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+/* test commands that involve both input parameters and return values */
+static void test_dispatch_cmd_io(void)
+{
+    QDict *req = qdict_new();
+    QDict *args = qdict_new();
+    QDict *ud1a = qdict_new();
+    QDict *ud1b = qdict_new();
+    QObject *resp;
+
+    qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
+    qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
+    qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
+    qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
+    qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
+    qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
+    qdict_put_obj(req, "arguments", QOBJECT(args));
+
+    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+
+    /* TODO: put in full payload and check for errors */
+    resp = qmp_dispatch(QOBJECT(req));
+    assert(resp != NULL);
+    assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
+    g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
+
+    qobject_decref(resp);
+    QDECREF(req);
+}
+
+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_error", test_dispatch_cmd_error);
+    g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
+
+    module_call_init(MODULE_INIT_QAPI);
+    g_test_run();
+
+    return 0;
+}
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v5 18/18] qapi: add QAPI code generation documentation
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (16 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 17/18] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
@ 2011-07-05 13:02 ` Michael Roth
  2011-07-07 14:37 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Luiz Capitulino
  18 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-05 13:02 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 docs/qapi-code-gen.txt |  316 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 316 insertions(+), 0 deletions(-)
 create mode 100644 docs/qapi-code-gen.txt

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
new file mode 100644
index 0000000..b7befb5
--- /dev/null
+++ b/docs/qapi-code-gen.txt
@@ -0,0 +1,316 @@
+= How to use the QAPI code generator =
+
+* Note: as of this writing, QMP does not use QAPI. Eventually QMP
+commands will be converted to use QAPI internally. The following
+information describes QMP/QAPI as it will exist after the
+conversion.
+
+QAPI is a native C API within QEMU which provides management-level
+functionality to internal/external users. For external
+users/processes, this interface is made available by a JSON-based
+QEMU Monitor protocol that is provided by the QMP server.
+
+To map QMP-defined interfaces to the native C QAPI implementations,
+a JSON-based schema is used to define types and function
+signatures, and a set of scripts is used to generate types/signatures,
+and marshaling/dispatch code. The QEMU Guest Agent also uses these
+scripts, paired with a seperate schema, to generate
+marshaling/dispatch code for the guest agent server running in the
+guest.
+
+This document will describe how the schemas, scripts, and resulting
+code is used.
+
+
+== QMP/Guest agent schema ==
+
+This file defines the types, commands, and events used by QMP.  It should
+fully describe the interface used by QMP.
+
+This file is designed to be loosely based on JSON although it's technically
+executable Python.  While dictionaries are used, they are parsed as
+OrderedDicts so that ordering is preserved.
+
+There are two basic syntaxes used, type definitions and command definitions.
+
+The first syntax defines a type and is represented by a dictionary.  There are
+two kinds of types that are supported: complex user-defined types, and enums.
+
+A complex type is a dictionary containing a single key who's value is a
+dictionary.  This corresponds to a struct in C or an Object in JSON.  An
+example of a complex type is:
+
+ { 'type': 'MyType',
+   'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } }
+
+The use of '*' as a prefix to the name means the member is optional.  Optional
+members should always be added to the end of the dictionary to preserve
+backwards compatibility.
+
+An enumeration type is a dictionary containing a single key who's value is a
+list of strings.  An example enumeration is:
+
+ { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
+
+Generally speaking, complex types and enums should always use CamelCase for
+the type names.
+
+Commands are defined by using a list containing three members.  The first
+member is the command name, the second member is a dictionary containing
+arguments, and the third member is the return type.
+
+An example command is:
+
+ { 'command': 'my-command',
+   'data': { 'arg1': 'str', '*arg2': 'str' },
+   'returns': 'str' ]
+
+Command names should be all lower case with words separated by a hyphen.
+
+
+== Code generation ==
+
+Schemas are fed into 3 scripts to generate all the code/files that, paired
+with the core QAPI libraries, comprise everything required to take JSON
+commands read in by a QMP/guest agent server, unmarshal the arguments into
+the underlying C types, call into the corresponding C function, and map the
+response back to a QMP/guest agent response to be returned to the user.
+
+As an example, we'll use the following schema, which describes a single
+complex user-defined type (which will produce a C struct, along with a list
+node structure that can be used to chain together a list of such types in
+case we want to accept/return a list of this type with a command), and a
+command which takes that type as a parameter and returns the same type:
+
+    mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
+    { 'type': 'UserDefOne',
+      'data': { 'integer': 'int', 'string': 'str' } }
+
+    { 'command': 'my-command',
+      'data':    {'arg1': 'UserDefOne'},
+      'returns': 'UserDefOne' }
+    mdroth@illuin:~/w/qemu2.git$
+
+=== scripts/qapi-types.py ===
+
+Used to generate the C types defined by a schema. The following files are
+created:
+
+$(prefix)qapi-types.h - C types corresponding to types defined in
+                        the schema you pass in
+$(prefix)qapi-types.c - Cleanup functions for the above C types
+
+The $(prefix) is an optional parameter used as a namespace to keep the
+generated code from one schema/code-generation separated from others so code
+can be generated/used from multiple schemas without clobbering previously
+created code.
+
+Example:
+
+    mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
+      --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
+    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "qapi/qapi-dealloc-visitor.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    void qapi_free_UserDefOne(UserDefOne * obj)
+    {
+        QapiDeallocVisitor *md;
+        Visitor *v;
+
+        if (!obj) {
+            return;
+        }
+
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &obj, NULL, NULL);
+        qapi_dealloc_visitor_cleanup(md);
+    }
+
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
+    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+    #define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+
+    #include "qapi/qapi-types-core.h"
+
+    typedef struct UserDefOne UserDefOne;
+
+    typedef struct UserDefOneList
+    {
+        UserDefOne *value;
+        struct UserDefOneList *next;
+    } UserDefOneList;
+
+    struct UserDefOne
+    {
+        int64_t integer;
+        char * string;
+    };
+
+    void qapi_free_UserDefOne(UserDefOne * obj);
+
+    #endif
+
+
+=== scripts/qapi-visit.py ===
+
+Used to generate the visitor functions used to walk through and convert
+a QObject (as provided by QMP) to a native C data structure and
+vice-versa, as well as the visitor function used to dealloc a complex
+schema-defined C type.
+
+The following files are generated:
+
+$(prefix)qapi-visit.c: visitor function for a particular C type, used
+                       to automagically convert QObjects into the
+                       corresponding C type and vice-versa, as well
+                       as for deallocating memory for an existing C
+                       type
+
+$(prefix)qapi-visit.h: declarations for previously mentioned visitor
+                       functions
+
+Example:
+
+    mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
+        --output-dir="qapi-generated" --prefix="example-" < example-schema.json
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "example-qapi-visit.h"
+
+    void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
+    {
+        visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
+        visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
+        visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
+        visit_end_struct(m, errp);
+    }
+
+    void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
+    {
+        GenericList *i;
+
+        visit_start_list(m, name, errp);
+
+        for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+            UserDefOneList *native_i = (UserDefOneList *)i;
+            visit_type_UserDefOne(m, &native_i->value, NULL, errp);
+        }
+
+        visit_end_list(m, errp);
+    }
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+    #define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+
+    #include "qapi/qapi-visit-core.h"
+    #include "example-qapi-types.h"
+
+    void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
+    void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
+
+    #endif
+    mdroth@illuin:~/w/qemu2.git$
+
+
+=== scripts/qapi-commands.py ===
+
+Used to generate the marshaling/dispatch functions for the commands defined
+in the schema. The following files are generated:
+
+$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
+                        QMP command defined in the schema. Functions
+                        generated by qapi-visit.py are used to
+                        convert QObjects recieved from the wire into
+                        function parameters, and uses the same
+                        visitor functions to convert native C return
+                        values to QObjects from transmission back
+                        over the wire.
+
+$(prefix)qmp-commands.h: Function prototypes for the QMP commands
+                         specified in the schema.
+
+Example:
+
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #include "qemu-objects.h"
+    #include "qapi/qmp-core.h"
+    #include "qapi/qapi-visit-core.h"
+    #include "qapi/qmp-output-visitor.h"
+    #include "qapi/qmp-input-visitor.h"
+    #include "qapi/qapi-dealloc-visitor.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    #include "example-qmp-commands.h"
+    static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
+    {
+        QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+        QmpOutputVisitor *mo = qmp_output_visitor_new();
+        Visitor *v;
+
+        v = qmp_output_get_visitor(mo);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        qapi_dealloc_visitor_cleanup(md);
+
+
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+
+    static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
+    {
+        UserDefOne * retval = NULL;
+        QmpInputVisitor *mi;
+        QapiDeallocVisitor *md;
+        Visitor *v;
+        UserDefOne * arg1 = NULL;
+
+        mi = qmp_input_visitor_new(QOBJECT(args));
+        v = qmp_input_get_visitor(mi);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+
+        if (error_is_set(errp)) {
+            goto out;
+        }
+        retval = qmp_my_command(arg1, errp);
+        qmp_marshal_output_my_command(retval, ret, errp);
+
+    out:
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+        qapi_dealloc_visitor_cleanup(md);
+        return;
+    }
+
+    static void qmp_init_marshal(void)
+    {
+        qmp_register_command("my-command", qmp_marshal_input_my_command);
+    }
+
+    qapi_init(qmp_init_marshal);
+    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
+    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+    #ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+    #define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+
+    #include "example-qapi-types.h"
+    #include "error.h"
+
+    UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
+
+    #endif
+    mdroth@illuin:~/w/qemu2.git$
-- 
1.7.0.4

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

* Re: [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core Michael Roth
@ 2011-07-07 14:32   ` Luiz Capitulino
  2011-07-07 14:40     ` Michael Roth
  0 siblings, 1 reply; 30+ messages in thread
From: Luiz Capitulino @ 2011-07-07 14:32 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Tue,  5 Jul 2011 08:02:31 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> Base definitions/includes for Visiter interface used by generated
> visiter/marshalling code.
> 
> Includes a GenericList type. Our lists require an embedded element.
> Since these types are generated, if you want to use them in a different
> type of data structure, there's no easy way to add another embedded
> element. The solution is to have non-embedded lists and that what this is.
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  Makefile.objs          |    6 +++
>  configure              |    1 +
>  qapi/qapi-types-core.h |   21 +++++++++
>  qapi/qapi-visit-core.c |  114 ++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/qapi-visit-core.h |   68 ++++++++++++++++++++++++++++
>  5 files changed, 210 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qapi-types-core.h
>  create mode 100644 qapi/qapi-visit-core.c
>  create mode 100644 qapi/qapi-visit-core.h
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index 493c988..0077014 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -372,6 +372,12 @@ endif
>  
>  libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
>  
> +######################################################################
> +# qapi
> +
> +qapi-nested-y = qapi-visit-core.o
> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))

qapi-obj-y has to included in common-obj-y, no? I'd also move this up in this
file (where others "modulename-obj-y" are located).

> +
>  vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>  
>  vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
> diff --git a/configure b/configure
> index 63156a2..02c552e 100755
> --- a/configure
> +++ b/configure
> @@ -3486,6 +3486,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
>  DIRS="$DIRS pc-bios/spapr-rtas"
>  DIRS="$DIRS roms/seabios roms/vgabios"
>  DIRS="$DIRS fsdev ui"
> +DIRS="$DIRS qapi"
>  FILES="Makefile tests/Makefile"
>  FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
>  FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
> diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
> new file mode 100644
> index 0000000..de733ab
> --- /dev/null
> +++ b/qapi/qapi-types-core.h
> @@ -0,0 +1,21 @@
> +/*
> + * Core Definitions for QAPI-generated Types
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QAPI_TYPES_CORE_H
> +#define QAPI_TYPES_CORE_H
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include "error.h"
> +
> +#endif
> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
> new file mode 100644
> index 0000000..c8a7805
> --- /dev/null
> +++ b/qapi/qapi-visit-core.c
> @@ -0,0 +1,114 @@
> +/*
> + * Core Definitions for QAPI Visitor Classes
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "qapi/qapi-visit-core.h"
> +
> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp) && v->start_handle) {
> +        v->start_handle(v, obj, kind, name, errp);
> +    }
> +}
> +
> +void visit_end_handle(Visitor *v, Error **errp)
> +{
> +    if (!error_is_set(errp) && v->end_handle) {
> +        v->end_handle(v, errp);
> +    }
> +}
> +
> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->start_struct(v, obj, kind, name, size, errp);
> +    }
> +}
> +
> +void visit_end_struct(Visitor *v, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->end_struct(v, errp);
> +    }
> +}
> +
> +void visit_start_list(Visitor *v, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->start_list(v, name, errp);
> +    }
> +}
> +
> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        return v->next_list(v, list, errp);
> +    }
> +
> +    return 0;
> +}
> +
> +void visit_end_list(Visitor *v, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->end_list(v, errp);
> +    }
> +}
> +
> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp) && v->start_optional) {
> +        v->start_optional(v, present, name, errp);
> +    }
> +}
> +
> +void visit_end_optional(Visitor *v, Error **errp)
> +{
> +    if (!error_is_set(errp) && v->end_optional) {
> +        v->end_optional(v, errp);
> +    }
> +}
> +
> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->type_enum(v, obj, kind, name, errp);
> +    }
> +}
> +
> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->type_int(v, obj, name, errp);
> +    }
> +}
> +
> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->type_bool(v, obj, name, errp);
> +    }
> +}
> +
> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->type_str(v, obj, name, errp);
> +    }
> +}
> +
> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->type_number(v, obj, name, errp);
> +    }
> +}
> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
> new file mode 100644
> index 0000000..8350a6d
> --- /dev/null
> +++ b/qapi/qapi-visit-core.h
> @@ -0,0 +1,68 @@
> +/*
> + * Core Definitions for QAPI Visitor Classes
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +#ifndef QAPI_VISITOR_CORE_H
> +#define QAPI_VISITOR_CORE_H
> +
> +#include "qapi/qapi-types-core.h"
> +#include "error.h"
> +#include <stdlib.h>
> +
> +typedef struct GenericList
> +{
> +    void *value;
> +    struct GenericList *next;
> +} GenericList;
> +
> +typedef struct Visitor Visitor;
> +
> +struct Visitor
> +{
> +    /* Must be set */
> +    void (*start_struct)(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
> +    void (*end_struct)(Visitor *v, Error **errp);
> +
> +    void (*start_list)(Visitor *v, const char *name, Error **errp);
> +    GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
> +    void (*end_list)(Visitor *v, Error **errp);
> +
> +    void (*type_enum)(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
> +
> +    void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
> +    void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
> +    void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
> +    void (*type_number)(Visitor *v, double *obj, const char *name, Error **errp);
> +
> +    /* May be NULL */
> +    void (*start_optional)(Visitor *v, bool *present, const char *name, Error **errp);
> +    void (*end_optional)(Visitor *v, Error **errp);
> +
> +    void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
> +    void (*end_handle)(Visitor *v, Error **errp);
> +};
> +
> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
> +void visit_end_handle(Visitor *v, Error **errp);
> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
> +void visit_end_struct(Visitor *v, Error **errp);
> +void visit_start_list(Visitor *v, const char *name, Error **errp);
> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
> +void visit_end_list(Visitor *v, Error **errp);
> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp);
> +void visit_end_optional(Visitor *v, Error **errp);
> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
> +
> +#endif

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor Michael Roth
@ 2011-07-07 14:32   ` Luiz Capitulino
  2011-07-07 14:45     ` Michael Roth
  2011-07-12  0:05     ` Michael Roth
  0 siblings, 2 replies; 30+ messages in thread
From: Luiz Capitulino @ 2011-07-07 14:32 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Tue,  5 Jul 2011 08:02:32 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> A type of Visiter class that is used to walk a qobject's
> structure and assign each entry to the corresponding native C type.
> Command marshaling function will use this to pull out QMP command
> parameters recieved over the wire and pass them as native arguments
> to the corresponding C functions.
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  Makefile.objs            |    2 +-
>  qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/qmp-input-visitor.h |   27 +++++
>  qerror.h                 |    3 +
>  4 files changed, 295 insertions(+), 1 deletions(-)
>  create mode 100644 qapi/qmp-input-visitor.c
>  create mode 100644 qapi/qmp-input-visitor.h
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index 0077014..997ecef 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
>  ######################################################################
>  # qapi
>  
> -qapi-nested-y = qapi-visit-core.o
> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
>  qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>  
>  vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
> new file mode 100644
> index 0000000..80912bb
> --- /dev/null
> +++ b/qapi/qmp-input-visitor.c
> @@ -0,0 +1,264 @@
> +/*
> + * Input Visitor
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "qmp-input-visitor.h"
> +#include "qemu-queue.h"
> +#include "qemu-common.h"
> +#include "qemu-objects.h"
> +#include "qerror.h"
> +
> +#define QIV_STACK_SIZE 1024
> +
> +typedef struct StackObject
> +{
> +    const QObject *obj;
> +    const  QListEntry *entry;
> +} StackObject;
> +
> +struct QmpInputVisitor
> +{
> +    Visitor visitor;
> +    const QObject *obj;
> +    StackObject stack[QIV_STACK_SIZE];
> +    int nb_stack;
> +};
> +
> +static QmpInputVisitor *to_qiv(Visitor *v)
> +{
> +    return container_of(v, QmpInputVisitor, visitor);
> +}
> +
> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
> +{
> +    const QObject *qobj;
> +
> +    if (qiv->nb_stack == 0) {
> +        qobj = qiv->obj;
> +    } else {
> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
> +    }
> +
> +    if (name && qobject_type(qobj) == QTYPE_QDICT) {
> +        return qdict_get(qobject_to_qdict(qobj), name);
> +    } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
> +    }
> +
> +    return qobj;
> +}
> +
> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
> +{
> +    qiv->stack[qiv->nb_stack].obj = obj;
> +    if (qobject_type(obj) == QTYPE_QLIST) {
> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
> +    }
> +    qiv->nb_stack++;
> +
> +    if (qiv->nb_stack >= QIV_STACK_SIZE) {
> +        error_set(errp, QERR_BUFFER_OVERRUN);
> +        return;
> +    }
> +}
> +
> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
> +{
> +    qiv->nb_stack--;
> +    if (qiv->nb_stack < 0) {
> +        error_set(errp, QERR_BUFFER_OVERRUN);
> +        return;
> +    }
> +}
> +
> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
> +        return;
> +    }
> +
> +    qmp_input_push(qiv, qobj, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (obj) {
> +        *obj = qemu_mallocz(size);
> +    }
> +}
> +
> +static void qmp_input_end_struct(Visitor *v, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +
> +    qmp_input_pop(qiv, errp);
> +}
> +
> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
> +        return;
> +    }
> +
> +    qmp_input_push(qiv, qobj, errp);
> +}
> +
> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    GenericList *entry;
> +    StackObject *so = &qiv->stack[qiv->nb_stack - 1];
> +
> +    if (so->entry == NULL) {
> +        return NULL;
> +    }
> +
> +    entry = qemu_mallocz(sizeof(*entry));
> +    if (*list) {
> +        so->entry = qlist_next(so->entry);
> +        if (so->entry == NULL) {
> +            qemu_free(entry);
> +            return NULL;
> +        }
> +        (*list)->next = entry;
> +    }
> +    *list = entry;
> +
> +
> +    return entry;
> +}
> +
> +static void qmp_input_end_list(Visitor *v, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +
> +    qmp_input_pop(qiv, errp);
> +}
> +
> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
> +        return;
> +    }
> +
> +    *obj = qint_get_int(qobject_to_qint(qobj));
> +}
> +
> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
> +        return;
> +    }
> +
> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
> +}
> +
> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
> +        return;
> +    }
> +
> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
> +}
> +
> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
> +        return;
> +    }
> +
> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
> +}
> +
> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +    int64_t value;
> +    qmp_input_type_int(v, &value, name, errp);
> +    *obj = value;
> +}
> +
> +static void qmp_input_start_optional(Visitor *v, bool *present,
> +                                     const char *name, Error **errp)
> +{
> +    QmpInputVisitor *qiv = to_qiv(v);
> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj) {
> +        *present = false;
> +        return;
> +    }
> +
> +    *present = true;
> +}
> +
> +static void qmp_input_end_optional(Visitor *v, Error **errp)
> +{
> +}
> +
> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
> +{
> +    return &v->visitor;
> +}
> +
> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
> +{

We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
decrefing here.

> +    qemu_free(v);
> +}
> +
> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
> +{
> +    QmpInputVisitor *v;
> +
> +    v = qemu_mallocz(sizeof(*v));
> +
> +    v->visitor.start_struct = qmp_input_start_struct;
> +    v->visitor.end_struct = qmp_input_end_struct;
> +    v->visitor.start_list = qmp_input_start_list;
> +    v->visitor.next_list = qmp_input_next_list;
> +    v->visitor.end_list = qmp_input_end_list;
> +    v->visitor.type_enum = qmp_input_type_enum;
> +    v->visitor.type_int = qmp_input_type_int;
> +    v->visitor.type_bool = qmp_input_type_bool;
> +    v->visitor.type_str = qmp_input_type_str;
> +    v->visitor.type_number = qmp_input_type_number;
> +    v->visitor.start_optional = qmp_input_start_optional;
> +    v->visitor.end_optional = qmp_input_end_optional;
> +
> +    v->obj = obj;
> +
> +    return v;
> +}
> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
> new file mode 100644
> index 0000000..0f77916
> --- /dev/null
> +++ b/qapi/qmp-input-visitor.h
> @@ -0,0 +1,27 @@
> +/*
> + * Input Visitor
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QMP_INPUT_VISITOR_H
> +#define QMP_INPUT_VISITOR_H
> +
> +#include "qapi-visit-core.h"
> +#include "qobject.h"
> +
> +typedef struct QmpInputVisitor QmpInputVisitor;
> +
> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
> +
> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
> +
> +#endif
> diff --git a/qerror.h b/qerror.h
> index 16c830d..9a9fa5b 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
>  #define QERR_JSON_PARSE_ERROR \
>      "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>  
> +#define QERR_BUFFER_OVERRUN \
> +    "{ 'class': 'BufferOverrun', 'data': {} }"
> +

You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
but BufferOverrrun is probably fine.

>  #define QERR_KVM_MISSING_CAP \
>      "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>  

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

* Re: [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5
  2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
                   ` (17 preceding siblings ...)
  2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 18/18] qapi: add QAPI code generation documentation Michael Roth
@ 2011-07-07 14:37 ` Luiz Capitulino
  2011-07-07 15:02   ` Michael Roth
  18 siblings, 1 reply; 30+ messages in thread
From: Luiz Capitulino @ 2011-07-07 14:37 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Tue,  5 Jul 2011 08:02:27 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> This is Set 2/3 of the QAPI+QGA patchsets.
> 
> These patches apply on top of master (set1 merged), and can also be obtained
> from:
> git://repo.or.cz/qemu/mdroth.git qapi-backport-set2-v5

This doesn't build due to a bug in error.h. If you didn't get it you're
probably testing against a not up to date branch...

I have the fix for error.h and will submit it.

Only a few small issues remain, I think the next version will be good to go,
although I'd only merge it along with the guest agent patches.

> 
> (Set1+2 are a backport of some of the QAPI-related work from Anthony's
> glib tree. The main goal is to get the basic code generation infrastructure in
> place so that it can be used by the guest agent to implement a QMP-like guest
> interface, and so that future work regarding the QMP conversion to QAPI can be
> decoupled from the infrastructure bits. Set3 is the Qemu Guest Agent
> (virtagent), rebased on the new code QAPI code generation infrastructure. This
> is the first user of QAPI, QMP will follow.)
> ___
> 
> This patchset introduces the following:
> 
>  - Hard dependency on GLib. This has been floating around the list for a while.
>    Currently the only users are the unit tests for this patchset and the guest
>    agent. We can make both of these a configure option, but based on previous
>    discussions a hard dependency will likely be introduced with subsequent
>    QAPI patches.
> 
>  - A couple additional qlist utility functions used by QAPI.
> 
>  - QAPI schema-based code generation for synchronous QMP/QGA commands
>    and types, and Visitor/dispatch infrastructure to handle
>    marshaling/unmarshaling/dispatch between QAPI and the QMP/QGA wire protocols.
> 
>  - Documentation and unit tests for visitor functions and synchronous
>    command/type generation.
> 
> CHANGES SINCE V4:
>  - Fix segfault in output visitor when dealing with QAPI-defined C structs
>    with NULL pointers
> 
> CHANGES SINCE V3:
>  - Added copyright headers for generated code and remaining files
>  - Added checking for required/extra parameters in top-level of QMP QObject
>  - Made QDict arg to input visitor constructor a const
>  - Renamed qmp_dispatch_err() -> do_qmp_dispatch()
>  - Changed QERR_QAPI_STACK_OVERRUN to QERR_BUFFER_OVERRUN
>  - Moved configure changes to create QAPI directory when using a different build
>    root to first patch which uses it.
>  - Squashed Makefile changes for test-visitor/test-qmp-commands into single
>    commits
>  - Removed redundant NULL checks for qemu_free() in dealloc visitor
> 
> CHANGES SINCE V2:
>  - Added cleanup functions for input/output visitor types and fixed a leak in
>    dispatch path.
>  - Corrected spelling from visiter->visitor and updated filenames accordingly.
>  - Re-organized patches so that each new C file can be built as part of the
>    introducting commit (for instances where there were no users of the
>    qapi-obj-y target yet a test build was done by adding the target as a
>    superficial dependency on other tools), and moved code generator patches
>    after the required dependencies.
>  - Made qlist_first/qlist_next accept/return const types.
>  - Moved Visitor interface inline wrapper functions to real ones.
>  - Fixed error-reporting for invalid parameters when parameter name is null.
>  - Removed hard-coded size for QAPI-type allocations done by the input visitor,
>    using generated code to pass in a sizeof() now.
>  - Replaced assert()'s on visitor stack overruns, replaced with an error
>    indication.
>  - Fixed build issue when using a separate build directory.
>  - Added missing copyright headers for scripts, moved external code in
>    ordereddict.py to a seperate patch.
>  - Many thanks to Luiz, Anthony, and everyone else for the excellent
>    review/testing.
> 
> CHANGES SINCE V1:
>  - Fixed build issue that was missed due to deprecated files being present in
>    source tree. Thanks to Matsuda Daiki for sending fixes.
>  - Fixed grammatical errors in documentation pointed out by Luiz.
>  - Added generated code to the make clean target.
> 
> CHANGES SINCE V0 ("QAPI Infrastructure Round 1"):
>  - Fixed known memory leaks in generated code
>  - Stricter error-handling in generated code
>  - Removed currently unused code (generators for events and async/proxied
>    QMP/QGA commands and definition used by the not-yet-introduced QMP server
>    replacement)
>  - Added documentation for code generation scripts/schemas/usage
>  - Addressed review comments from Luiz and Stefan
> 
>  Makefile                    |   24 +++-
>  Makefile.objs               |    9 +
>  Makefile.target             |    1 +
>  configure                   |   14 ++
>  docs/qapi-code-gen.txt      |  316 +++++++++++++++++++++++++++++++++++
>  module.h                    |    2 +
>  qapi-schema-test.json       |   22 +++
>  qapi/qapi-dealloc-visitor.c |  138 ++++++++++++++++
>  qapi/qapi-dealloc-visitor.h |   26 +++
>  qapi/qapi-types-core.h      |   21 +++
>  qapi/qapi-visit-core.c      |  114 +++++++++++++
>  qapi/qapi-visit-core.h      |   68 ++++++++
>  qapi/qmp-core.h             |   41 +++++
>  qapi/qmp-dispatch.c         |  124 ++++++++++++++
>  qapi/qmp-input-visitor.c    |  264 ++++++++++++++++++++++++++++++
>  qapi/qmp-input-visitor.h    |   27 +++
>  qapi/qmp-output-visitor.c   |  216 ++++++++++++++++++++++++
>  qapi/qmp-output-visitor.h   |   28 +++
>  qapi/qmp-registry.c         |   40 +++++
>  qerror.h                    |    3 +
>  qlist.h                     |   11 ++
>  scripts/ordereddict.py      |  128 +++++++++++++++
>  scripts/qapi-commands.py    |  381 +++++++++++++++++++++++++++++++++++++++++++
>  scripts/qapi-types.py       |  258 +++++++++++++++++++++++++++++
>  scripts/qapi-visit.py       |  261 +++++++++++++++++++++++++++++
>  scripts/qapi.py             |  203 +++++++++++++++++++++++
>  test-qmp-commands.c         |  113 +++++++++++++
>  test-visitor.c              |  305 ++++++++++++++++++++++++++++++++++
>  28 files changed, 3157 insertions(+), 1 deletions(-)
> 

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

* Re: [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core
  2011-07-07 14:32   ` Luiz Capitulino
@ 2011-07-07 14:40     ` Michael Roth
  0 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-07 14:40 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
> On Tue,  5 Jul 2011 08:02:31 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> Base definitions/includes for Visiter interface used by generated
>> visiter/marshalling code.
>>
>> Includes a GenericList type. Our lists require an embedded element.
>> Since these types are generated, if you want to use them in a different
>> type of data structure, there's no easy way to add another embedded
>> element. The solution is to have non-embedded lists and that what this is.
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>> ---
>>   Makefile.objs          |    6 +++
>>   configure              |    1 +
>>   qapi/qapi-types-core.h |   21 +++++++++
>>   qapi/qapi-visit-core.c |  114 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   qapi/qapi-visit-core.h |   68 ++++++++++++++++++++++++++++
>>   5 files changed, 210 insertions(+), 0 deletions(-)
>>   create mode 100644 qapi/qapi-types-core.h
>>   create mode 100644 qapi/qapi-visit-core.c
>>   create mode 100644 qapi/qapi-visit-core.h
>>
>> diff --git a/Makefile.objs b/Makefile.objs
>> index 493c988..0077014 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -372,6 +372,12 @@ endif
>>
>>   libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
>>
>> +######################################################################
>> +# qapi
>> +
>> +qapi-nested-y = qapi-visit-core.o
>> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>
> qapi-obj-y has to included in common-obj-y, no? I'd also move this up in this
> file (where others "modulename-obj-y" are located).
>

Eventually, when we do the full QMP conversion. But for now, only the 
guest agent pulls these in. I'll move the block up.

>> +
>>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>
>>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>> diff --git a/configure b/configure
>> index 63156a2..02c552e 100755
>> --- a/configure
>> +++ b/configure
>> @@ -3486,6 +3486,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
>>   DIRS="$DIRS pc-bios/spapr-rtas"
>>   DIRS="$DIRS roms/seabios roms/vgabios"
>>   DIRS="$DIRS fsdev ui"
>> +DIRS="$DIRS qapi"
>>   FILES="Makefile tests/Makefile"
>>   FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
>>   FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
>> diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
>> new file mode 100644
>> index 0000000..de733ab
>> --- /dev/null
>> +++ b/qapi/qapi-types-core.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * Core Definitions for QAPI-generated Types
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#ifndef QAPI_TYPES_CORE_H
>> +#define QAPI_TYPES_CORE_H
>> +
>> +#include<stdbool.h>
>> +#include<stdint.h>
>> +#include "error.h"
>> +
>> +#endif
>> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
>> new file mode 100644
>> index 0000000..c8a7805
>> --- /dev/null
>> +++ b/qapi/qapi-visit-core.c
>> @@ -0,0 +1,114 @@
>> +/*
>> + * Core Definitions for QAPI Visitor Classes
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qapi/qapi-visit-core.h"
>> +
>> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)&&  v->start_handle) {
>> +        v->start_handle(v, obj, kind, name, errp);
>> +    }
>> +}
>> +
>> +void visit_end_handle(Visitor *v, Error **errp)
>> +{
>> +    if (!error_is_set(errp)&&  v->end_handle) {
>> +        v->end_handle(v, errp);
>> +    }
>> +}
>> +
>> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->start_struct(v, obj, kind, name, size, errp);
>> +    }
>> +}
>> +
>> +void visit_end_struct(Visitor *v, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->end_struct(v, errp);
>> +    }
>> +}
>> +
>> +void visit_start_list(Visitor *v, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->start_list(v, name, errp);
>> +    }
>> +}
>> +
>> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        return v->next_list(v, list, errp);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +void visit_end_list(Visitor *v, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->end_list(v, errp);
>> +    }
>> +}
>> +
>> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)&&  v->start_optional) {
>> +        v->start_optional(v, present, name, errp);
>> +    }
>> +}
>> +
>> +void visit_end_optional(Visitor *v, Error **errp)
>> +{
>> +    if (!error_is_set(errp)&&  v->end_optional) {
>> +        v->end_optional(v, errp);
>> +    }
>> +}
>> +
>> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->type_enum(v, obj, kind, name, errp);
>> +    }
>> +}
>> +
>> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->type_int(v, obj, name, errp);
>> +    }
>> +}
>> +
>> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->type_bool(v, obj, name, errp);
>> +    }
>> +}
>> +
>> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->type_str(v, obj, name, errp);
>> +    }
>> +}
>> +
>> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
>> +{
>> +    if (!error_is_set(errp)) {
>> +        v->type_number(v, obj, name, errp);
>> +    }
>> +}
>> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
>> new file mode 100644
>> index 0000000..8350a6d
>> --- /dev/null
>> +++ b/qapi/qapi-visit-core.h
>> @@ -0,0 +1,68 @@
>> +/*
>> + * Core Definitions for QAPI Visitor Classes
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +#ifndef QAPI_VISITOR_CORE_H
>> +#define QAPI_VISITOR_CORE_H
>> +
>> +#include "qapi/qapi-types-core.h"
>> +#include "error.h"
>> +#include<stdlib.h>
>> +
>> +typedef struct GenericList
>> +{
>> +    void *value;
>> +    struct GenericList *next;
>> +} GenericList;
>> +
>> +typedef struct Visitor Visitor;
>> +
>> +struct Visitor
>> +{
>> +    /* Must be set */
>> +    void (*start_struct)(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
>> +    void (*end_struct)(Visitor *v, Error **errp);
>> +
>> +    void (*start_list)(Visitor *v, const char *name, Error **errp);
>> +    GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
>> +    void (*end_list)(Visitor *v, Error **errp);
>> +
>> +    void (*type_enum)(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
>> +
>> +    void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp);
>> +    void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
>> +    void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
>> +    void (*type_number)(Visitor *v, double *obj, const char *name, Error **errp);
>> +
>> +    /* May be NULL */
>> +    void (*start_optional)(Visitor *v, bool *present, const char *name, Error **errp);
>> +    void (*end_optional)(Visitor *v, Error **errp);
>> +
>> +    void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
>> +    void (*end_handle)(Visitor *v, Error **errp);
>> +};
>> +
>> +void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp);
>> +void visit_end_handle(Visitor *v, Error **errp);
>> +void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp);
>> +void visit_end_struct(Visitor *v, Error **errp);
>> +void visit_start_list(Visitor *v, const char *name, Error **errp);
>> +GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
>> +void visit_end_list(Visitor *v, Error **errp);
>> +void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp);
>> +void visit_end_optional(Visitor *v, Error **errp);
>> +void visit_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp);
>> +void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp);
>> +void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
>> +void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
>> +void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
>> +
>> +#endif
>

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-07 14:32   ` Luiz Capitulino
@ 2011-07-07 14:45     ` Michael Roth
  2011-07-12  0:05     ` Michael Roth
  1 sibling, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-07 14:45 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
> On Tue,  5 Jul 2011 08:02:32 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> A type of Visiter class that is used to walk a qobject's
>> structure and assign each entry to the corresponding native C type.
>> Command marshaling function will use this to pull out QMP command
>> parameters recieved over the wire and pass them as native arguments
>> to the corresponding C functions.
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>> ---
>>   Makefile.objs            |    2 +-
>>   qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
>>   qapi/qmp-input-visitor.h |   27 +++++
>>   qerror.h                 |    3 +
>>   4 files changed, 295 insertions(+), 1 deletions(-)
>>   create mode 100644 qapi/qmp-input-visitor.c
>>   create mode 100644 qapi/qmp-input-visitor.h
>>
>> diff --git a/Makefile.objs b/Makefile.objs
>> index 0077014..997ecef 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
>>   ######################################################################
>>   # qapi
>>
>> -qapi-nested-y = qapi-visit-core.o
>> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
>>   qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>>
>>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
>> new file mode 100644
>> index 0000000..80912bb
>> --- /dev/null
>> +++ b/qapi/qmp-input-visitor.c
>> @@ -0,0 +1,264 @@
>> +/*
>> + * Input Visitor
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qmp-input-visitor.h"
>> +#include "qemu-queue.h"
>> +#include "qemu-common.h"
>> +#include "qemu-objects.h"
>> +#include "qerror.h"
>> +
>> +#define QIV_STACK_SIZE 1024
>> +
>> +typedef struct StackObject
>> +{
>> +    const QObject *obj;
>> +    const  QListEntry *entry;
>> +} StackObject;
>> +
>> +struct QmpInputVisitor
>> +{
>> +    Visitor visitor;
>> +    const QObject *obj;
>> +    StackObject stack[QIV_STACK_SIZE];
>> +    int nb_stack;
>> +};
>> +
>> +static QmpInputVisitor *to_qiv(Visitor *v)
>> +{
>> +    return container_of(v, QmpInputVisitor, visitor);
>> +}
>> +
>> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
>> +{
>> +    const QObject *qobj;
>> +
>> +    if (qiv->nb_stack == 0) {
>> +        qobj = qiv->obj;
>> +    } else {
>> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
>> +    }
>> +
>> +    if (name&&  qobject_type(qobj) == QTYPE_QDICT) {
>> +        return qdict_get(qobject_to_qdict(qobj), name);
>> +    } else if (qiv->nb_stack>  0&&  qobject_type(qobj) == QTYPE_QLIST) {
>> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
>> +    }
>> +
>> +    return qobj;
>> +}
>> +
>> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
>> +{
>> +    qiv->stack[qiv->nb_stack].obj = obj;
>> +    if (qobject_type(obj) == QTYPE_QLIST) {
>> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
>> +    }
>> +    qiv->nb_stack++;
>> +
>> +    if (qiv->nb_stack>= QIV_STACK_SIZE) {
>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>> +        return;
>> +    }
>> +}
>> +
>> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
>> +{
>> +    qiv->nb_stack--;
>> +    if (qiv->nb_stack<  0) {
>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>> +        return;
>> +    }
>> +}
>> +
>> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
>> +        return;
>> +    }
>> +
>> +    qmp_input_push(qiv, qobj, errp);
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    if (obj) {
>> +        *obj = qemu_mallocz(size);
>> +    }
>> +}
>> +
>> +static void qmp_input_end_struct(Visitor *v, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +
>> +    qmp_input_pop(qiv, errp);
>> +}
>> +
>> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
>> +        return;
>> +    }
>> +
>> +    qmp_input_push(qiv, qobj, errp);
>> +}
>> +
>> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    GenericList *entry;
>> +    StackObject *so =&qiv->stack[qiv->nb_stack - 1];
>> +
>> +    if (so->entry == NULL) {
>> +        return NULL;
>> +    }
>> +
>> +    entry = qemu_mallocz(sizeof(*entry));
>> +    if (*list) {
>> +        so->entry = qlist_next(so->entry);
>> +        if (so->entry == NULL) {
>> +            qemu_free(entry);
>> +            return NULL;
>> +        }
>> +        (*list)->next = entry;
>> +    }
>> +    *list = entry;
>> +
>> +
>> +    return entry;
>> +}
>> +
>> +static void qmp_input_end_list(Visitor *v, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +
>> +    qmp_input_pop(qiv, errp);
>> +}
>> +
>> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
>> +        return;
>> +    }
>> +
>> +    *obj = qint_get_int(qobject_to_qint(qobj));
>> +}
>> +
>> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
>> +        return;
>> +    }
>> +
>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
>> +}
>> +
>> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
>> +        return;
>> +    }
>> +
>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
>> +}
>> +
>> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
>> +        return;
>> +    }
>> +
>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
>> +}
>> +
>> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    int64_t value;
>> +    qmp_input_type_int(v,&value, name, errp);
>> +    *obj = value;
>> +}
>> +
>> +static void qmp_input_start_optional(Visitor *v, bool *present,
>> +                                     const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj) {
>> +        *present = false;
>> +        return;
>> +    }
>> +
>> +    *present = true;
>> +}
>> +
>> +static void qmp_input_end_optional(Visitor *v, Error **errp)
>> +{
>> +}
>> +
>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
>> +{
>> +    return&v->visitor;
>> +}
>> +
>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
>> +{
>
> We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
> decrefing here.
>

Sorry, remember the discussion but must've missed it when addressing 
comments. Will add it.

>> +    qemu_free(v);
>> +}
>> +
>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
>> +{
>> +    QmpInputVisitor *v;
>> +
>> +    v = qemu_mallocz(sizeof(*v));
>> +
>> +    v->visitor.start_struct = qmp_input_start_struct;
>> +    v->visitor.end_struct = qmp_input_end_struct;
>> +    v->visitor.start_list = qmp_input_start_list;
>> +    v->visitor.next_list = qmp_input_next_list;
>> +    v->visitor.end_list = qmp_input_end_list;
>> +    v->visitor.type_enum = qmp_input_type_enum;
>> +    v->visitor.type_int = qmp_input_type_int;
>> +    v->visitor.type_bool = qmp_input_type_bool;
>> +    v->visitor.type_str = qmp_input_type_str;
>> +    v->visitor.type_number = qmp_input_type_number;
>> +    v->visitor.start_optional = qmp_input_start_optional;
>> +    v->visitor.end_optional = qmp_input_end_optional;
>> +
>> +    v->obj = obj;
>> +
>> +    return v;
>> +}
>> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
>> new file mode 100644
>> index 0000000..0f77916
>> --- /dev/null
>> +++ b/qapi/qmp-input-visitor.h
>> @@ -0,0 +1,27 @@
>> +/*
>> + * Input Visitor
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#ifndef QMP_INPUT_VISITOR_H
>> +#define QMP_INPUT_VISITOR_H
>> +
>> +#include "qapi-visit-core.h"
>> +#include "qobject.h"
>> +
>> +typedef struct QmpInputVisitor QmpInputVisitor;
>> +
>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
>> +
>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
>> +
>> +#endif
>> diff --git a/qerror.h b/qerror.h
>> index 16c830d..9a9fa5b 100644
>> --- a/qerror.h
>> +++ b/qerror.h
>> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
>>   #define QERR_JSON_PARSE_ERROR \
>>       "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>>
>> +#define QERR_BUFFER_OVERRUN \
>> +    "{ 'class': 'BufferOverrun', 'data': {} }"
>> +
>
> You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
> but BufferOverrrun is probably fine.
>

I like overrun since it doesn't suggest an issue with insufficient 
host/process/guest memory. Will add to qerror.c

>>   #define QERR_KVM_MISSING_CAP \
>>       "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>>
>

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

* Re: [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5
  2011-07-07 14:37 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Luiz Capitulino
@ 2011-07-07 15:02   ` Michael Roth
  0 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-07 15:02 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 07/07/2011 09:37 AM, Luiz Capitulino wrote:
> On Tue,  5 Jul 2011 08:02:27 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> This is Set 2/3 of the QAPI+QGA patchsets.
>>
>> These patches apply on top of master (set1 merged), and can also be obtained
>> from:
>> git://repo.or.cz/qemu/mdroth.git qapi-backport-set2-v5
>
> This doesn't build due to a bug in error.h. If you didn't get it you're
> probably testing against a not up to date branch...
>
> I have the fix for error.h and will submit it.
>
> Only a few small issues remain, I think the next version will be good to go,
> although I'd only merge it along with the guest agent patches.
>

Doh, I see it too. I must've missed a build test after rebasing on 
master. I'll keep an eye out for your patch, thanks!

>>
>> (Set1+2 are a backport of some of the QAPI-related work from Anthony's
>> glib tree. The main goal is to get the basic code generation infrastructure in
>> place so that it can be used by the guest agent to implement a QMP-like guest
>> interface, and so that future work regarding the QMP conversion to QAPI can be
>> decoupled from the infrastructure bits. Set3 is the Qemu Guest Agent
>> (virtagent), rebased on the new code QAPI code generation infrastructure. This
>> is the first user of QAPI, QMP will follow.)
>> ___
>>
>> This patchset introduces the following:
>>
>>   - Hard dependency on GLib. This has been floating around the list for a while.
>>     Currently the only users are the unit tests for this patchset and the guest
>>     agent. We can make both of these a configure option, but based on previous
>>     discussions a hard dependency will likely be introduced with subsequent
>>     QAPI patches.
>>
>>   - A couple additional qlist utility functions used by QAPI.
>>
>>   - QAPI schema-based code generation for synchronous QMP/QGA commands
>>     and types, and Visitor/dispatch infrastructure to handle
>>     marshaling/unmarshaling/dispatch between QAPI and the QMP/QGA wire protocols.
>>
>>   - Documentation and unit tests for visitor functions and synchronous
>>     command/type generation.
>>
>> CHANGES SINCE V4:
>>   - Fix segfault in output visitor when dealing with QAPI-defined C structs
>>     with NULL pointers
>>
>> CHANGES SINCE V3:
>>   - Added copyright headers for generated code and remaining files
>>   - Added checking for required/extra parameters in top-level of QMP QObject
>>   - Made QDict arg to input visitor constructor a const
>>   - Renamed qmp_dispatch_err() ->  do_qmp_dispatch()
>>   - Changed QERR_QAPI_STACK_OVERRUN to QERR_BUFFER_OVERRUN
>>   - Moved configure changes to create QAPI directory when using a different build
>>     root to first patch which uses it.
>>   - Squashed Makefile changes for test-visitor/test-qmp-commands into single
>>     commits
>>   - Removed redundant NULL checks for qemu_free() in dealloc visitor
>>
>> CHANGES SINCE V2:
>>   - Added cleanup functions for input/output visitor types and fixed a leak in
>>     dispatch path.
>>   - Corrected spelling from visiter->visitor and updated filenames accordingly.
>>   - Re-organized patches so that each new C file can be built as part of the
>>     introducting commit (for instances where there were no users of the
>>     qapi-obj-y target yet a test build was done by adding the target as a
>>     superficial dependency on other tools), and moved code generator patches
>>     after the required dependencies.
>>   - Made qlist_first/qlist_next accept/return const types.
>>   - Moved Visitor interface inline wrapper functions to real ones.
>>   - Fixed error-reporting for invalid parameters when parameter name is null.
>>   - Removed hard-coded size for QAPI-type allocations done by the input visitor,
>>     using generated code to pass in a sizeof() now.
>>   - Replaced assert()'s on visitor stack overruns, replaced with an error
>>     indication.
>>   - Fixed build issue when using a separate build directory.
>>   - Added missing copyright headers for scripts, moved external code in
>>     ordereddict.py to a seperate patch.
>>   - Many thanks to Luiz, Anthony, and everyone else for the excellent
>>     review/testing.
>>
>> CHANGES SINCE V1:
>>   - Fixed build issue that was missed due to deprecated files being present in
>>     source tree. Thanks to Matsuda Daiki for sending fixes.
>>   - Fixed grammatical errors in documentation pointed out by Luiz.
>>   - Added generated code to the make clean target.
>>
>> CHANGES SINCE V0 ("QAPI Infrastructure Round 1"):
>>   - Fixed known memory leaks in generated code
>>   - Stricter error-handling in generated code
>>   - Removed currently unused code (generators for events and async/proxied
>>     QMP/QGA commands and definition used by the not-yet-introduced QMP server
>>     replacement)
>>   - Added documentation for code generation scripts/schemas/usage
>>   - Addressed review comments from Luiz and Stefan
>>
>>   Makefile                    |   24 +++-
>>   Makefile.objs               |    9 +
>>   Makefile.target             |    1 +
>>   configure                   |   14 ++
>>   docs/qapi-code-gen.txt      |  316 +++++++++++++++++++++++++++++++++++
>>   module.h                    |    2 +
>>   qapi-schema-test.json       |   22 +++
>>   qapi/qapi-dealloc-visitor.c |  138 ++++++++++++++++
>>   qapi/qapi-dealloc-visitor.h |   26 +++
>>   qapi/qapi-types-core.h      |   21 +++
>>   qapi/qapi-visit-core.c      |  114 +++++++++++++
>>   qapi/qapi-visit-core.h      |   68 ++++++++
>>   qapi/qmp-core.h             |   41 +++++
>>   qapi/qmp-dispatch.c         |  124 ++++++++++++++
>>   qapi/qmp-input-visitor.c    |  264 ++++++++++++++++++++++++++++++
>>   qapi/qmp-input-visitor.h    |   27 +++
>>   qapi/qmp-output-visitor.c   |  216 ++++++++++++++++++++++++
>>   qapi/qmp-output-visitor.h   |   28 +++
>>   qapi/qmp-registry.c         |   40 +++++
>>   qerror.h                    |    3 +
>>   qlist.h                     |   11 ++
>>   scripts/ordereddict.py      |  128 +++++++++++++++
>>   scripts/qapi-commands.py    |  381 +++++++++++++++++++++++++++++++++++++++++++
>>   scripts/qapi-types.py       |  258 +++++++++++++++++++++++++++++
>>   scripts/qapi-visit.py       |  261 +++++++++++++++++++++++++++++
>>   scripts/qapi.py             |  203 +++++++++++++++++++++++
>>   test-qmp-commands.c         |  113 +++++++++++++
>>   test-visitor.c              |  305 ++++++++++++++++++++++++++++++++++
>>   28 files changed, 3157 insertions(+), 1 deletions(-)
>>
>

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-07 14:32   ` Luiz Capitulino
  2011-07-07 14:45     ` Michael Roth
@ 2011-07-12  0:05     ` Michael Roth
  2011-07-12 13:16       ` Luiz Capitulino
  1 sibling, 1 reply; 30+ messages in thread
From: Michael Roth @ 2011-07-12  0:05 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
> On Tue,  5 Jul 2011 08:02:32 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> A type of Visiter class that is used to walk a qobject's
>> structure and assign each entry to the corresponding native C type.
>> Command marshaling function will use this to pull out QMP command
>> parameters recieved over the wire and pass them as native arguments
>> to the corresponding C functions.
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>> ---
>>   Makefile.objs            |    2 +-
>>   qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
>>   qapi/qmp-input-visitor.h |   27 +++++
>>   qerror.h                 |    3 +
>>   4 files changed, 295 insertions(+), 1 deletions(-)
>>   create mode 100644 qapi/qmp-input-visitor.c
>>   create mode 100644 qapi/qmp-input-visitor.h
>>
>> diff --git a/Makefile.objs b/Makefile.objs
>> index 0077014..997ecef 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
>>   ######################################################################
>>   # qapi
>>
>> -qapi-nested-y = qapi-visit-core.o
>> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
>>   qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>>
>>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
>> new file mode 100644
>> index 0000000..80912bb
>> --- /dev/null
>> +++ b/qapi/qmp-input-visitor.c
>> @@ -0,0 +1,264 @@
>> +/*
>> + * Input Visitor
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qmp-input-visitor.h"
>> +#include "qemu-queue.h"
>> +#include "qemu-common.h"
>> +#include "qemu-objects.h"
>> +#include "qerror.h"
>> +
>> +#define QIV_STACK_SIZE 1024
>> +
>> +typedef struct StackObject
>> +{
>> +    const QObject *obj;
>> +    const  QListEntry *entry;
>> +} StackObject;
>> +
>> +struct QmpInputVisitor
>> +{
>> +    Visitor visitor;
>> +    const QObject *obj;
>> +    StackObject stack[QIV_STACK_SIZE];
>> +    int nb_stack;
>> +};
>> +
>> +static QmpInputVisitor *to_qiv(Visitor *v)
>> +{
>> +    return container_of(v, QmpInputVisitor, visitor);
>> +}
>> +
>> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
>> +{
>> +    const QObject *qobj;
>> +
>> +    if (qiv->nb_stack == 0) {
>> +        qobj = qiv->obj;
>> +    } else {
>> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
>> +    }
>> +
>> +    if (name&&  qobject_type(qobj) == QTYPE_QDICT) {
>> +        return qdict_get(qobject_to_qdict(qobj), name);
>> +    } else if (qiv->nb_stack>  0&&  qobject_type(qobj) == QTYPE_QLIST) {
>> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
>> +    }
>> +
>> +    return qobj;
>> +}
>> +
>> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
>> +{
>> +    qiv->stack[qiv->nb_stack].obj = obj;
>> +    if (qobject_type(obj) == QTYPE_QLIST) {
>> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
>> +    }
>> +    qiv->nb_stack++;
>> +
>> +    if (qiv->nb_stack>= QIV_STACK_SIZE) {
>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>> +        return;
>> +    }
>> +}
>> +
>> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
>> +{
>> +    qiv->nb_stack--;
>> +    if (qiv->nb_stack<  0) {
>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>> +        return;
>> +    }
>> +}
>> +
>> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
>> +        return;
>> +    }
>> +
>> +    qmp_input_push(qiv, qobj, errp);
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    if (obj) {
>> +        *obj = qemu_mallocz(size);
>> +    }
>> +}
>> +
>> +static void qmp_input_end_struct(Visitor *v, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +
>> +    qmp_input_pop(qiv, errp);
>> +}
>> +
>> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
>> +        return;
>> +    }
>> +
>> +    qmp_input_push(qiv, qobj, errp);
>> +}
>> +
>> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    GenericList *entry;
>> +    StackObject *so =&qiv->stack[qiv->nb_stack - 1];
>> +
>> +    if (so->entry == NULL) {
>> +        return NULL;
>> +    }
>> +
>> +    entry = qemu_mallocz(sizeof(*entry));
>> +    if (*list) {
>> +        so->entry = qlist_next(so->entry);
>> +        if (so->entry == NULL) {
>> +            qemu_free(entry);
>> +            return NULL;
>> +        }
>> +        (*list)->next = entry;
>> +    }
>> +    *list = entry;
>> +
>> +
>> +    return entry;
>> +}
>> +
>> +static void qmp_input_end_list(Visitor *v, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +
>> +    qmp_input_pop(qiv, errp);
>> +}
>> +
>> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
>> +        return;
>> +    }
>> +
>> +    *obj = qint_get_int(qobject_to_qint(qobj));
>> +}
>> +
>> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
>> +        return;
>> +    }
>> +
>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
>> +}
>> +
>> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
>> +        return;
>> +    }
>> +
>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
>> +}
>> +
>> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
>> +        return;
>> +    }
>> +
>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
>> +}
>> +
>> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    int64_t value;
>> +    qmp_input_type_int(v,&value, name, errp);
>> +    *obj = value;
>> +}
>> +
>> +static void qmp_input_start_optional(Visitor *v, bool *present,
>> +                                     const char *name, Error **errp)
>> +{
>> +    QmpInputVisitor *qiv = to_qiv(v);
>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj) {
>> +        *present = false;
>> +        return;
>> +    }
>> +
>> +    *present = true;
>> +}
>> +
>> +static void qmp_input_end_optional(Visitor *v, Error **errp)
>> +{
>> +}
>> +
>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
>> +{
>> +    return&v->visitor;
>> +}
>> +
>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
>> +{
>
> We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
> decrefing here.
>

I think it was either that, or just making the QObject arg to 
qmp_input_visitor_new() const, to make it clear it was caller-freed.

>> +    qemu_free(v);
>> +}
>> +
>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
>> +{
>> +    QmpInputVisitor *v;
>> +
>> +    v = qemu_mallocz(sizeof(*v));
>> +
>> +    v->visitor.start_struct = qmp_input_start_struct;
>> +    v->visitor.end_struct = qmp_input_end_struct;
>> +    v->visitor.start_list = qmp_input_start_list;
>> +    v->visitor.next_list = qmp_input_next_list;
>> +    v->visitor.end_list = qmp_input_end_list;
>> +    v->visitor.type_enum = qmp_input_type_enum;
>> +    v->visitor.type_int = qmp_input_type_int;
>> +    v->visitor.type_bool = qmp_input_type_bool;
>> +    v->visitor.type_str = qmp_input_type_str;
>> +    v->visitor.type_number = qmp_input_type_number;
>> +    v->visitor.start_optional = qmp_input_start_optional;
>> +    v->visitor.end_optional = qmp_input_end_optional;
>> +
>> +    v->obj = obj;
>> +
>> +    return v;
>> +}
>> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
>> new file mode 100644
>> index 0000000..0f77916
>> --- /dev/null
>> +++ b/qapi/qmp-input-visitor.h
>> @@ -0,0 +1,27 @@
>> +/*
>> + * Input Visitor
>> + *
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>> + * See the COPYING.LIB file in the top-level directory.
>> + *
>> + */
>> +
>> +#ifndef QMP_INPUT_VISITOR_H
>> +#define QMP_INPUT_VISITOR_H
>> +
>> +#include "qapi-visit-core.h"
>> +#include "qobject.h"
>> +
>> +typedef struct QmpInputVisitor QmpInputVisitor;
>> +
>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
>> +
>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
>> +
>> +#endif
>> diff --git a/qerror.h b/qerror.h
>> index 16c830d..9a9fa5b 100644
>> --- a/qerror.h
>> +++ b/qerror.h
>> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
>>   #define QERR_JSON_PARSE_ERROR \
>>       "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>>
>> +#define QERR_BUFFER_OVERRUN \
>> +    "{ 'class': 'BufferOverrun', 'data': {} }"
>> +
>
> You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
> but BufferOverrrun is probably fine.
>
>>   #define QERR_KVM_MISSING_CAP \
>>       "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>>
>

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-12  0:05     ` Michael Roth
@ 2011-07-12 13:16       ` Luiz Capitulino
  2011-07-12 13:46         ` Michael Roth
  0 siblings, 1 reply; 30+ messages in thread
From: Luiz Capitulino @ 2011-07-12 13:16 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Mon, 11 Jul 2011 19:05:58 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
> > On Tue,  5 Jul 2011 08:02:32 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >> A type of Visiter class that is used to walk a qobject's
> >> structure and assign each entry to the corresponding native C type.
> >> Command marshaling function will use this to pull out QMP command
> >> parameters recieved over the wire and pass them as native arguments
> >> to the corresponding C functions.
> >>
> >> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> >> ---
> >>   Makefile.objs            |    2 +-
> >>   qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
> >>   qapi/qmp-input-visitor.h |   27 +++++
> >>   qerror.h                 |    3 +
> >>   4 files changed, 295 insertions(+), 1 deletions(-)
> >>   create mode 100644 qapi/qmp-input-visitor.c
> >>   create mode 100644 qapi/qmp-input-visitor.h
> >>
> >> diff --git a/Makefile.objs b/Makefile.objs
> >> index 0077014..997ecef 100644
> >> --- a/Makefile.objs
> >> +++ b/Makefile.objs
> >> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
> >>   ######################################################################
> >>   # qapi
> >>
> >> -qapi-nested-y = qapi-visit-core.o
> >> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
> >>   qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
> >>
> >>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> >> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
> >> new file mode 100644
> >> index 0000000..80912bb
> >> --- /dev/null
> >> +++ b/qapi/qmp-input-visitor.c
> >> @@ -0,0 +1,264 @@
> >> +/*
> >> + * Input Visitor
> >> + *
> >> + * Copyright IBM, Corp. 2011
> >> + *
> >> + * Authors:
> >> + *  Anthony Liguori<aliguori@us.ibm.com>
> >> + *
> >> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> >> + * See the COPYING.LIB file in the top-level directory.
> >> + *
> >> + */
> >> +
> >> +#include "qmp-input-visitor.h"
> >> +#include "qemu-queue.h"
> >> +#include "qemu-common.h"
> >> +#include "qemu-objects.h"
> >> +#include "qerror.h"
> >> +
> >> +#define QIV_STACK_SIZE 1024
> >> +
> >> +typedef struct StackObject
> >> +{
> >> +    const QObject *obj;
> >> +    const  QListEntry *entry;
> >> +} StackObject;
> >> +
> >> +struct QmpInputVisitor
> >> +{
> >> +    Visitor visitor;
> >> +    const QObject *obj;
> >> +    StackObject stack[QIV_STACK_SIZE];
> >> +    int nb_stack;
> >> +};
> >> +
> >> +static QmpInputVisitor *to_qiv(Visitor *v)
> >> +{
> >> +    return container_of(v, QmpInputVisitor, visitor);
> >> +}
> >> +
> >> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
> >> +{
> >> +    const QObject *qobj;
> >> +
> >> +    if (qiv->nb_stack == 0) {
> >> +        qobj = qiv->obj;
> >> +    } else {
> >> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
> >> +    }
> >> +
> >> +    if (name&&  qobject_type(qobj) == QTYPE_QDICT) {
> >> +        return qdict_get(qobject_to_qdict(qobj), name);
> >> +    } else if (qiv->nb_stack>  0&&  qobject_type(qobj) == QTYPE_QLIST) {
> >> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
> >> +    }
> >> +
> >> +    return qobj;
> >> +}
> >> +
> >> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
> >> +{
> >> +    qiv->stack[qiv->nb_stack].obj = obj;
> >> +    if (qobject_type(obj) == QTYPE_QLIST) {
> >> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
> >> +    }
> >> +    qiv->nb_stack++;
> >> +
> >> +    if (qiv->nb_stack>= QIV_STACK_SIZE) {
> >> +        error_set(errp, QERR_BUFFER_OVERRUN);
> >> +        return;
> >> +    }
> >> +}
> >> +
> >> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
> >> +{
> >> +    qiv->nb_stack--;
> >> +    if (qiv->nb_stack<  0) {
> >> +        error_set(errp, QERR_BUFFER_OVERRUN);
> >> +        return;
> >> +    }
> >> +}
> >> +
> >> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
> >> +        return;
> >> +    }
> >> +
> >> +    qmp_input_push(qiv, qobj, errp);
> >> +    if (error_is_set(errp)) {
> >> +        return;
> >> +    }
> >> +
> >> +    if (obj) {
> >> +        *obj = qemu_mallocz(size);
> >> +    }
> >> +}
> >> +
> >> +static void qmp_input_end_struct(Visitor *v, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +
> >> +    qmp_input_pop(qiv, errp);
> >> +}
> >> +
> >> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
> >> +        return;
> >> +    }
> >> +
> >> +    qmp_input_push(qiv, qobj, errp);
> >> +}
> >> +
> >> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    GenericList *entry;
> >> +    StackObject *so =&qiv->stack[qiv->nb_stack - 1];
> >> +
> >> +    if (so->entry == NULL) {
> >> +        return NULL;
> >> +    }
> >> +
> >> +    entry = qemu_mallocz(sizeof(*entry));
> >> +    if (*list) {
> >> +        so->entry = qlist_next(so->entry);
> >> +        if (so->entry == NULL) {
> >> +            qemu_free(entry);
> >> +            return NULL;
> >> +        }
> >> +        (*list)->next = entry;
> >> +    }
> >> +    *list = entry;
> >> +
> >> +
> >> +    return entry;
> >> +}
> >> +
> >> +static void qmp_input_end_list(Visitor *v, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +
> >> +    qmp_input_pop(qiv, errp);
> >> +}
> >> +
> >> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qint_get_int(qobject_to_qint(qobj));
> >> +}
> >> +
> >> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
> >> +}
> >> +
> >> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
> >> +}
> >> +
> >> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
> >> +}
> >> +
> >> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> >> +{
> >> +    int64_t value;
> >> +    qmp_input_type_int(v,&value, name, errp);
> >> +    *obj = value;
> >> +}
> >> +
> >> +static void qmp_input_start_optional(Visitor *v, bool *present,
> >> +                                     const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisitor *qiv = to_qiv(v);
> >> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj) {
> >> +        *present = false;
> >> +        return;
> >> +    }
> >> +
> >> +    *present = true;
> >> +}
> >> +
> >> +static void qmp_input_end_optional(Visitor *v, Error **errp)
> >> +{
> >> +}
> >> +
> >> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
> >> +{
> >> +    return&v->visitor;
> >> +}
> >> +
> >> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
> >> +{
> >
> > We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
> > decrefing here.
> >
> 
> I think it was either that, or just making the QObject arg to 
> qmp_input_visitor_new() const, to make it clear it was caller-freed.

No, because (at least theoretically) a client could free it before walking
the struct with the visitor functions. The rule is: if you store it, you
have to increment its reference or get its ownership.


> 
> >> +    qemu_free(v);
> >> +}
> >> +
> >> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
> >> +{
> >> +    QmpInputVisitor *v;
> >> +
> >> +    v = qemu_mallocz(sizeof(*v));
> >> +
> >> +    v->visitor.start_struct = qmp_input_start_struct;
> >> +    v->visitor.end_struct = qmp_input_end_struct;
> >> +    v->visitor.start_list = qmp_input_start_list;
> >> +    v->visitor.next_list = qmp_input_next_list;
> >> +    v->visitor.end_list = qmp_input_end_list;
> >> +    v->visitor.type_enum = qmp_input_type_enum;
> >> +    v->visitor.type_int = qmp_input_type_int;
> >> +    v->visitor.type_bool = qmp_input_type_bool;
> >> +    v->visitor.type_str = qmp_input_type_str;
> >> +    v->visitor.type_number = qmp_input_type_number;
> >> +    v->visitor.start_optional = qmp_input_start_optional;
> >> +    v->visitor.end_optional = qmp_input_end_optional;
> >> +
> >> +    v->obj = obj;
> >> +
> >> +    return v;
> >> +}
> >> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
> >> new file mode 100644
> >> index 0000000..0f77916
> >> --- /dev/null
> >> +++ b/qapi/qmp-input-visitor.h
> >> @@ -0,0 +1,27 @@
> >> +/*
> >> + * Input Visitor
> >> + *
> >> + * Copyright IBM, Corp. 2011
> >> + *
> >> + * Authors:
> >> + *  Anthony Liguori<aliguori@us.ibm.com>
> >> + *
> >> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> >> + * See the COPYING.LIB file in the top-level directory.
> >> + *
> >> + */
> >> +
> >> +#ifndef QMP_INPUT_VISITOR_H
> >> +#define QMP_INPUT_VISITOR_H
> >> +
> >> +#include "qapi-visit-core.h"
> >> +#include "qobject.h"
> >> +
> >> +typedef struct QmpInputVisitor QmpInputVisitor;
> >> +
> >> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
> >> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
> >> +
> >> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
> >> +
> >> +#endif
> >> diff --git a/qerror.h b/qerror.h
> >> index 16c830d..9a9fa5b 100644
> >> --- a/qerror.h
> >> +++ b/qerror.h
> >> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
> >>   #define QERR_JSON_PARSE_ERROR \
> >>       "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
> >>
> >> +#define QERR_BUFFER_OVERRUN \
> >> +    "{ 'class': 'BufferOverrun', 'data': {} }"
> >> +
> >
> > You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
> > but BufferOverrrun is probably fine.
> >
> >>   #define QERR_KVM_MISSING_CAP \
> >>       "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
> >>
> >
> 

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-12 13:16       ` Luiz Capitulino
@ 2011-07-12 13:46         ` Michael Roth
  2011-07-12 13:53           ` Luiz Capitulino
  0 siblings, 1 reply; 30+ messages in thread
From: Michael Roth @ 2011-07-12 13:46 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 07/12/2011 08:16 AM, Luiz Capitulino wrote:
> On Mon, 11 Jul 2011 19:05:58 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
>>> On Tue,  5 Jul 2011 08:02:32 -0500
>>> Michael Roth<mdroth@linux.vnet.ibm.com>   wrote:
>>>
>>>> A type of Visiter class that is used to walk a qobject's
>>>> structure and assign each entry to the corresponding native C type.
>>>> Command marshaling function will use this to pull out QMP command
>>>> parameters recieved over the wire and pass them as native arguments
>>>> to the corresponding C functions.
>>>>
>>>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>>>> ---
>>>>    Makefile.objs            |    2 +-
>>>>    qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>    qapi/qmp-input-visitor.h |   27 +++++
>>>>    qerror.h                 |    3 +
>>>>    4 files changed, 295 insertions(+), 1 deletions(-)
>>>>    create mode 100644 qapi/qmp-input-visitor.c
>>>>    create mode 100644 qapi/qmp-input-visitor.h
>>>>
>>>> diff --git a/Makefile.objs b/Makefile.objs
>>>> index 0077014..997ecef 100644
>>>> --- a/Makefile.objs
>>>> +++ b/Makefile.objs
>>>> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
>>>>    ######################################################################
>>>>    # qapi
>>>>
>>>> -qapi-nested-y = qapi-visit-core.o
>>>> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
>>>>    qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>>>>
>>>>    vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>>> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
>>>> new file mode 100644
>>>> index 0000000..80912bb
>>>> --- /dev/null
>>>> +++ b/qapi/qmp-input-visitor.c
>>>> @@ -0,0 +1,264 @@
>>>> +/*
>>>> + * Input Visitor
>>>> + *
>>>> + * Copyright IBM, Corp. 2011
>>>> + *
>>>> + * Authors:
>>>> + *  Anthony Liguori<aliguori@us.ibm.com>
>>>> + *
>>>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>>>> + * See the COPYING.LIB file in the top-level directory.
>>>> + *
>>>> + */
>>>> +
>>>> +#include "qmp-input-visitor.h"
>>>> +#include "qemu-queue.h"
>>>> +#include "qemu-common.h"
>>>> +#include "qemu-objects.h"
>>>> +#include "qerror.h"
>>>> +
>>>> +#define QIV_STACK_SIZE 1024
>>>> +
>>>> +typedef struct StackObject
>>>> +{
>>>> +    const QObject *obj;
>>>> +    const  QListEntry *entry;
>>>> +} StackObject;
>>>> +
>>>> +struct QmpInputVisitor
>>>> +{
>>>> +    Visitor visitor;
>>>> +    const QObject *obj;
>>>> +    StackObject stack[QIV_STACK_SIZE];
>>>> +    int nb_stack;
>>>> +};
>>>> +
>>>> +static QmpInputVisitor *to_qiv(Visitor *v)
>>>> +{
>>>> +    return container_of(v, QmpInputVisitor, visitor);
>>>> +}
>>>> +
>>>> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
>>>> +{
>>>> +    const QObject *qobj;
>>>> +
>>>> +    if (qiv->nb_stack == 0) {
>>>> +        qobj = qiv->obj;
>>>> +    } else {
>>>> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
>>>> +    }
>>>> +
>>>> +    if (name&&   qobject_type(qobj) == QTYPE_QDICT) {
>>>> +        return qdict_get(qobject_to_qdict(qobj), name);
>>>> +    } else if (qiv->nb_stack>   0&&   qobject_type(qobj) == QTYPE_QLIST) {
>>>> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
>>>> +    }
>>>> +
>>>> +    return qobj;
>>>> +}
>>>> +
>>>> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
>>>> +{
>>>> +    qiv->stack[qiv->nb_stack].obj = obj;
>>>> +    if (qobject_type(obj) == QTYPE_QLIST) {
>>>> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
>>>> +    }
>>>> +    qiv->nb_stack++;
>>>> +
>>>> +    if (qiv->nb_stack>= QIV_STACK_SIZE) {
>>>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>>>> +        return;
>>>> +    }
>>>> +}
>>>> +
>>>> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
>>>> +{
>>>> +    qiv->nb_stack--;
>>>> +    if (qiv->nb_stack<   0) {
>>>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>>>> +        return;
>>>> +    }
>>>> +}
>>>> +
>>>> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    qmp_input_push(qiv, qobj, errp);
>>>> +    if (error_is_set(errp)) {
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    if (obj) {
>>>> +        *obj = qemu_mallocz(size);
>>>> +    }
>>>> +}
>>>> +
>>>> +static void qmp_input_end_struct(Visitor *v, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +
>>>> +    qmp_input_pop(qiv, errp);
>>>> +}
>>>> +
>>>> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    qmp_input_push(qiv, qobj, errp);
>>>> +}
>>>> +
>>>> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    GenericList *entry;
>>>> +    StackObject *so =&qiv->stack[qiv->nb_stack - 1];
>>>> +
>>>> +    if (so->entry == NULL) {
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    entry = qemu_mallocz(sizeof(*entry));
>>>> +    if (*list) {
>>>> +        so->entry = qlist_next(so->entry);
>>>> +        if (so->entry == NULL) {
>>>> +            qemu_free(entry);
>>>> +            return NULL;
>>>> +        }
>>>> +        (*list)->next = entry;
>>>> +    }
>>>> +    *list = entry;
>>>> +
>>>> +
>>>> +    return entry;
>>>> +}
>>>> +
>>>> +static void qmp_input_end_list(Visitor *v, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +
>>>> +    qmp_input_pop(qiv, errp);
>>>> +}
>>>> +
>>>> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qint_get_int(qobject_to_qint(qobj));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
>>>> +{
>>>> +    int64_t value;
>>>> +    qmp_input_type_int(v,&value, name, errp);
>>>> +    *obj = value;
>>>> +}
>>>> +
>>>> +static void qmp_input_start_optional(Visitor *v, bool *present,
>>>> +                                     const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj) {
>>>> +        *present = false;
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *present = true;
>>>> +}
>>>> +
>>>> +static void qmp_input_end_optional(Visitor *v, Error **errp)
>>>> +{
>>>> +}
>>>> +
>>>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
>>>> +{
>>>> +    return&v->visitor;
>>>> +}
>>>> +
>>>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
>>>> +{
>>>
>>> We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
>>> decrefing here.
>>>
>>
>> I think it was either that, or just making the QObject arg to
>> qmp_input_visitor_new() const, to make it clear it was caller-freed.
>
> No, because (at least theoretically) a client could free it before walking
> the struct with the visitor functions. The rule is: if you store it, you
> have to increment its reference or get its ownership.
>
>

Makes sense. Sucks to have to remove the const for that though...would a 
temporary cast to non-const be acceptable in a case like this?

>>
>>>> +    qemu_free(v);
>>>> +}
>>>> +
>>>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
>>>> +{
>>>> +    QmpInputVisitor *v;
>>>> +
>>>> +    v = qemu_mallocz(sizeof(*v));
>>>> +
>>>> +    v->visitor.start_struct = qmp_input_start_struct;
>>>> +    v->visitor.end_struct = qmp_input_end_struct;
>>>> +    v->visitor.start_list = qmp_input_start_list;
>>>> +    v->visitor.next_list = qmp_input_next_list;
>>>> +    v->visitor.end_list = qmp_input_end_list;
>>>> +    v->visitor.type_enum = qmp_input_type_enum;
>>>> +    v->visitor.type_int = qmp_input_type_int;
>>>> +    v->visitor.type_bool = qmp_input_type_bool;
>>>> +    v->visitor.type_str = qmp_input_type_str;
>>>> +    v->visitor.type_number = qmp_input_type_number;
>>>> +    v->visitor.start_optional = qmp_input_start_optional;
>>>> +    v->visitor.end_optional = qmp_input_end_optional;
>>>> +
>>>> +    v->obj = obj;
>>>> +
>>>> +    return v;
>>>> +}
>>>> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
>>>> new file mode 100644
>>>> index 0000000..0f77916
>>>> --- /dev/null
>>>> +++ b/qapi/qmp-input-visitor.h
>>>> @@ -0,0 +1,27 @@
>>>> +/*
>>>> + * Input Visitor
>>>> + *
>>>> + * Copyright IBM, Corp. 2011
>>>> + *
>>>> + * Authors:
>>>> + *  Anthony Liguori<aliguori@us.ibm.com>
>>>> + *
>>>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>>>> + * See the COPYING.LIB file in the top-level directory.
>>>> + *
>>>> + */
>>>> +
>>>> +#ifndef QMP_INPUT_VISITOR_H
>>>> +#define QMP_INPUT_VISITOR_H
>>>> +
>>>> +#include "qapi-visit-core.h"
>>>> +#include "qobject.h"
>>>> +
>>>> +typedef struct QmpInputVisitor QmpInputVisitor;
>>>> +
>>>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
>>>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
>>>> +
>>>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
>>>> +
>>>> +#endif
>>>> diff --git a/qerror.h b/qerror.h
>>>> index 16c830d..9a9fa5b 100644
>>>> --- a/qerror.h
>>>> +++ b/qerror.h
>>>> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
>>>>    #define QERR_JSON_PARSE_ERROR \
>>>>        "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>>>>
>>>> +#define QERR_BUFFER_OVERRUN \
>>>> +    "{ 'class': 'BufferOverrun', 'data': {} }"
>>>> +
>>>
>>> You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
>>> but BufferOverrrun is probably fine.
>>>
>>>>    #define QERR_KVM_MISSING_CAP \
>>>>        "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>>>>
>>>
>>
>

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-12 13:46         ` Michael Roth
@ 2011-07-12 13:53           ` Luiz Capitulino
  2011-07-12 14:14             ` Michael Roth
  0 siblings, 1 reply; 30+ messages in thread
From: Luiz Capitulino @ 2011-07-12 13:53 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Tue, 12 Jul 2011 08:46:13 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 07/12/2011 08:16 AM, Luiz Capitulino wrote:
> > On Mon, 11 Jul 2011 19:05:58 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >> On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
> >>> On Tue,  5 Jul 2011 08:02:32 -0500
> >>> Michael Roth<mdroth@linux.vnet.ibm.com>   wrote:
> >>>
> >>>> A type of Visiter class that is used to walk a qobject's
> >>>> structure and assign each entry to the corresponding native C type.
> >>>> Command marshaling function will use this to pull out QMP command
> >>>> parameters recieved over the wire and pass them as native arguments
> >>>> to the corresponding C functions.
> >>>>
> >>>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> >>>> ---
> >>>>    Makefile.objs            |    2 +-
> >>>>    qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
> >>>>    qapi/qmp-input-visitor.h |   27 +++++
> >>>>    qerror.h                 |    3 +
> >>>>    4 files changed, 295 insertions(+), 1 deletions(-)
> >>>>    create mode 100644 qapi/qmp-input-visitor.c
> >>>>    create mode 100644 qapi/qmp-input-visitor.h
> >>>>
> >>>> diff --git a/Makefile.objs b/Makefile.objs
> >>>> index 0077014..997ecef 100644
> >>>> --- a/Makefile.objs
> >>>> +++ b/Makefile.objs
> >>>> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
> >>>>    ######################################################################
> >>>>    # qapi
> >>>>
> >>>> -qapi-nested-y = qapi-visit-core.o
> >>>> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
> >>>>    qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
> >>>>
> >>>>    vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> >>>> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
> >>>> new file mode 100644
> >>>> index 0000000..80912bb
> >>>> --- /dev/null
> >>>> +++ b/qapi/qmp-input-visitor.c
> >>>> @@ -0,0 +1,264 @@
> >>>> +/*
> >>>> + * Input Visitor
> >>>> + *
> >>>> + * Copyright IBM, Corp. 2011
> >>>> + *
> >>>> + * Authors:
> >>>> + *  Anthony Liguori<aliguori@us.ibm.com>
> >>>> + *
> >>>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> >>>> + * See the COPYING.LIB file in the top-level directory.
> >>>> + *
> >>>> + */
> >>>> +
> >>>> +#include "qmp-input-visitor.h"
> >>>> +#include "qemu-queue.h"
> >>>> +#include "qemu-common.h"
> >>>> +#include "qemu-objects.h"
> >>>> +#include "qerror.h"
> >>>> +
> >>>> +#define QIV_STACK_SIZE 1024
> >>>> +
> >>>> +typedef struct StackObject
> >>>> +{
> >>>> +    const QObject *obj;
> >>>> +    const  QListEntry *entry;
> >>>> +} StackObject;
> >>>> +
> >>>> +struct QmpInputVisitor
> >>>> +{
> >>>> +    Visitor visitor;
> >>>> +    const QObject *obj;
> >>>> +    StackObject stack[QIV_STACK_SIZE];
> >>>> +    int nb_stack;
> >>>> +};
> >>>> +
> >>>> +static QmpInputVisitor *to_qiv(Visitor *v)
> >>>> +{
> >>>> +    return container_of(v, QmpInputVisitor, visitor);
> >>>> +}
> >>>> +
> >>>> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
> >>>> +{
> >>>> +    const QObject *qobj;
> >>>> +
> >>>> +    if (qiv->nb_stack == 0) {
> >>>> +        qobj = qiv->obj;
> >>>> +    } else {
> >>>> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
> >>>> +    }
> >>>> +
> >>>> +    if (name&&   qobject_type(qobj) == QTYPE_QDICT) {
> >>>> +        return qdict_get(qobject_to_qdict(qobj), name);
> >>>> +    } else if (qiv->nb_stack>   0&&   qobject_type(qobj) == QTYPE_QLIST) {
> >>>> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
> >>>> +    }
> >>>> +
> >>>> +    return qobj;
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
> >>>> +{
> >>>> +    qiv->stack[qiv->nb_stack].obj = obj;
> >>>> +    if (qobject_type(obj) == QTYPE_QLIST) {
> >>>> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
> >>>> +    }
> >>>> +    qiv->nb_stack++;
> >>>> +
> >>>> +    if (qiv->nb_stack>= QIV_STACK_SIZE) {
> >>>> +        error_set(errp, QERR_BUFFER_OVERRUN);
> >>>> +        return;
> >>>> +    }
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
> >>>> +{
> >>>> +    qiv->nb_stack--;
> >>>> +    if (qiv->nb_stack<   0) {
> >>>> +        error_set(errp, QERR_BUFFER_OVERRUN);
> >>>> +        return;
> >>>> +    }
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
> >>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    qmp_input_push(qiv, qobj, errp);
> >>>> +    if (error_is_set(errp)) {
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    if (obj) {
> >>>> +        *obj = qemu_mallocz(size);
> >>>> +    }
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_end_struct(Visitor *v, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +
> >>>> +    qmp_input_pop(qiv, errp);
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
> >>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    qmp_input_push(qiv, qobj, errp);
> >>>> +}
> >>>> +
> >>>> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    GenericList *entry;
> >>>> +    StackObject *so =&qiv->stack[qiv->nb_stack - 1];
> >>>> +
> >>>> +    if (so->entry == NULL) {
> >>>> +        return NULL;
> >>>> +    }
> >>>> +
> >>>> +    entry = qemu_mallocz(sizeof(*entry));
> >>>> +    if (*list) {
> >>>> +        so->entry = qlist_next(so->entry);
> >>>> +        if (so->entry == NULL) {
> >>>> +            qemu_free(entry);
> >>>> +            return NULL;
> >>>> +        }
> >>>> +        (*list)->next = entry;
> >>>> +    }
> >>>> +    *list = entry;
> >>>> +
> >>>> +
> >>>> +    return entry;
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_end_list(Visitor *v, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +
> >>>> +    qmp_input_pop(qiv, errp);
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> >>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    *obj = qint_get_int(qobject_to_qint(qobj));
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
> >>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
> >>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
> >>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
> >>>> +{
> >>>> +    int64_t value;
> >>>> +    qmp_input_type_int(v,&value, name, errp);
> >>>> +    *obj = value;
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_start_optional(Visitor *v, bool *present,
> >>>> +                                     const char *name, Error **errp)
> >>>> +{
> >>>> +    QmpInputVisitor *qiv = to_qiv(v);
> >>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
> >>>> +
> >>>> +    if (!qobj) {
> >>>> +        *present = false;
> >>>> +        return;
> >>>> +    }
> >>>> +
> >>>> +    *present = true;
> >>>> +}
> >>>> +
> >>>> +static void qmp_input_end_optional(Visitor *v, Error **errp)
> >>>> +{
> >>>> +}
> >>>> +
> >>>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
> >>>> +{
> >>>> +    return&v->visitor;
> >>>> +}
> >>>> +
> >>>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
> >>>> +{
> >>>
> >>> We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
> >>> decrefing here.
> >>>
> >>
> >> I think it was either that, or just making the QObject arg to
> >> qmp_input_visitor_new() const, to make it clear it was caller-freed.
> >
> > No, because (at least theoretically) a client could free it before walking
> > the struct with the visitor functions. The rule is: if you store it, you
> > have to increment its reference or get its ownership.
> >
> >
> 
> Makes sense. Sucks to have to remove the const for that though...would a 
> temporary cast to non-const be acceptable in a case like this?

Well, if we have to change it, it's not const anymore :)

> 
> >>
> >>>> +    qemu_free(v);
> >>>> +}
> >>>> +
> >>>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
> >>>> +{
> >>>> +    QmpInputVisitor *v;
> >>>> +
> >>>> +    v = qemu_mallocz(sizeof(*v));
> >>>> +
> >>>> +    v->visitor.start_struct = qmp_input_start_struct;
> >>>> +    v->visitor.end_struct = qmp_input_end_struct;
> >>>> +    v->visitor.start_list = qmp_input_start_list;
> >>>> +    v->visitor.next_list = qmp_input_next_list;
> >>>> +    v->visitor.end_list = qmp_input_end_list;
> >>>> +    v->visitor.type_enum = qmp_input_type_enum;
> >>>> +    v->visitor.type_int = qmp_input_type_int;
> >>>> +    v->visitor.type_bool = qmp_input_type_bool;
> >>>> +    v->visitor.type_str = qmp_input_type_str;
> >>>> +    v->visitor.type_number = qmp_input_type_number;
> >>>> +    v->visitor.start_optional = qmp_input_start_optional;
> >>>> +    v->visitor.end_optional = qmp_input_end_optional;
> >>>> +
> >>>> +    v->obj = obj;
> >>>> +
> >>>> +    return v;
> >>>> +}
> >>>> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
> >>>> new file mode 100644
> >>>> index 0000000..0f77916
> >>>> --- /dev/null
> >>>> +++ b/qapi/qmp-input-visitor.h
> >>>> @@ -0,0 +1,27 @@
> >>>> +/*
> >>>> + * Input Visitor
> >>>> + *
> >>>> + * Copyright IBM, Corp. 2011
> >>>> + *
> >>>> + * Authors:
> >>>> + *  Anthony Liguori<aliguori@us.ibm.com>
> >>>> + *
> >>>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> >>>> + * See the COPYING.LIB file in the top-level directory.
> >>>> + *
> >>>> + */
> >>>> +
> >>>> +#ifndef QMP_INPUT_VISITOR_H
> >>>> +#define QMP_INPUT_VISITOR_H
> >>>> +
> >>>> +#include "qapi-visit-core.h"
> >>>> +#include "qobject.h"
> >>>> +
> >>>> +typedef struct QmpInputVisitor QmpInputVisitor;
> >>>> +
> >>>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
> >>>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
> >>>> +
> >>>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
> >>>> +
> >>>> +#endif
> >>>> diff --git a/qerror.h b/qerror.h
> >>>> index 16c830d..9a9fa5b 100644
> >>>> --- a/qerror.h
> >>>> +++ b/qerror.h
> >>>> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
> >>>>    #define QERR_JSON_PARSE_ERROR \
> >>>>        "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
> >>>>
> >>>> +#define QERR_BUFFER_OVERRUN \
> >>>> +    "{ 'class': 'BufferOverrun', 'data': {} }"
> >>>> +
> >>>
> >>> You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
> >>> but BufferOverrrun is probably fine.
> >>>
> >>>>    #define QERR_KVM_MISSING_CAP \
> >>>>        "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
> >>>>
> >>>
> >>
> >
> 

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

* Re: [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor
  2011-07-12 13:53           ` Luiz Capitulino
@ 2011-07-12 14:14             ` Michael Roth
  0 siblings, 0 replies; 30+ messages in thread
From: Michael Roth @ 2011-07-12 14:14 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 07/12/2011 08:53 AM, Luiz Capitulino wrote:
> On Tue, 12 Jul 2011 08:46:13 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> On 07/12/2011 08:16 AM, Luiz Capitulino wrote:
>>> On Mon, 11 Jul 2011 19:05:58 -0500
>>> Michael Roth<mdroth@linux.vnet.ibm.com>   wrote:
>>>
>>>> On 07/07/2011 09:32 AM, Luiz Capitulino wrote:
>>>>> On Tue,  5 Jul 2011 08:02:32 -0500
>>>>> Michael Roth<mdroth@linux.vnet.ibm.com>    wrote:
>>>>>
>>>>>> A type of Visiter class that is used to walk a qobject's
>>>>>> structure and assign each entry to the corresponding native C type.
>>>>>> Command marshaling function will use this to pull out QMP command
>>>>>> parameters recieved over the wire and pass them as native arguments
>>>>>> to the corresponding C functions.
>>>>>>
>>>>>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>>>>>> ---
>>>>>>     Makefile.objs            |    2 +-
>>>>>>     qapi/qmp-input-visitor.c |  264 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>     qapi/qmp-input-visitor.h |   27 +++++
>>>>>>     qerror.h                 |    3 +
>>>>>>     4 files changed, 295 insertions(+), 1 deletions(-)
>>>>>>     create mode 100644 qapi/qmp-input-visitor.c
>>>>>>     create mode 100644 qapi/qmp-input-visitor.h
>>>>>>
>>>>>> diff --git a/Makefile.objs b/Makefile.objs
>>>>>> index 0077014..997ecef 100644
>>>>>> --- a/Makefile.objs
>>>>>> +++ b/Makefile.objs
>>>>>> @@ -375,7 +375,7 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
>>>>>>     ######################################################################
>>>>>>     # qapi
>>>>>>
>>>>>> -qapi-nested-y = qapi-visit-core.o
>>>>>> +qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o
>>>>>>     qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>>>>>>
>>>>>>     vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>>>>> diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
>>>>>> new file mode 100644
>>>>>> index 0000000..80912bb
>>>>>> --- /dev/null
>>>>>> +++ b/qapi/qmp-input-visitor.c
>>>>>> @@ -0,0 +1,264 @@
>>>>>> +/*
>>>>>> + * Input Visitor
>>>>>> + *
>>>>>> + * Copyright IBM, Corp. 2011
>>>>>> + *
>>>>>> + * Authors:
>>>>>> + *  Anthony Liguori<aliguori@us.ibm.com>
>>>>>> + *
>>>>>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>>>>>> + * See the COPYING.LIB file in the top-level directory.
>>>>>> + *
>>>>>> + */
>>>>>> +
>>>>>> +#include "qmp-input-visitor.h"
>>>>>> +#include "qemu-queue.h"
>>>>>> +#include "qemu-common.h"
>>>>>> +#include "qemu-objects.h"
>>>>>> +#include "qerror.h"
>>>>>> +
>>>>>> +#define QIV_STACK_SIZE 1024
>>>>>> +
>>>>>> +typedef struct StackObject
>>>>>> +{
>>>>>> +    const QObject *obj;
>>>>>> +    const  QListEntry *entry;
>>>>>> +} StackObject;
>>>>>> +
>>>>>> +struct QmpInputVisitor
>>>>>> +{
>>>>>> +    Visitor visitor;
>>>>>> +    const QObject *obj;
>>>>>> +    StackObject stack[QIV_STACK_SIZE];
>>>>>> +    int nb_stack;
>>>>>> +};
>>>>>> +
>>>>>> +static QmpInputVisitor *to_qiv(Visitor *v)
>>>>>> +{
>>>>>> +    return container_of(v, QmpInputVisitor, visitor);
>>>>>> +}
>>>>>> +
>>>>>> +static const QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name)
>>>>>> +{
>>>>>> +    const QObject *qobj;
>>>>>> +
>>>>>> +    if (qiv->nb_stack == 0) {
>>>>>> +        qobj = qiv->obj;
>>>>>> +    } else {
>>>>>> +        qobj = qiv->stack[qiv->nb_stack - 1].obj;
>>>>>> +    }
>>>>>> +
>>>>>> +    if (name&&    qobject_type(qobj) == QTYPE_QDICT) {
>>>>>> +        return qdict_get(qobject_to_qdict(qobj), name);
>>>>>> +    } else if (qiv->nb_stack>    0&&    qobject_type(qobj) == QTYPE_QLIST) {
>>>>>> +        return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
>>>>>> +    }
>>>>>> +
>>>>>> +    return qobj;
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
>>>>>> +{
>>>>>> +    qiv->stack[qiv->nb_stack].obj = obj;
>>>>>> +    if (qobject_type(obj) == QTYPE_QLIST) {
>>>>>> +        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
>>>>>> +    }
>>>>>> +    qiv->nb_stack++;
>>>>>> +
>>>>>> +    if (qiv->nb_stack>= QIV_STACK_SIZE) {
>>>>>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>>>>>> +        return;
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
>>>>>> +{
>>>>>> +    qiv->nb_stack--;
>>>>>> +    if (qiv->nb_stack<    0) {
>>>>>> +        error_set(errp, QERR_BUFFER_OVERRUN);
>>>>>> +        return;
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
>>>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict");
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    qmp_input_push(qiv, qobj, errp);
>>>>>> +    if (error_is_set(errp)) {
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    if (obj) {
>>>>>> +        *obj = qemu_mallocz(size);
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_end_struct(Visitor *v, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +
>>>>>> +    qmp_input_pop(qiv, errp);
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
>>>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list");
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    qmp_input_push(qiv, qobj, errp);
>>>>>> +}
>>>>>> +
>>>>>> +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    GenericList *entry;
>>>>>> +    StackObject *so =&qiv->stack[qiv->nb_stack - 1];
>>>>>> +
>>>>>> +    if (so->entry == NULL) {
>>>>>> +        return NULL;
>>>>>> +    }
>>>>>> +
>>>>>> +    entry = qemu_mallocz(sizeof(*entry));
>>>>>> +    if (*list) {
>>>>>> +        so->entry = qlist_next(so->entry);
>>>>>> +        if (so->entry == NULL) {
>>>>>> +            qemu_free(entry);
>>>>>> +            return NULL;
>>>>>> +        }
>>>>>> +        (*list)->next = entry;
>>>>>> +    }
>>>>>> +    *list = entry;
>>>>>> +
>>>>>> +
>>>>>> +    return entry;
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_end_list(Visitor *v, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +
>>>>>> +    qmp_input_pop(qiv, errp);
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
>>>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer");
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    *obj = qint_get_int(qobject_to_qint(qobj));
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
>>>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean");
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
>>>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string");
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_type_number(Visitor *v, double *obj, const char *name, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
>>>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "double");
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_type_enum(Visitor *v, int *obj, const char *kind, const char *name, Error **errp)
>>>>>> +{
>>>>>> +    int64_t value;
>>>>>> +    qmp_input_type_int(v,&value, name, errp);
>>>>>> +    *obj = value;
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_start_optional(Visitor *v, bool *present,
>>>>>> +                                     const char *name, Error **errp)
>>>>>> +{
>>>>>> +    QmpInputVisitor *qiv = to_qiv(v);
>>>>>> +    const QObject *qobj = qmp_input_get_object(qiv, name);
>>>>>> +
>>>>>> +    if (!qobj) {
>>>>>> +        *present = false;
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    *present = true;
>>>>>> +}
>>>>>> +
>>>>>> +static void qmp_input_end_optional(Visitor *v, Error **errp)
>>>>>> +{
>>>>>> +}
>>>>>> +
>>>>>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
>>>>>> +{
>>>>>> +    return&v->visitor;
>>>>>> +}
>>>>>> +
>>>>>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v)
>>>>>> +{
>>>>>
>>>>> We talked about doing a qobject_incref(v->obj) in qmp_input_visitor_new() and
>>>>> decrefing here.
>>>>>
>>>>
>>>> I think it was either that, or just making the QObject arg to
>>>> qmp_input_visitor_new() const, to make it clear it was caller-freed.
>>>
>>> No, because (at least theoretically) a client could free it before walking
>>> the struct with the visitor functions. The rule is: if you store it, you
>>> have to increment its reference or get its ownership.
>>>
>>>
>>
>> Makes sense. Sucks to have to remove the const for that though...would a
>> temporary cast to non-const be acceptable in a case like this?
>
> Well, if we have to change it, it's not const anymore :)
>

Heh, yah, silly question. Though from a documentation/api perspective, 
const also helps in terms of making it clear that the dict entries are 
read-only... but not to the point of violating the semantics of const i 
suppose. Only other thing we could do is store a copy instead, but 
that's probably unnecessarily costly, particularly with guest-file-write

>>
>>>>
>>>>>> +    qemu_free(v);
>>>>>> +}
>>>>>> +
>>>>>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj)
>>>>>> +{
>>>>>> +    QmpInputVisitor *v;
>>>>>> +
>>>>>> +    v = qemu_mallocz(sizeof(*v));
>>>>>> +
>>>>>> +    v->visitor.start_struct = qmp_input_start_struct;
>>>>>> +    v->visitor.end_struct = qmp_input_end_struct;
>>>>>> +    v->visitor.start_list = qmp_input_start_list;
>>>>>> +    v->visitor.next_list = qmp_input_next_list;
>>>>>> +    v->visitor.end_list = qmp_input_end_list;
>>>>>> +    v->visitor.type_enum = qmp_input_type_enum;
>>>>>> +    v->visitor.type_int = qmp_input_type_int;
>>>>>> +    v->visitor.type_bool = qmp_input_type_bool;
>>>>>> +    v->visitor.type_str = qmp_input_type_str;
>>>>>> +    v->visitor.type_number = qmp_input_type_number;
>>>>>> +    v->visitor.start_optional = qmp_input_start_optional;
>>>>>> +    v->visitor.end_optional = qmp_input_end_optional;
>>>>>> +
>>>>>> +    v->obj = obj;
>>>>>> +
>>>>>> +    return v;
>>>>>> +}
>>>>>> diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
>>>>>> new file mode 100644
>>>>>> index 0000000..0f77916
>>>>>> --- /dev/null
>>>>>> +++ b/qapi/qmp-input-visitor.h
>>>>>> @@ -0,0 +1,27 @@
>>>>>> +/*
>>>>>> + * Input Visitor
>>>>>> + *
>>>>>> + * Copyright IBM, Corp. 2011
>>>>>> + *
>>>>>> + * Authors:
>>>>>> + *  Anthony Liguori<aliguori@us.ibm.com>
>>>>>> + *
>>>>>> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
>>>>>> + * See the COPYING.LIB file in the top-level directory.
>>>>>> + *
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef QMP_INPUT_VISITOR_H
>>>>>> +#define QMP_INPUT_VISITOR_H
>>>>>> +
>>>>>> +#include "qapi-visit-core.h"
>>>>>> +#include "qobject.h"
>>>>>> +
>>>>>> +typedef struct QmpInputVisitor QmpInputVisitor;
>>>>>> +
>>>>>> +QmpInputVisitor *qmp_input_visitor_new(const QObject *obj);
>>>>>> +void qmp_input_visitor_cleanup(QmpInputVisitor *v);
>>>>>> +
>>>>>> +Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
>>>>>> +
>>>>>> +#endif
>>>>>> diff --git a/qerror.h b/qerror.h
>>>>>> index 16c830d..9a9fa5b 100644
>>>>>> --- a/qerror.h
>>>>>> +++ b/qerror.h
>>>>>> @@ -124,6 +124,9 @@ QError *qobject_to_qerror(const QObject *obj);
>>>>>>     #define QERR_JSON_PARSE_ERROR \
>>>>>>         "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
>>>>>>
>>>>>> +#define QERR_BUFFER_OVERRUN \
>>>>>> +    "{ 'class': 'BufferOverrun', 'data': {} }"
>>>>>> +
>>>>>
>>>>> You also have to add an entry in qerror.c. I slightly prefer NotEnoughMemory,
>>>>> but BufferOverrrun is probably fine.
>>>>>
>>>>>>     #define QERR_KVM_MISSING_CAP \
>>>>>>         "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
>>>>>>
>>>>>
>>>>
>>>
>>
>

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

end of thread, other threads:[~2011-07-12 14:15 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-05 13:02 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 01/18] Add hard build dependency on glib Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 02/18] qlist: add qlist_first()/qlist_next() Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 03/18] qapi: add module init types for qapi Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 04/18] qapi: add QAPI visitor core Michael Roth
2011-07-07 14:32   ` Luiz Capitulino
2011-07-07 14:40     ` Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 05/18] qapi: add QMP input visitor Michael Roth
2011-07-07 14:32   ` Luiz Capitulino
2011-07-07 14:45     ` Michael Roth
2011-07-12  0:05     ` Michael Roth
2011-07-12 13:16       ` Luiz Capitulino
2011-07-12 13:46         ` Michael Roth
2011-07-12 13:53           ` Luiz Capitulino
2011-07-12 14:14             ` Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 06/18] qapi: add QMP output visitor Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 07/18] qapi: add QAPI dealloc visitor Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 08/18] qapi: add QMP command registration/lookup functions Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 09/18] qapi: add QMP dispatch functions Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 10/18] qapi: add ordereddict.py helper library Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 11/18] qapi: add qapi.py helper libraries Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 12/18] qapi: add qapi-types.py code generator Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 13/18] qapi: add qapi-visit.py " Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 14/18] qapi: add qapi-commands.py " Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 15/18] qapi: test schema used for unit tests Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 16/18] qapi: add test-visitor, tests for gen. visitor code Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 17/18] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
2011-07-05 13:02 ` [Qemu-devel] [PATCH v5 18/18] qapi: add QAPI code generation documentation Michael Roth
2011-07-07 14:37 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v5 Luiz Capitulino
2011-07-07 15:02   ` Michael Roth

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.