All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2
@ 2011-06-03 22:32 Michael Roth
  2011-06-03 22:32 ` [Qemu-devel] [PATCH v2][ 01/21] Add hard build dependency on glib Michael Roth
                   ` (21 more replies)
  0 siblings, 22 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:32 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 qapi-backport-set1-v1, and can also be obtained
from:
git://repo.or.cz/qemu/mdroth.git qapi-backport-set2-v2

(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 Visiter/dispatch infrastructure to handle
   marshaling/unmarshaling/dispatch between QAPI and the QMP/QGA wire protocols.

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

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                    |   22 ++
 Makefile.objs               |    9 +
 Makefile.target             |    1 +
 configure                   |   13 ++
 docs/qapi-code-gen.txt      |  316 +++++++++++++++++++++++++++++
 module.h                    |    2 +
 qapi-schema-test.json       |   16 ++
 qapi/qapi-dealloc-visiter.c |  127 ++++++++++++
 qapi/qapi-dealloc-visiter.h |   26 +++
 qapi/qapi-types-core.h      |   21 ++
 qapi/qapi-visit-core.h      |  187 +++++++++++++++++
 qapi/qmp-core.h             |   43 ++++
 qapi/qmp-dispatch.c         |   73 +++++++
 qapi/qmp-input-visiter.c    |  239 ++++++++++++++++++++++
 qapi/qmp-input-visiter.h    |   26 +++
 qapi/qmp-output-visiter.c   |  180 +++++++++++++++++
 qapi/qmp-output-visiter.h   |   27 +++
 qapi/qmp-registry.c         |   27 +++
 qlist.h                     |   11 +
 scripts/ordereddict.py      |  128 ++++++++++++
 scripts/qapi-commands.py    |  468 +++++++++++++++++++++++++++++++++++++++++++
 scripts/qapi-types.py       |  221 ++++++++++++++++++++
 scripts/qapi-visit.py       |  223 ++++++++++++++++++++
 scripts/qapi.py             |  181 +++++++++++++++++
 test-qmp-commands.c         |  113 +++++++++++
 test-visiter.c              |  214 ++++++++++++++++++++
 26 files changed, 2914 insertions(+), 0 deletions(-)

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

* [Qemu-devel] [PATCH v2][ 01/21] Add hard build dependency on glib
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
@ 2011-06-03 22:32 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 02/21] qlist: add qlist_first()/qlist_next() Michael Roth
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:32 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 d7944c8..cf318c8 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 66ffad4..eb264d9 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -366,3 +366,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 602d50d..1082228 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -204,6 +204,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 a318d37..5a7ec17 100755
--- a/configure
+++ b/configure
@@ -1766,6 +1766,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
+
+##########################################
 # kvm probe
 if test "$kvm" != "no" ; then
     cat > $TMPC <<EOF
@@ -2939,6 +2951,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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 02/21] qlist: add qlist_first()/qlist_next()
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
  2011-06-03 22:32 ` [Qemu-devel] [PATCH v2][ 01/21] Add hard build dependency on glib Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-08 17:50   ` Luiz Capitulino
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 03/21] qapi: add module init types for qapi Michael Roth
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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..cd2d23e 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 QListEntry *qlist_first(QList *qlist)
+{
+    return QTAILQ_FIRST(&qlist->head);
+}
+
+static inline QListEntry *qlist_next(QListEntry *entry)
+{
+    return QTAILQ_NEXT(entry, next);
+}
+
 #endif /* QLIST_H */
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 03/21] qapi: add module init types for qapi
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
  2011-06-03 22:32 ` [Qemu-devel] [PATCH v2][ 01/21] Add hard build dependency on glib Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 02/21] qlist: add qlist_first()/qlist_next() Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 04/21] qapi: add ordereddict/qapi.py helper libraries Michael Roth
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 04/21] qapi: add ordereddict/qapi.py helper libraries
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (2 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 03/21] qapi: add module init types for qapi Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-07 19:04   ` Anthony Liguori
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator Michael Roth
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/ordereddict.py |  128 ++++++++++++++++++++++++++++++++++
 scripts/qapi.py        |  181 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 309 insertions(+), 0 deletions(-)
 create mode 100644 scripts/ordereddict.py
 create mode 100644 scripts/qapi.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
+
diff --git a/scripts/qapi.py b/scripts/qapi.py
new file mode 100644
index 0000000..422b6bd
--- /dev/null
+++ b/scripts/qapi.py
@@ -0,0 +1,181 @@
+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 = ''
+
+    for line in fp:
+        if line.startswith('#') or line == '\n':
+            continue
+
+        if line.startswith(' '):
+            expr += line
+        elif expr:
+            exprs.append(evaluate(expr))
+            expr = line
+        else:
+            expr += line
+
+    if expr:
+        exprs.append(evaluate(expr))
+
+    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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (3 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 04/21] qapi: add ordereddict/qapi.py helper libraries Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-07 19:06   ` Anthony Liguori
  2011-06-09 15:05   ` Luiz Capitulino
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 06/21] qapi: add qapi-visit.py " Michael Roth
                   ` (16 subsequent siblings)
  21 siblings, 2 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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 |  221 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 221 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..15603f3
--- /dev/null
+++ b/scripts/qapi-types.py
@@ -0,0 +1,221 @@
+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)
+{
+    QapiDeallocVisiter *md;
+    Visiter *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visiter_new();
+    v = qapi_dealloc_get_visiter(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visiter_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 */
+
+#include "qapi/qapi-dealloc-visiter.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',             prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+#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'):
+        add_enum(expr['enum'])
+        ret += generate_enum(expr['enum'], expr['data'])
+    elif expr.has_key('union'):
+        add_enum('%sKind' % expr['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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 06/21] qapi: add qapi-visit.py code generator
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (4 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 07/21] qapi: add qapi-commands.py " Michael Roth
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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 |  223 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 223 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..c228709
--- /dev/null
+++ b/scripts/qapi-visit.py
@@ -0,0 +1,223 @@
+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", 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(Visiter *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, 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(Visiter *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(Visiter *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(Visiter *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(Visiter *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(Visiter *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visiter *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(Visiter *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 */
+
+#include "%(header)s"
+''',
+                 header=basename(h_file)))
+
+fdecl.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 07/21] qapi: add qapi-commands.py code generator
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (5 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 06/21] qapi: add qapi-visit.py " Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 08/21] qapi: add qapi-types-core.h Michael Roth
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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 |  468 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 468 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..9d7b132
--- /dev/null
+++ b/scripts/qapi-commands.py
@@ -0,0 +1,468 @@
+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)->%(c_prefix)shas_%(c_name)s, "%(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", 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)->%(c_prefix)s%(c_name)s, "%(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(Visiter *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    visit_start_struct(m, (void **)obj, "%(name)s", name, 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(Visiter *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(Visiter *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(Visiter *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(Visiter *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(Visiter *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visiter *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(Visiter *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_visiter_output_containers_decl(ret_type):
+    ret = ""
+    push_indent()
+    if ret_type:
+        ret += mcgen('''
+QmpOutputVisiter *mo;
+QapiDeallocVisiter *md;
+Visiter *v;
+''')
+    pop_indent()
+
+    return ret
+
+def gen_visiter_input_containers_decl(args):
+    ret = ""
+
+    push_indent()
+    if len(args) > 0:
+        ret += mcgen('''
+QmpInputVisiter *mi;
+QapiDeallocVisiter *md;
+Visiter *v;
+''')
+    pop_indent()
+
+    return ret.rstrip()
+
+def gen_visiter_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_visiter_input_block(args, obj, dealloc=False):
+    ret = ""
+    if len(args) == 0:
+        return ret
+
+    push_indent()
+
+    if dealloc:
+        ret += mcgen('''
+md = qapi_dealloc_visiter_new();
+v = qapi_dealloc_get_visiter(md);
+''')
+    else:
+        ret += mcgen('''
+mi = qmp_input_visiter_new(%(obj)s);
+v = qmp_input_get_visiter(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_visiter_cleanup(md);
+''')
+    else:
+        ret += mcgen('''
+/* TODO: add cleanup for input/output visiter objects */
+''')
+    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)
+{
+    QapiDeallocVisiter *md = qapi_dealloc_visiter_new();
+    QmpOutputVisiter *mo = qmp_output_visiter_new();
+    Visiter *v;
+    
+    v = qmp_output_get_visiter(mo);
+    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    if (!error_is_set(errp)) {
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+    v = qapi_dealloc_get_visiter(md);
+    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    qapi_dealloc_visiter_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('''
+%(visiter_input_containers_decl)s
+%(visiter_input_vars_decl)s
+
+%(visiter_input_block)s
+
+''',
+                     visiter_input_containers_decl=gen_visiter_input_containers_decl(args),
+                     visiter_input_vars_decl=gen_visiter_input_vars_decl(args),
+                     visiter_input_block=gen_visiter_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('''
+%(visiter_input_block_cleanup)s
+    return;
+}
+''',
+                 visiter_input_block_cleanup=gen_visiter_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 */
+
+#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 */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-output-visiter.h"
+#include "qapi/qmp-input-visiter.h"
+#include "qapi/qapi-dealloc-visiter.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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 08/21] qapi: add qapi-types-core.h
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (6 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 07/21] qapi: add qapi-commands.py " Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h Michael Roth
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

Base declarations and includes for qapi types generator.

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

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

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

* [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (7 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 08/21] qapi: add qapi-types-core.h Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-09 15:14   ` Luiz Capitulino
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter Michael Roth
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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.

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

diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
new file mode 100644
index 0000000..a5ba016
--- /dev/null
+++ b/qapi/qapi-visit-core.h
@@ -0,0 +1,187 @@
+/*
+ * Core Definitions for QAPI Visiter 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_VISITER_CORE_H
+#define QAPI_VISITER_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 Visiter Visiter;
+
+struct Visiter
+{
+    /* Must be set */
+    void (*start_struct)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
+    void (*end_struct)(Visiter *v, Error **errp);
+
+    void (*start_list)(Visiter *v, const char *name, Error **errp);
+    GenericList *(*next_list)(Visiter *v, GenericList **list, Error **errp);
+    void (*end_list)(Visiter *v, Error **errp);
+
+    void (*type_enum)(Visiter *v, int *obj, const char *kind, const char *name, Error **errp);
+
+    void (*type_int)(Visiter *v, int64_t *obj, const char *name, Error **errp);
+    void (*type_bool)(Visiter *v, bool *obj, const char *name, Error **errp);
+    void (*type_str)(Visiter *v, char **obj, const char *name, Error **errp);
+    void (*type_number)(Visiter *v, double *obj, const char *name, Error **errp);
+
+    /* May be NULL */
+    void (*start_optional)(Visiter *v, bool *present, const char *name, Error **errp);
+    void (*end_optional)(Visiter *v, Error **errp);
+
+    void (*start_handle)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
+    void (*end_handle)(Visiter *v, Error **errp);
+};
+
+static inline void visit_start_handle(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->start_handle) {
+        v->start_handle(v, obj, kind, name, errp);
+    }
+}
+
+static inline void visit_end_handle(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->end_handle) {
+        v->end_handle(v, errp);
+    }
+}
+
+static inline void visit_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->start_struct(v, obj, kind, name, errp);
+}
+
+static inline void visit_end_struct(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->end_struct(v, errp);
+}
+
+static inline void visit_start_list(Visiter *v, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->start_list(v, name, errp);
+}
+
+static inline GenericList *visit_next_list(Visiter *v, GenericList **list, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return 0;
+    }
+
+    return v->next_list(v, list, errp);
+}
+
+static inline void visit_end_list(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->end_list(v, errp);
+}
+
+static inline void visit_start_optional(Visiter *v, bool *present, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->start_optional) {
+        v->start_optional(v, present, name, errp);
+    }
+}
+
+static inline void visit_end_optional(Visiter *v, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (v->end_optional) {
+        v->end_optional(v, errp);
+    }
+}
+
+static inline void visit_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_enum(v, obj, kind, name, errp);
+}
+
+static inline void visit_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_int(v, obj, name, errp);
+}
+
+static inline void visit_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_bool(v, obj, name, errp);
+}
+
+static inline void visit_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_str(v, obj, name, errp);
+}
+
+static inline void visit_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    v->type_number(v, obj, name, errp);
+}
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (8 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-09 15:30   ` Luiz Capitulino
                     ` (2 more replies)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter Michael Roth
                   ` (11 subsequent siblings)
  21 siblings, 3 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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>
---
 qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-input-visiter.h |   26 +++++
 2 files changed, 265 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-input-visiter.c
 create mode 100644 qapi/qmp-input-visiter.h

diff --git a/qapi/qmp-input-visiter.c b/qapi/qmp-input-visiter.c
new file mode 100644
index 0000000..6767e39
--- /dev/null
+++ b/qapi/qmp-input-visiter.c
@@ -0,0 +1,239 @@
+#include "qmp-input-visiter.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+
+#define QAPI_OBJECT_SIZE 512
+
+#define QIV_STACK_SIZE 1024
+
+typedef struct StackObject
+{
+    QObject *obj;
+    QListEntry *entry;
+} StackObject;
+
+struct QmpInputVisiter
+{
+    Visiter visiter;
+    QObject *obj;
+    StackObject stack[QIV_STACK_SIZE];
+    int nb_stack;
+};
+
+static QmpInputVisiter *to_qiv(Visiter *v)
+{
+    return container_of(v, QmpInputVisiter, visiter);
+}
+
+static QObject *qmp_input_get_object(QmpInputVisiter *qiv, const char *name)
+{
+    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(QmpInputVisiter *qiv, QObject *obj)
+{
+    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++;
+
+    assert(qiv->nb_stack < QIV_STACK_SIZE); // FIXME
+}
+
+static void qmp_input_pop(QmpInputVisiter *qiv)
+{
+    qiv->nb_stack--;
+    assert(qiv->nb_stack >= 0); // FIXME
+}
+
+static void qmp_input_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "object");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj);
+
+    if (obj) {
+        *obj = qemu_mallocz(QAPI_OBJECT_SIZE);
+    }
+}
+
+static void qmp_input_end_struct(Visiter *v, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv);
+}
+
+static void qmp_input_start_list(Visiter *v, const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "list");
+        return;
+    }
+
+    qmp_input_push(qiv, qobj);
+}
+
+static GenericList *qmp_input_next_list(Visiter *v, GenericList **list, Error **errp)
+{
+    QmpInputVisiter *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(Visiter *v, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+
+    qmp_input_pop(qiv);
+}
+
+static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "integer");
+        return;
+    }
+
+    *obj = qint_get_int(qobject_to_qint(qobj));
+}
+
+static void qmp_input_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
+        return;
+    }
+
+    *obj = qbool_get_int(qobject_to_qbool(qobj));
+}
+
+static void qmp_input_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
+        return;
+    }
+
+    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
+}
+
+static void qmp_input_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "double");
+        return;
+    }
+
+    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+}
+
+static void qmp_input_type_enum(Visiter *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(Visiter *v, bool *present,
+                                     const char *name, Error **errp)
+{
+    QmpInputVisiter *qiv = to_qiv(v);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+
+    if (!qobj) {
+        *present = false;
+        return;
+    }
+
+    *present = true;
+}
+
+static void qmp_input_end_optional(Visiter *v, Error **errp)
+{
+}
+
+Visiter *qmp_input_get_visiter(QmpInputVisiter *v)
+{
+    return &v->visiter;
+}
+
+QmpInputVisiter *qmp_input_visiter_new(QObject *obj)
+{
+    QmpInputVisiter *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visiter.start_struct = qmp_input_start_struct;
+    v->visiter.end_struct = qmp_input_end_struct;
+    v->visiter.start_list = qmp_input_start_list;
+    v->visiter.next_list = qmp_input_next_list;
+    v->visiter.end_list = qmp_input_end_list;
+    v->visiter.type_enum = qmp_input_type_enum;
+    v->visiter.type_int = qmp_input_type_int;
+    v->visiter.type_bool = qmp_input_type_bool;
+    v->visiter.type_str = qmp_input_type_str;
+    v->visiter.type_number = qmp_input_type_number;
+    v->visiter.start_optional = qmp_input_start_optional;
+    v->visiter.end_optional = qmp_input_end_optional;
+
+    v->obj = obj;
+
+    return v;
+}
diff --git a/qapi/qmp-input-visiter.h b/qapi/qmp-input-visiter.h
new file mode 100644
index 0000000..3e4d06f
--- /dev/null
+++ b/qapi/qmp-input-visiter.h
@@ -0,0 +1,26 @@
+/*
+ * Input Visiter
+ *
+ * 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_VISITER_H
+#define QMP_INPUT_VISITER_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpInputVisiter QmpInputVisiter;
+
+QmpInputVisiter *qmp_input_visiter_new(QObject *obj);
+
+Visiter *qmp_input_get_visiter(QmpInputVisiter *v);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (9 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-09 17:47   ` Luiz Capitulino
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 12/21] qapi: add QAPI dealloc visiter Michael Roth
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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 visiter:
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>
---
 qapi/qmp-output-visiter.c |  180 +++++++++++++++++++++++++++++++++++++++++++++
 qapi/qmp-output-visiter.h |   27 +++++++
 2 files changed, 207 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-output-visiter.c
 create mode 100644 qapi/qmp-output-visiter.h

diff --git a/qapi/qmp-output-visiter.c b/qapi/qmp-output-visiter.c
new file mode 100644
index 0000000..4a7cb36
--- /dev/null
+++ b/qapi/qmp-output-visiter.c
@@ -0,0 +1,180 @@
+#include "qmp-output-visiter.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 QmpOutputVisiter
+{
+    Visiter visiter;
+    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 QmpOutputVisiter *to_qov(Visiter *v)
+{
+    return container_of(v, QmpOutputVisiter, visiter);
+}
+
+static void qmp_output_push_obj(QmpOutputVisiter *qov, QObject *value)
+{
+    QStackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static QObject *qmp_output_pop(QmpOutputVisiter *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(QmpOutputVisiter *qov)
+{
+    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+    return e->value;
+}
+
+static QObject *qmp_output_last(QmpOutputVisiter *qov)
+{
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+    return e->value;
+}
+
+static void qmp_output_add_obj(QmpOutputVisiter *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(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    QmpOutputVisiter *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(Visiter *v, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_start_list(Visiter *v, const char *name, Error **errp)
+{
+    QmpOutputVisiter *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(Visiter *v, GenericList **list, Error **errp)
+{
+    GenericList *retval = *list;
+    *list = retval->next;
+    return retval;
+}
+
+static void qmp_output_end_list(Visiter *v, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
+static void qmp_output_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qint_from_int(*obj));
+}
+
+static void qmp_output_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qbool_from_int(*obj));
+}
+
+static void qmp_output_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qstring_from_str(*obj));
+}
+
+static void qmp_output_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+    QmpOutputVisiter *qov = to_qov(v);
+    qmp_output_add(qov, name, qfloat_from_double(*obj));
+}
+
+static void qmp_output_type_enum(Visiter *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(QmpOutputVisiter *qov)
+{
+    return qmp_output_first(qov);
+}
+
+Visiter *qmp_output_get_visiter(QmpOutputVisiter *v)
+{
+    return &v->visiter;
+}
+
+QmpOutputVisiter *qmp_output_visiter_new(void)
+{
+    QmpOutputVisiter *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visiter.start_struct = qmp_output_start_struct;
+    v->visiter.end_struct = qmp_output_end_struct;
+    v->visiter.start_list = qmp_output_start_list;
+    v->visiter.next_list = qmp_output_next_list;
+    v->visiter.end_list = qmp_output_end_list;
+    v->visiter.type_enum = qmp_output_type_enum;
+    v->visiter.type_int = qmp_output_type_int;
+    v->visiter.type_bool = qmp_output_type_bool;
+    v->visiter.type_str = qmp_output_type_str;
+    v->visiter.type_number = qmp_output_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qmp-output-visiter.h b/qapi/qmp-output-visiter.h
new file mode 100644
index 0000000..b04ab02
--- /dev/null
+++ b/qapi/qmp-output-visiter.h
@@ -0,0 +1,27 @@
+/*
+ * Output Visiter
+ *
+ * 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_VISITER_H
+#define QMP_OUTPUT_VISITER_H
+
+#include "qapi-visit-core.h"
+#include "qobject.h"
+
+typedef struct QmpOutputVisiter QmpOutputVisiter;
+
+QmpOutputVisiter *qmp_output_visiter_new(void);
+
+QObject *qmp_output_get_qobject(QmpOutputVisiter *v);
+Visiter *qmp_output_get_visiter(QmpOutputVisiter *v);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 12/21] qapi: add QAPI dealloc visiter
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (10 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-07 19:07   ` Anthony Liguori
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 13/21] qapi: add command registration/lookup functions Michael Roth
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino

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

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qapi-dealloc-visiter.c |  127 +++++++++++++++++++++++++++++++++++++++++++
 qapi/qapi-dealloc-visiter.h |   26 +++++++++
 2 files changed, 153 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qapi-dealloc-visiter.c
 create mode 100644 qapi/qapi-dealloc-visiter.h

diff --git a/qapi/qapi-dealloc-visiter.c b/qapi/qapi-dealloc-visiter.c
new file mode 100644
index 0000000..fe5e68d
--- /dev/null
+++ b/qapi/qapi-dealloc-visiter.c
@@ -0,0 +1,127 @@
+#include "qapi-dealloc-visiter.h"
+#include "qemu-queue.h"
+#include "qemu-common.h"
+#include "qemu-objects.h"
+
+typedef struct StackEntry
+{
+    void *value;
+    QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QapiDeallocVisiter
+{
+    Visiter visiter;
+    QTAILQ_HEAD(, StackEntry) stack;
+};
+
+static QapiDeallocVisiter *to_qov(Visiter *v)
+{
+    return container_of(v, QapiDeallocVisiter, visiter);
+}
+
+static void qapi_dealloc_push(QapiDeallocVisiter *qov, void *value)
+{
+    StackEntry *e = qemu_mallocz(sizeof(*e));
+
+    e->value = value;
+    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
+}
+
+static void *qapi_dealloc_pop(QapiDeallocVisiter *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(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
+{
+    QapiDeallocVisiter *qov = to_qov(v);
+    qapi_dealloc_push(qov, obj);
+}
+
+static void qapi_dealloc_end_struct(Visiter *v, Error **errp)
+{
+    QapiDeallocVisiter *qov = to_qov(v);
+    void **obj = qapi_dealloc_pop(qov);
+    if (obj && *obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_start_list(Visiter *v, const char *name, Error **errp)
+{
+}
+
+static GenericList *qapi_dealloc_next_list(Visiter *v, GenericList **list, Error **errp)
+{
+    GenericList *retval = *list;
+    if (retval->value) {
+        qemu_free(retval->value);
+    }
+    *list = retval->next;
+    return retval;
+}
+
+static void qapi_dealloc_end_list(Visiter *v, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_str(Visiter *v, char **obj, const char *name, Error **errp)
+{
+    if (obj && *obj) {
+        qemu_free(*obj);
+    }
+}
+
+static void qapi_dealloc_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_number(Visiter *v, double *obj, const char *name, Error **errp)
+{
+}
+
+static void qapi_dealloc_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
+{
+}
+
+Visiter *qapi_dealloc_get_visiter(QapiDeallocVisiter *v)
+{
+    return &v->visiter;
+}
+
+void qapi_dealloc_visiter_cleanup(QapiDeallocVisiter *v)
+{
+    qemu_free(v);
+}
+
+QapiDeallocVisiter *qapi_dealloc_visiter_new(void)
+{
+    QapiDeallocVisiter *v;
+
+    v = qemu_mallocz(sizeof(*v));
+
+    v->visiter.start_struct = qapi_dealloc_start_struct;
+    v->visiter.end_struct = qapi_dealloc_end_struct;
+    v->visiter.start_list = qapi_dealloc_start_list;
+    v->visiter.next_list = qapi_dealloc_next_list;
+    v->visiter.end_list = qapi_dealloc_end_list;
+    v->visiter.type_enum = qapi_dealloc_type_enum;
+    v->visiter.type_int = qapi_dealloc_type_int;
+    v->visiter.type_bool = qapi_dealloc_type_bool;
+    v->visiter.type_str = qapi_dealloc_type_str;
+    v->visiter.type_number = qapi_dealloc_type_number;
+
+    QTAILQ_INIT(&v->stack);
+
+    return v;
+}
diff --git a/qapi/qapi-dealloc-visiter.h b/qapi/qapi-dealloc-visiter.h
new file mode 100644
index 0000000..9192fc8
--- /dev/null
+++ b/qapi/qapi-dealloc-visiter.h
@@ -0,0 +1,26 @@
+/*
+ * Dealloc Visiter
+ *
+ * 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_VISITER_H
+#define QAPI_DEALLOC_VISITER_H
+
+#include "qapi-visit-core.h"
+
+typedef struct QapiDeallocVisiter QapiDeallocVisiter;
+
+QapiDeallocVisiter *qapi_dealloc_visiter_new(void);
+void qapi_dealloc_visiter_cleanup(QapiDeallocVisiter *d);
+
+Visiter *qapi_dealloc_get_visiter(QapiDeallocVisiter *v);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 13/21] qapi: add command registration/lookup functions
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (11 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 12/21] qapi: add QAPI dealloc visiter Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 14/21] qapi: add QMP dispatch functions Michael Roth
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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>
---
 qapi/qmp-registry.c |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-registry.c

diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
new file mode 100644
index 0000000..f870244
--- /dev/null
+++ b/qapi/qmp-registry.c
@@ -0,0 +1,27 @@
+#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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 14/21] qapi: add QMP dispatch functions
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (12 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 13/21] qapi: add command registration/lookup functions Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 15/21] qapi: add base declaration/types for QMP Michael Roth
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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>
---
 qapi/qmp-dispatch.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 73 insertions(+), 0 deletions(-)
 create mode 100644 qapi/qmp-dispatch.c

diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
new file mode 100644
index 0000000..e70af7d
--- /dev/null
+++ b/qapi/qmp-dispatch.c
@@ -0,0 +1,73 @@
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "json-parser.h"
+
+static QObject *qmp_dispatch_err(QObject *request, Error **errp)
+{
+    const char *command;
+    QDict *args, *dict;
+    QmpCommand *cmd;
+    QObject *ret = NULL;
+
+    if (qobject_type(request) != QTYPE_QDICT) {
+        error_set(errp, QERR_JSON_PARSE_ERROR, "request is not a dictionary");
+        goto out;
+    }
+
+    dict = qobject_to_qdict(request);
+    if (!qdict_haskey(dict, "execute")) {
+        error_set(errp, QERR_JSON_PARSE_ERROR, "no execute key");
+        goto out;
+    }
+
+    command = qdict_get_str(dict, "execute");
+    cmd = qmp_find_command(command);
+    if (cmd == NULL) {
+        error_set(errp, QERR_COMMAND_NOT_FOUND, command);
+        goto out;
+    }
+
+    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 (ret == NULL) {
+            ret = QOBJECT(qdict_new());
+        }
+        break;
+    }
+
+    QDECREF(args);
+
+out:
+
+    return ret;
+}
+
+QObject *qmp_dispatch(QObject *request)
+{
+    Error *err = NULL;
+    QObject *ret;
+    QDict *rsp;
+
+    ret = qmp_dispatch_err(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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 15/21] qapi: add base declaration/types for QMP
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (13 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 14/21] qapi: add QMP dispatch functions Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 16/21] qapi: test schema used for unit tests Michael Roth
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


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

diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
new file mode 100644
index 0000000..34b2e6a
--- /dev/null
+++ b/qapi/qmp-core.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "monitor.h"
+#include "error_int.h"
+#include "qapi/qapi-types-core.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);
+
+QObject *qmp_dispatch(QObject *request);
+void qmp_proxy_dispatch(const char *name, QDict *args, Error **errp);
+
+#endif
+
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 16/21] qapi: test schema used for unit tests
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (14 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 15/21] qapi: add base declaration/types for QMP Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 17/21] qapi: add test-visiter, tests for gen. visiter code Michael Roth
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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 |   16 ++++++++++++++++
 1 files changed, 16 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..3c8d56b
--- /dev/null
+++ b/qapi-schema-test.json
@@ -0,0 +1,16 @@
+# *-*- Mode: Python -*-*
+
+# 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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 17/21] qapi: add test-visiter, tests for gen. visiter code
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (15 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 16/21] qapi: test schema used for unit tests Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-07 19:08   ` Anthony Liguori
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter Michael Roth
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


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

diff --git a/test-visiter.c b/test-visiter.c
new file mode 100644
index 0000000..31596a0
--- /dev/null
+++ b/test-visiter.c
@@ -0,0 +1,214 @@
+#include <glib.h>
+#include "qapi/qmp-output-visiter.h"
+#include "qapi/qmp-input-visiter.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(Visiter *v, TestStruct **obj, const char *name, Error **errp)
+{
+    visit_start_struct(v, (void **)obj, "TestStruct", name, 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(Visiter *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 deep nesting with refs to other user-defined types */
+static void test_nested_structs(void)
+{
+    QmpOutputVisiter *mo;
+    QmpInputVisiter *mi;
+    Visiter *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_visiter_new();
+    v = qmp_output_get_visiter(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_visiter_new();
+    v = qmp_output_get_visiter(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_visiter_new(obj);
+    v = qmp_input_get_visiter(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);
+}
+
+int main(int argc, char **argv)
+{
+    QmpOutputVisiter *mo;
+    QmpInputVisiter *mi;
+    Visiter *v;
+    TestStruct ts = { 42, 82 };
+    TestStruct *pts = &ts;
+    TestStructList *lts = NULL;
+    Error *err = NULL;
+    QObject *obj;
+    QString *str;
+
+    g_test_init(&argc, &argv, NULL);
+
+    mo = qmp_output_visiter_new();
+    v = qmp_output_get_visiter(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_visiter_new(obj);
+    v = qmp_input_get_visiter(mi);
+
+    int64_t value = 0;
+
+    visit_type_int(v, &value, NULL, &err);
+    if (err) {
+        printf("%s\n", error_get_pretty(err));
+        return 1;
+    }
+
+    g_assert(value == 0x42);
+
+    qobject_decref(obj);
+
+    obj = qobject_from_json("{'x': 42, 'y': 84}");
+    mi = qmp_input_visiter_new(obj);
+    v = qmp_input_get_visiter(mi);
+
+    pts = NULL;
+
+    visit_type_TestStruct(v, &pts, NULL, &err);
+    if (err) {
+        printf("%s\n", error_get_pretty(err));
+        return 1;
+    }
+
+    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_visiter_new(obj);
+    v = qmp_input_get_visiter(mi);
+
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        printf("%s\n", error_get_pretty(err));
+        return 1;
+    }
+
+    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);
+
+    g_test_add_func("/0.15/nested_structs", test_nested_structs);
+
+    g_test_run();
+
+    return 0;
+}
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (16 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 17/21] qapi: add test-visiter, tests for gen. visiter code Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-08 17:39   ` Luiz Capitulino
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile      |   14 ++++++++++++++
 Makefile.objs |    7 +++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index cf318c8..7176176 100644
--- a/Makefile
+++ b/Makefile
@@ -145,6 +145,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-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
+test-visiter: test-visiter.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:
@@ -157,6 +170,7 @@ clean:
 	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; \
diff --git a/Makefile.objs b/Makefile.objs
index eb264d9..9b77d10 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
+qapi-nested-y += qmp-registry.o qmp-dispatch.o
+qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
+
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (17 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 20/21] qapi: Makefile changes to build test-qmp-commands Michael Roth
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Jes.Sorensen, agl, mdroth, lcapitulino


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

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] 52+ messages in thread

* [Qemu-devel] [PATCH v2][ 20/21] qapi: Makefile changes to build test-qmp-commands
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (18 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 21/21] qapi: add QAPI code generation documentation Michael Roth
  2011-06-08 16:43 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Luiz Capitulino
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/Makefile b/Makefile
index 7176176..944e85e 100644
--- a/Makefile
+++ b/Makefile
@@ -146,7 +146,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-visiter.o: QEMU_CFLAGS += -I $(qapi-dir)
+$(qapi-obj-y) test-visiter.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
@@ -154,10 +154,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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
 test-visiter: test-visiter.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:
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH v2][ 21/21] qapi: add QAPI code generation documentation
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (19 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 20/21] qapi: Makefile changes to build test-qmp-commands Michael Roth
@ 2011-06-03 22:33 ` Michael Roth
  2011-06-08 16:43 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Luiz Capitulino
  21 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-03 22:33 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..35ab9ef
--- /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-visiter.h"
+    #include "example-qapi-types.h"
+    #include "example-qapi-visit.h"
+
+    void qapi_free_UserDefOne(UserDefOne * obj)
+    {
+        QapiDeallocVisiter *md;
+        Visiter *v;
+
+        if (!obj) {
+            return;
+        }
+
+        md = qapi_dealloc_visiter_new();
+        v = qapi_dealloc_get_visiter(md);
+        visit_type_UserDefOne(v, &obj, NULL, NULL);
+        qapi_dealloc_visiter_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 visiter 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 visiter function used to dealloc a complex
+schema-defined C type.
+
+The following files are generated:
+
+$(prefix)qapi-visit.c: visiter 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 visiter
+                       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(Visiter *m, UserDefOne ** obj, const char *name, Error **errp)
+    {
+        visit_start_struct(m, (void **)obj, "UserDefOne", name, 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(Visiter *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(Visiter *m, UserDefOne ** obj, const char *name, Error **errp);
+    void visit_type_UserDefOneList(Visiter *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
+                        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.
+
+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-visiter.h"
+    #include "qapi/qmp-input-visiter.h"
+    #include "qapi/qapi-dealloc-visiter.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)
+    {
+        QapiDeallocVisiter *md = qapi_dealloc_visiter_new();
+        QmpOutputVisiter *mo = qmp_output_visiter_new();
+        Visiter *v;
+        
+        v = qmp_output_get_visiter(mo);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        v = qapi_dealloc_get_visiter(md);
+        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        qapi_dealloc_visiter_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;
+        QmpInputVisiter *mi;
+        QapiDeallocVisiter *md;
+        Visiter *v;
+        UserDefOne * arg1 = NULL;
+    
+        mi = qmp_input_visiter_new(QOBJECT(args));
+        v = qmp_input_get_visiter(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_visiter_new();
+        v = qapi_dealloc_get_visiter(md);
+        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+        qapi_dealloc_visiter_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] 52+ messages in thread

* Re: [Qemu-devel] [PATCH v2][ 04/21] qapi: add ordereddict/qapi.py helper libraries
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 04/21] qapi: add ordereddict/qapi.py helper libraries Michael Roth
@ 2011-06-07 19:04   ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-07 19:04 UTC (permalink / raw)
  To: Michael Roth; +Cc: Jes.Sorensen, agl, qemu-devel, lcapitulino

On 06/03/2011 05:33 PM, Michael Roth wrote:
> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> ---
>   scripts/ordereddict.py |  128 ++++++++++++++++++++++++++++++++++
>   scripts/qapi.py        |  181 ++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 309 insertions(+), 0 deletions(-)
>   create mode 100644 scripts/ordereddict.py
>   create mode 100644 scripts/qapi.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

Please make ordereddict.py a separate patch since this is external code.

> diff --git a/scripts/qapi.py b/scripts/qapi.py
> new file mode 100644
> index 0000000..422b6bd
> --- /dev/null
> +++ b/scripts/qapi.py
> @@ -0,0 +1,181 @@

Can you add a copyright/license to this?  GPLv2.

Regards,

Anthony Liguori

> +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 = ''
> +
> +    for line in fp:
> +        if line.startswith('#') or line == '\n':
> +            continue
> +
> +        if line.startswith(' '):
> +            expr += line
> +        elif expr:
> +            exprs.append(evaluate(expr))
> +            expr = line
> +        else:
> +            expr += line
> +
> +    if expr:
> +        exprs.append(evaluate(expr))
> +
> +    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()

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

* Re: [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator Michael Roth
@ 2011-06-07 19:06   ` Anthony Liguori
  2011-06-07 19:12     ` Luiz Capitulino
  2011-06-09  7:00     ` Markus Armbruster
  2011-06-09 15:05   ` Luiz Capitulino
  1 sibling, 2 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-07 19:06 UTC (permalink / raw)
  To: Michael Roth; +Cc: Jes.Sorensen, agl, qemu-devel, lcapitulino

On 06/03/2011 05:33 PM, Michael Roth wrote:
> 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 |  221 +++++++++++++++++++++++++++++++++++++++++++++++++
>   1 files changed, 221 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..15603f3
> --- /dev/null
> +++ b/scripts/qapi-types.py

Other than copyright, I think this is ready to go.

Haven't seen much comments about this series.  I think we're at the 
speak now or forever hold your peace moment, so if you've got concerns 
about this approach, please speak up.

Regards,

Anthony Liguori

> @@ -0,0 +1,221 @@
> +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)
> +{
> +    QapiDeallocVisiter *md;
> +    Visiter *v;
> +
> +    if (!obj) {
> +        return;
> +    }
> +
> +    md = qapi_dealloc_visiter_new();
> +    v = qapi_dealloc_get_visiter(md);
> +    visit_type_%(type)s(v,&obj, NULL, NULL);
> +    qapi_dealloc_visiter_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 */
> +
> +#include "qapi/qapi-dealloc-visiter.h"
> +#include "%(prefix)sqapi-types.h"
> +#include "%(prefix)sqapi-visit.h"
> +
> +''',             prefix=prefix))
> +
> +fdecl.write(mcgen('''
> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +#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'):
> +        add_enum(expr['enum'])
> +        ret += generate_enum(expr['enum'], expr['data'])
> +    elif expr.has_key('union'):
> +        add_enum('%sKind' % expr['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()

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

* Re: [Qemu-devel] [PATCH v2][ 12/21] qapi: add QAPI dealloc visiter
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 12/21] qapi: add QAPI dealloc visiter Michael Roth
@ 2011-06-07 19:07   ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-07 19:07 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, lcapitulino, agl, qemu-devel, Jes.Sorensen

On 06/03/2011 05:33 PM, Michael Roth wrote:
> Type of Visiter class that can be passed into a qapi-generated C
> type's visiter function to free() any heap-allocated data types.
>
> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> ---
>   qapi/qapi-dealloc-visiter.c |  127 +++++++++++++++++++++++++++++++++++++++++++
>   qapi/qapi-dealloc-visiter.h |   26 +++++++++
>   2 files changed, 153 insertions(+), 0 deletions(-)
>   create mode 100644 qapi/qapi-dealloc-visiter.c
>   create mode 100644 qapi/qapi-dealloc-visiter.h
>
> diff --git a/qapi/qapi-dealloc-visiter.c b/qapi/qapi-dealloc-visiter.c
> new file mode 100644
> index 0000000..fe5e68d

This turned out really nice.

Regards,

Anthony Liguori

> --- /dev/null
> +++ b/qapi/qapi-dealloc-visiter.c
> @@ -0,0 +1,127 @@
> +#include "qapi-dealloc-visiter.h"
> +#include "qemu-queue.h"
> +#include "qemu-common.h"
> +#include "qemu-objects.h"
> +
> +typedef struct StackEntry
> +{
> +    void *value;
> +    QTAILQ_ENTRY(StackEntry) node;
> +} StackEntry;
> +
> +struct QapiDeallocVisiter
> +{
> +    Visiter visiter;
> +    QTAILQ_HEAD(, StackEntry) stack;
> +};
> +
> +static QapiDeallocVisiter *to_qov(Visiter *v)
> +{
> +    return container_of(v, QapiDeallocVisiter, visiter);
> +}
> +
> +static void qapi_dealloc_push(QapiDeallocVisiter *qov, void *value)
> +{
> +    StackEntry *e = qemu_mallocz(sizeof(*e));
> +
> +    e->value = value;
> +    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
> +}
> +
> +static void *qapi_dealloc_pop(QapiDeallocVisiter *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(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> +    QapiDeallocVisiter *qov = to_qov(v);
> +    qapi_dealloc_push(qov, obj);
> +}
> +
> +static void qapi_dealloc_end_struct(Visiter *v, Error **errp)
> +{
> +    QapiDeallocVisiter *qov = to_qov(v);
> +    void **obj = qapi_dealloc_pop(qov);
> +    if (obj&&  *obj) {
> +        qemu_free(*obj);
> +    }
> +}
> +
> +static void qapi_dealloc_start_list(Visiter *v, const char *name, Error **errp)
> +{
> +}
> +
> +static GenericList *qapi_dealloc_next_list(Visiter *v, GenericList **list, Error **errp)
> +{
> +    GenericList *retval = *list;
> +    if (retval->value) {
> +        qemu_free(retval->value);
> +    }
> +    *list = retval->next;
> +    return retval;
> +}
> +
> +static void qapi_dealloc_end_list(Visiter *v, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_str(Visiter *v, char **obj, const char *name, Error **errp)
> +{
> +    if (obj&&  *obj) {
> +        qemu_free(*obj);
> +    }
> +}
> +
> +static void qapi_dealloc_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_number(Visiter *v, double *obj, const char *name, Error **errp)
> +{
> +}
> +
> +static void qapi_dealloc_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +}
> +
> +Visiter *qapi_dealloc_get_visiter(QapiDeallocVisiter *v)
> +{
> +    return&v->visiter;
> +}
> +
> +void qapi_dealloc_visiter_cleanup(QapiDeallocVisiter *v)
> +{
> +    qemu_free(v);
> +}
> +
> +QapiDeallocVisiter *qapi_dealloc_visiter_new(void)
> +{
> +    QapiDeallocVisiter *v;
> +
> +    v = qemu_mallocz(sizeof(*v));
> +
> +    v->visiter.start_struct = qapi_dealloc_start_struct;
> +    v->visiter.end_struct = qapi_dealloc_end_struct;
> +    v->visiter.start_list = qapi_dealloc_start_list;
> +    v->visiter.next_list = qapi_dealloc_next_list;
> +    v->visiter.end_list = qapi_dealloc_end_list;
> +    v->visiter.type_enum = qapi_dealloc_type_enum;
> +    v->visiter.type_int = qapi_dealloc_type_int;
> +    v->visiter.type_bool = qapi_dealloc_type_bool;
> +    v->visiter.type_str = qapi_dealloc_type_str;
> +    v->visiter.type_number = qapi_dealloc_type_number;
> +
> +    QTAILQ_INIT(&v->stack);
> +
> +    return v;
> +}
> diff --git a/qapi/qapi-dealloc-visiter.h b/qapi/qapi-dealloc-visiter.h
> new file mode 100644
> index 0000000..9192fc8
> --- /dev/null
> +++ b/qapi/qapi-dealloc-visiter.h
> @@ -0,0 +1,26 @@
> +/*
> + * Dealloc Visiter
> + *
> + * 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_VISITER_H
> +#define QAPI_DEALLOC_VISITER_H
> +
> +#include "qapi-visit-core.h"
> +
> +typedef struct QapiDeallocVisiter QapiDeallocVisiter;
> +
> +QapiDeallocVisiter *qapi_dealloc_visiter_new(void);
> +void qapi_dealloc_visiter_cleanup(QapiDeallocVisiter *d);
> +
> +Visiter *qapi_dealloc_get_visiter(QapiDeallocVisiter *v);
> +
> +#endif

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

* Re: [Qemu-devel] [PATCH v2][ 17/21] qapi: add test-visiter, tests for gen. visiter code
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 17/21] qapi: add test-visiter, tests for gen. visiter code Michael Roth
@ 2011-06-07 19:08   ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-07 19:08 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, lcapitulino, agl, qemu-devel, Jes.Sorensen

On 06/03/2011 05:33 PM, Michael Roth wrote:
> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> ---
>   test-visiter.c |  214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 files changed, 214 insertions(+), 0 deletions(-)
>   create mode 100644 test-visiter.c
>
> diff --git a/test-visiter.c b/test-visiter.c
> new file mode 100644
> index 0000000..31596a0
> --- /dev/null
> +++ b/test-visiter.c
> @@ -0,0 +1,214 @@
> +#include<glib.h>
> +#include "qapi/qmp-output-visiter.h"
> +#include "qapi/qmp-input-visiter.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(Visiter *v, TestStruct **obj, const char *name, Error **errp)
> +{
> +    visit_start_struct(v, (void **)obj, "TestStruct", name, 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(Visiter *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 deep nesting with refs to other user-defined types */
> +static void test_nested_structs(void)
> +{
> +    QmpOutputVisiter *mo;
> +    QmpInputVisiter *mi;
> +    Visiter *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_visiter_new();
> +    v = qmp_output_get_visiter(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_visiter_new();
> +    v = qmp_output_get_visiter(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_visiter_new(obj);
> +    v = qmp_input_get_visiter(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);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    QmpOutputVisiter *mo;
> +    QmpInputVisiter *mi;
> +    Visiter *v;
> +    TestStruct ts = { 42, 82 };
> +    TestStruct *pts =&ts;
> +    TestStructList *lts = NULL;
> +    Error *err = NULL;
> +    QObject *obj;
> +    QString *str;
> +
> +    g_test_init(&argc,&argv, NULL);
> +
> +    mo = qmp_output_visiter_new();
> +    v = qmp_output_get_visiter(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_visiter_new(obj);
> +    v = qmp_input_get_visiter(mi);
> +
> +    int64_t value = 0;
> +
> +    visit_type_int(v,&value, NULL,&err);
> +    if (err) {
> +        printf("%s\n", error_get_pretty(err));
> +        return 1;
> +    }
> +
> +    g_assert(value == 0x42);
> +
> +    qobject_decref(obj);
> +
> +    obj = qobject_from_json("{'x': 42, 'y': 84}");
> +    mi = qmp_input_visiter_new(obj);
> +    v = qmp_input_get_visiter(mi);
> +
> +    pts = NULL;
> +
> +    visit_type_TestStruct(v,&pts, NULL,&err);
> +    if (err) {
> +        printf("%s\n", error_get_pretty(err));
> +        return 1;
> +    }
> +
> +    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_visiter_new(obj);
> +    v = qmp_input_get_visiter(mi);
> +
> +    visit_type_TestStructList(v,&lts, NULL,&err);
> +    if (err) {
> +        printf("%s\n", error_get_pretty(err));
> +        return 1;
> +    }
> +
> +    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);

Please stick the above into a function so you can make it a named tested.

Regards,

Anthony Liguori

> +
> +    g_test_add_func("/0.15/nested_structs", test_nested_structs);
> +
> +    g_test_run();
> +
> +    return 0;
> +}

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

* Re: [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-07 19:06   ` Anthony Liguori
@ 2011-06-07 19:12     ` Luiz Capitulino
  2011-06-07 19:54       ` Anthony Liguori
  2011-06-09  7:00     ` Markus Armbruster
  1 sibling, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-07 19:12 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Jes.Sorensen, agl, Michael Roth, qemu-devel

On Tue, 07 Jun 2011 14:06:53 -0500
Anthony Liguori <anthony@codemonkey.ws> wrote:

> On 06/03/2011 05:33 PM, Michael Roth wrote:
> > 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 |  221 +++++++++++++++++++++++++++++++++++++++++++++++++
> >   1 files changed, 221 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..15603f3
> > --- /dev/null
> > +++ b/scripts/qapi-types.py
> 
> Other than copyright, I think this is ready to go.
> 
> Haven't seen much comments about this series.  I think we're at the 
> speak now or forever hold your peace moment, so if you've got concerns 
> about this approach, please speak up.

Haven't started reviewing it yet, hope to start doing it tomorrow.

> 
> Regards,
> 
> Anthony Liguori
> 
> > @@ -0,0 +1,221 @@
> > +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)
> > +{
> > +    QapiDeallocVisiter *md;
> > +    Visiter *v;
> > +
> > +    if (!obj) {
> > +        return;
> > +    }
> > +
> > +    md = qapi_dealloc_visiter_new();
> > +    v = qapi_dealloc_get_visiter(md);
> > +    visit_type_%(type)s(v,&obj, NULL, NULL);
> > +    qapi_dealloc_visiter_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 */
> > +
> > +#include "qapi/qapi-dealloc-visiter.h"
> > +#include "%(prefix)sqapi-types.h"
> > +#include "%(prefix)sqapi-visit.h"
> > +
> > +''',             prefix=prefix))
> > +
> > +fdecl.write(mcgen('''
> > +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> > +#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'):
> > +        add_enum(expr['enum'])
> > +        ret += generate_enum(expr['enum'], expr['data'])
> > +    elif expr.has_key('union'):
> > +        add_enum('%sKind' % expr['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()
> 

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

* Re: [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-07 19:12     ` Luiz Capitulino
@ 2011-06-07 19:54       ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-07 19:54 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: Jes.Sorensen, agl, Michael Roth, qemu-devel

On 06/07/2011 02:12 PM, Luiz Capitulino wrote:
> On Tue, 07 Jun 2011 14:06:53 -0500
> Anthony Liguori<anthony@codemonkey.ws>  wrote:
>
>> On 06/03/2011 05:33 PM, Michael Roth wrote:
>>> 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 |  221 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>    1 files changed, 221 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..15603f3
>>> --- /dev/null
>>> +++ b/scripts/qapi-types.py
>>
>> Other than copyright, I think this is ready to go.
>>
>> Haven't seen much comments about this series.  I think we're at the
>> speak now or forever hold your peace moment, so if you've got concerns
>> about this approach, please speak up.
>
> Haven't started reviewing it yet, hope to start doing it tomorrow.

Okay.  I'll give folks some time to review.

Regards,

Anthony Liguori

>
>>
>> Regards,
>>
>> Anthony Liguori
>>
>>> @@ -0,0 +1,221 @@
>>> +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)
>>> +{
>>> +    QapiDeallocVisiter *md;
>>> +    Visiter *v;
>>> +
>>> +    if (!obj) {
>>> +        return;
>>> +    }
>>> +
>>> +    md = qapi_dealloc_visiter_new();
>>> +    v = qapi_dealloc_get_visiter(md);
>>> +    visit_type_%(type)s(v,&obj, NULL, NULL);
>>> +    qapi_dealloc_visiter_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 */
>>> +
>>> +#include "qapi/qapi-dealloc-visiter.h"
>>> +#include "%(prefix)sqapi-types.h"
>>> +#include "%(prefix)sqapi-visit.h"
>>> +
>>> +''',             prefix=prefix))
>>> +
>>> +fdecl.write(mcgen('''
>>> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
>>> +#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'):
>>> +        add_enum(expr['enum'])
>>> +        ret += generate_enum(expr['enum'], expr['data'])
>>> +    elif expr.has_key('union'):
>>> +        add_enum('%sKind' % expr['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()
>>
>
>

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

* Re: [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2
  2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
                   ` (20 preceding siblings ...)
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 21/21] qapi: add QAPI code generation documentation Michael Roth
@ 2011-06-08 16:43 ` Luiz Capitulino
  2011-06-08 17:03   ` Michael Roth
  21 siblings, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-08 16:43 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:32:58 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

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

I have started taking a look at this series, but it turns out that this is
complex stuff and I'd like to spend time playing with it and testing it
throughly.

I don't oppose merging this as is, as this series doesn't touch current QMP.
So I assume we'll have enough time to fix possible bugs before doing a mass
conversion.

The only problem is that all the patches have my signed off but I haven't
really reviewed them[*], so I'd feel more comfortable if they were removed
before merging (or that you wait for my review).

 * I guess that happened because Michael pulled from my repo and my git am
   hook has the '-s' flag...

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

* Re: [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2
  2011-06-08 16:43 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Luiz Capitulino
@ 2011-06-08 17:03   ` Michael Roth
  2011-06-08 17:59     ` Luiz Capitulino
  0 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-08 17:03 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 06/08/2011 11:43 AM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:32:58 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> This is Set 2/3 of the QAPI+QGA patchsets.
>
> I have started taking a look at this series, but it turns out that this is
> complex stuff and I'd like to spend time playing with it and testing it
> throughly.
>
> I don't oppose merging this as is, as this series doesn't touch current QMP.
> So I assume we'll have enough time to fix possible bugs before doing a mass
> conversion.

Yah, it's fairly well isolated from the rest of qemu. The error and json 
stuff (set1) was the only bit that would have an affect on qemu/qmp 
behavior, and that's been merged.

>
> The only problem is that all the patches have my signed off but I haven't
> really reviewed them[*], so I'd feel more comfortable if they were removed
> before merging (or that you wait for my review).
>
>   * I guess that happened because Michael pulled from my repo and my git am
>     hook has the '-s' flag...

Doh, yah the sign-offs were included in the commits I pulled. Sorry 
about that.

To be clear though, are you referring to patches 1-3 of set1? I don't 
see your sign-off in any patches in this set.

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

* Re: [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter Michael Roth
@ 2011-06-08 17:39   ` Luiz Capitulino
  2011-06-08 17:55     ` Michael Roth
  2011-06-08 18:12     ` Anthony Liguori
  0 siblings, 2 replies; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-08 17:39 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:16 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>

This doesn't build:

~/src/qmp-unstable/build (qapi-review)/ mk test-visiter
  GEN   qapi-generated/test-qapi-types.h
  GEN   qapi-generated/test-qapi-visit.h
  CC    qapi/qmp-input-visiter.o
  CC    qapi/qmp-output-visiter.o
/home/lcapitulino/src/qmp-unstable/qapi/qmp-input-visiter.c:239:1: fatal error: opening dependency file qapi/qmp-input-visiter.d: No such file or directory
compilation terminated.
/home/lcapitulino/src/qmp-unstable/qapi/qmp-output-visiter.c:180:1: fatal error: opening dependency file qapi/qmp-output-visiter.d: No such file or directory
compilation terminated.
make: *** [qapi/qmp-output-visiter.o] Error 1
make: *** Waiting for unfinished jobs....
make: *** [qapi/qmp-input-visiter.o] Error 1
~/src/qmp-unstable/build (qapi-review)/ 

I guess this is happening because all qapi files being added by this series
are not built. A patch adding a C file should also update the relevant
Makefile so tha the c file can be built and tested (if possible).

> ---
>  Makefile      |   14 ++++++++++++++
>  Makefile.objs |    7 +++++++
>  2 files changed, 21 insertions(+), 0 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index cf318c8..7176176 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -145,6 +145,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-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
> +test-visiter: test-visiter.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:
> @@ -157,6 +170,7 @@ clean:
>  	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; \
> diff --git a/Makefile.objs b/Makefile.objs
> index eb264d9..9b77d10 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
> +qapi-nested-y += qmp-registry.o qmp-dispatch.o
> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
> +
>  vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>  
>  vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)

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

* Re: [Qemu-devel] [PATCH v2][ 02/21] qlist: add qlist_first()/qlist_next()
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 02/21] qlist: add qlist_first()/qlist_next() Michael Roth
@ 2011-06-08 17:50   ` Luiz Capitulino
  0 siblings, 0 replies; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-08 17:50 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:00 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> 
> 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..cd2d23e 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 QListEntry *qlist_first(QList *qlist)
> +{
> +    return QTAILQ_FIRST(&qlist->head);
> +}
> +
> +static inline QListEntry *qlist_next(QListEntry *entry)
> +{
> +    return QTAILQ_NEXT(entry, next);
> +}

I'm not sure how the return value (QListEntry) is being used, but the same
interface for qdict returns a const value and users use get functions to
get visible members. The rationale is that QListEntry and QDictEntry
shouldn't be visible to users.

And the input parameter can be const too and would be nice to have
unit-tests...

> +
>  #endif /* QLIST_H */

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

* Re: [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter
  2011-06-08 17:39   ` Luiz Capitulino
@ 2011-06-08 17:55     ` Michael Roth
  2011-06-08 18:00       ` Luiz Capitulino
  2011-06-08 18:12     ` Anthony Liguori
  1 sibling, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-08 17:55 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 06/08/2011 12:39 PM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:33:16 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>
> This doesn't build:
>
> ~/src/qmp-unstable/build (qapi-review)/ mk test-visiter
>    GEN   qapi-generated/test-qapi-types.h
>    GEN   qapi-generated/test-qapi-visit.h
>    CC    qapi/qmp-input-visiter.o
>    CC    qapi/qmp-output-visiter.o
> /home/lcapitulino/src/qmp-unstable/qapi/qmp-input-visiter.c:239:1: fatal error: opening dependency file qapi/qmp-input-visiter.d: No such file or directory
> compilation terminated.
> /home/lcapitulino/src/qmp-unstable/qapi/qmp-output-visiter.c:180:1: fatal error: opening dependency file qapi/qmp-output-visiter.d: No such file or directory
> compilation terminated.
> make: *** [qapi/qmp-output-visiter.o] Error 1
> make: *** Waiting for unfinished jobs....
> make: *** [qapi/qmp-input-visiter.o] Error 1
> ~/src/qmp-unstable/build (qapi-review)/
>
> I guess this is happening because all qapi files being added by this series
> are not built. A patch adding a C file should also update the relevant
> Makefile so tha the c file can be built and tested (if possible).

Hmm, this commit builds for me with `./configure && make clean && make 
test-visiter`.

Is there something different about your build process, like a seperate 
output directory or something?

>
>> ---
>>   Makefile      |   14 ++++++++++++++
>>   Makefile.objs |    7 +++++++
>>   2 files changed, 21 insertions(+), 0 deletions(-)
>>
>> diff --git a/Makefile b/Makefile
>> index cf318c8..7176176 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -145,6 +145,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-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
>> +test-visiter: test-visiter.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:
>> @@ -157,6 +170,7 @@ clean:
>>   	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; \
>> diff --git a/Makefile.objs b/Makefile.objs
>> index eb264d9..9b77d10 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
>> +qapi-nested-y += qmp-registry.o qmp-dispatch.o
>> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>> +
>>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>
>>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>

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

* Re: [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2
  2011-06-08 17:03   ` Michael Roth
@ 2011-06-08 17:59     ` Luiz Capitulino
  0 siblings, 0 replies; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-08 17:59 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Wed, 08 Jun 2011 12:03:04 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 06/08/2011 11:43 AM, Luiz Capitulino wrote:
> > On Fri,  3 Jun 2011 17:32:58 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >> This is Set 2/3 of the QAPI+QGA patchsets.
> >
> > I have started taking a look at this series, but it turns out that this is
> > complex stuff and I'd like to spend time playing with it and testing it
> > throughly.
> >
> > I don't oppose merging this as is, as this series doesn't touch current QMP.
> > So I assume we'll have enough time to fix possible bugs before doing a mass
> > conversion.
> 
> Yah, it's fairly well isolated from the rest of qemu. The error and json 
> stuff (set1) was the only bit that would have an affect on qemu/qmp 
> behavior, and that's been merged.

Yes.

> > The only problem is that all the patches have my signed off but I haven't
> > really reviewed them[*], so I'd feel more comfortable if they were removed
> > before merging (or that you wait for my review).
> >
> >   * I guess that happened because Michael pulled from my repo and my git am
> >     hook has the '-s' flag...
> 
> Doh, yah the sign-offs were included in the commits I pulled. Sorry 
> about that.
> 
> To be clear though, are you referring to patches 1-3 of set1? I don't 
> see your sign-off in any patches in this set.

Doh, you're right. I was looking at my private branch (where I use my
git am alias). There's nothing we can do about set1 anyway. Sorry for the
noise.

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

* Re: [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter
  2011-06-08 17:55     ` Michael Roth
@ 2011-06-08 18:00       ` Luiz Capitulino
  0 siblings, 0 replies; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-08 18:00 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Wed, 08 Jun 2011 12:55:29 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 06/08/2011 12:39 PM, Luiz Capitulino wrote:
> > On Fri,  3 Jun 2011 17:33:16 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >>
> >> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> >
> > This doesn't build:
> >
> > ~/src/qmp-unstable/build (qapi-review)/ mk test-visiter
> >    GEN   qapi-generated/test-qapi-types.h
> >    GEN   qapi-generated/test-qapi-visit.h
> >    CC    qapi/qmp-input-visiter.o
> >    CC    qapi/qmp-output-visiter.o
> > /home/lcapitulino/src/qmp-unstable/qapi/qmp-input-visiter.c:239:1: fatal error: opening dependency file qapi/qmp-input-visiter.d: No such file or directory
> > compilation terminated.
> > /home/lcapitulino/src/qmp-unstable/qapi/qmp-output-visiter.c:180:1: fatal error: opening dependency file qapi/qmp-output-visiter.d: No such file or directory
> > compilation terminated.
> > make: *** [qapi/qmp-output-visiter.o] Error 1
> > make: *** Waiting for unfinished jobs....
> > make: *** [qapi/qmp-input-visiter.o] Error 1
> > ~/src/qmp-unstable/build (qapi-review)/
> >
> > I guess this is happening because all qapi files being added by this series
> > are not built. A patch adding a C file should also update the relevant
> > Makefile so tha the c file can be built and tested (if possible).
> 
> Hmm, this commit builds for me with `./configure && make clean && make 
> test-visiter`.
> 
> Is there something different about your build process, like a seperate 
> output directory or something?

Yes, I use a different build dir.

> 
> >
> >> ---
> >>   Makefile      |   14 ++++++++++++++
> >>   Makefile.objs |    7 +++++++
> >>   2 files changed, 21 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/Makefile b/Makefile
> >> index cf318c8..7176176 100644
> >> --- a/Makefile
> >> +++ b/Makefile
> >> @@ -145,6 +145,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-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
> >> +test-visiter: test-visiter.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:
> >> @@ -157,6 +170,7 @@ clean:
> >>   	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; \
> >> diff --git a/Makefile.objs b/Makefile.objs
> >> index eb264d9..9b77d10 100644
> >> --- a/Makefile.objs
> >> +++ b/Makefile.objs
> >> @@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
> >> +qapi-nested-y += qmp-registry.o qmp-dispatch.o
> >> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
> >> +
> >>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> >>
> >>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
> >
> 

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

* Re: [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter
  2011-06-08 17:39   ` Luiz Capitulino
  2011-06-08 17:55     ` Michael Roth
@ 2011-06-08 18:12     ` Anthony Liguori
  2011-06-08 18:16       ` Luiz Capitulino
  1 sibling, 1 reply; 52+ messages in thread
From: Anthony Liguori @ 2011-06-08 18:12 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, Jes.Sorensen, agl, Michael Roth, qemu-devel

On 06/08/2011 12:39 PM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:33:16 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>
> This doesn't build:
>
> ~/src/qmp-unstable/build (qapi-review)/ mk test-visiter
>    GEN   qapi-generated/test-qapi-types.h
>    GEN   qapi-generated/test-qapi-visit.h
>    CC    qapi/qmp-input-visiter.o
>    CC    qapi/qmp-output-visiter.o
> /home/lcapitulino/src/qmp-unstable/qapi/qmp-input-visiter.c:239:1: fatal error: opening dependency file qapi/qmp-input-visiter.d: No such file or directory
> compilation terminated.
> /home/lcapitulino/src/qmp-unstable/qapi/qmp-output-visiter.c:180:1: fatal error: opening dependency file qapi/qmp-output-visiter.d: No such file or directory
> compilation terminated.

There's a mkdir at the end of configure.  You'll need to add qapi to it.

Regards,

Anthony Liguori

> make: *** [qapi/qmp-output-visiter.o] Error 1
> make: *** Waiting for unfinished jobs....
> make: *** [qapi/qmp-input-visiter.o] Error 1
> ~/src/qmp-unstable/build (qapi-review)/
>
> I guess this is happening because all qapi files being added by this series
> are not built. A patch adding a C file should also update the relevant
> Makefile so tha the c file can be built and tested (if possible).
>
>> ---
>>   Makefile      |   14 ++++++++++++++
>>   Makefile.objs |    7 +++++++
>>   2 files changed, 21 insertions(+), 0 deletions(-)
>>
>> diff --git a/Makefile b/Makefile
>> index cf318c8..7176176 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -145,6 +145,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-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
>> +test-visiter: test-visiter.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:
>> @@ -157,6 +170,7 @@ clean:
>>   	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; \
>> diff --git a/Makefile.objs b/Makefile.objs
>> index eb264d9..9b77d10 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
>> +qapi-nested-y += qmp-registry.o qmp-dispatch.o
>> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
>> +
>>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>
>>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>
>

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

* Re: [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter
  2011-06-08 18:12     ` Anthony Liguori
@ 2011-06-08 18:16       ` Luiz Capitulino
  0 siblings, 0 replies; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-08 18:16 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: aliguori, Jes.Sorensen, agl, Michael Roth, qemu-devel

On Wed, 08 Jun 2011 13:12:50 -0500
Anthony Liguori <anthony@codemonkey.ws> wrote:

> On 06/08/2011 12:39 PM, Luiz Capitulino wrote:
> > On Fri,  3 Jun 2011 17:33:16 -0500
> > Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
> >
> >>
> >> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
> >
> > This doesn't build:
> >
> > ~/src/qmp-unstable/build (qapi-review)/ mk test-visiter
> >    GEN   qapi-generated/test-qapi-types.h
> >    GEN   qapi-generated/test-qapi-visit.h
> >    CC    qapi/qmp-input-visiter.o
> >    CC    qapi/qmp-output-visiter.o
> > /home/lcapitulino/src/qmp-unstable/qapi/qmp-input-visiter.c:239:1: fatal error: opening dependency file qapi/qmp-input-visiter.d: No such file or directory
> > compilation terminated.
> > /home/lcapitulino/src/qmp-unstable/qapi/qmp-output-visiter.c:180:1: fatal error: opening dependency file qapi/qmp-output-visiter.d: No such file or directory
> > compilation terminated.
> 
> There's a mkdir at the end of configure.  You'll need to add qapi to it.

Yeah, that fixed it.

> 
> Regards,
> 
> Anthony Liguori
> 
> > make: *** [qapi/qmp-output-visiter.o] Error 1
> > make: *** Waiting for unfinished jobs....
> > make: *** [qapi/qmp-input-visiter.o] Error 1
> > ~/src/qmp-unstable/build (qapi-review)/
> >
> > I guess this is happening because all qapi files being added by this series
> > are not built. A patch adding a C file should also update the relevant
> > Makefile so tha the c file can be built and tested (if possible).
> >
> >> ---
> >>   Makefile      |   14 ++++++++++++++
> >>   Makefile.objs |    7 +++++++
> >>   2 files changed, 21 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/Makefile b/Makefile
> >> index cf318c8..7176176 100644
> >> --- a/Makefile
> >> +++ b/Makefile
> >> @@ -145,6 +145,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-visiter.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-visiter.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h)
> >> +test-visiter: test-visiter.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:
> >> @@ -157,6 +170,7 @@ clean:
> >>   	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; \
> >> diff --git a/Makefile.objs b/Makefile.objs
> >> index eb264d9..9b77d10 100644
> >> --- a/Makefile.objs
> >> +++ b/Makefile.objs
> >> @@ -362,6 +362,13 @@ 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 = qmp-input-visiter.o qmp-output-visiter.o qapi-dealloc-visiter.o
> >> +qapi-nested-y += qmp-registry.o qmp-dispatch.o
> >> +qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
> >> +
> >>   vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
> >>
> >>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
> >
> >
> 

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

* Re: [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-07 19:06   ` Anthony Liguori
  2011-06-07 19:12     ` Luiz Capitulino
@ 2011-06-09  7:00     ` Markus Armbruster
  1 sibling, 0 replies; 52+ messages in thread
From: Markus Armbruster @ 2011-06-09  7:00 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Jes.Sorensen, lcapitulino, agl, Michael Roth, qemu-devel

Anthony Liguori <anthony@codemonkey.ws> writes:

> On 06/03/2011 05:33 PM, Michael Roth wrote:
>> 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 |  221 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 files changed, 221 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..15603f3
>> --- /dev/null
>> +++ b/scripts/qapi-types.py
>
> Other than copyright, I think this is ready to go.
>
> Haven't seen much comments about this series.  I think we're at the
> speak now or forever hold your peace moment, so if you've got concerns
> about this approach, please speak up.

There's one concern that trumps all the others I may have: QMP needs to
move.  I feel the best I can to for that is to keep out of its way.

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

* Re: [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator Michael Roth
  2011-06-07 19:06   ` Anthony Liguori
@ 2011-06-09 15:05   ` Luiz Capitulino
  2011-06-09 15:28     ` Michael Roth
  1 sibling, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-09 15:05 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:03 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

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

This is generating code that can't be built, because the qapi modules are
being added after the code generator. I think we should do the opposite:
the qapi modules have to be introduced before anything which uses them.

Also note that a patch adding a module should also update the Makefile, so
that the module can be built.

> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  scripts/qapi-types.py |  221 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 221 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..15603f3
> --- /dev/null
> +++ b/scripts/qapi-types.py
> @@ -0,0 +1,221 @@
> +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)
> +{
> +    QapiDeallocVisiter *md;
> +    Visiter *v;
> +
> +    if (!obj) {
> +        return;
> +    }
> +
> +    md = qapi_dealloc_visiter_new();
> +    v = qapi_dealloc_get_visiter(md);
> +    visit_type_%(type)s(v, &obj, NULL, NULL);
> +    qapi_dealloc_visiter_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 */
> +
> +#include "qapi/qapi-dealloc-visiter.h"
> +#include "%(prefix)sqapi-types.h"
> +#include "%(prefix)sqapi-visit.h"
> +
> +''',             prefix=prefix))
> +
> +fdecl.write(mcgen('''
> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +#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'):
> +        add_enum(expr['enum'])
> +        ret += generate_enum(expr['enum'], expr['data'])
> +    elif expr.has_key('union'):
> +        add_enum('%sKind' % expr['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()

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

* Re: [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h Michael Roth
@ 2011-06-09 15:14   ` Luiz Capitulino
  2011-06-09 18:08     ` Anthony Liguori
  0 siblings, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-09 15:14 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:07 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> Base definitions/includes for Visiter interface used by generated
> visiter/marshalling code.
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  qapi/qapi-visit-core.h |  187 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 187 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qapi-visit-core.h
> 
> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
> new file mode 100644
> index 0000000..a5ba016
> --- /dev/null
> +++ b/qapi/qapi-visit-core.h
> @@ -0,0 +1,187 @@
> +/*
> + * Core Definitions for QAPI Visiter 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_VISITER_CORE_H
> +#define QAPI_VISITER_CORE_H
> +
> +#include "qapi/qapi-types-core.h"
> +#include "error.h"
> +#include <stdlib.h>
> +
> +typedef struct GenericList
> +{
> +    void *value;
> +    struct GenericList *next;
> +} GenericList;

If there's a reason to not use our list API, it should be explained in
the commit log.

> +
> +typedef struct Visiter Visiter;
> +
> +struct Visiter
> +{
> +    /* Must be set */
> +    void (*start_struct)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
> +    void (*end_struct)(Visiter *v, Error **errp);
> +
> +    void (*start_list)(Visiter *v, const char *name, Error **errp);
> +    GenericList *(*next_list)(Visiter *v, GenericList **list, Error **errp);
> +    void (*end_list)(Visiter *v, Error **errp);
> +
> +    void (*type_enum)(Visiter *v, int *obj, const char *kind, const char *name, Error **errp);
> +
> +    void (*type_int)(Visiter *v, int64_t *obj, const char *name, Error **errp);
> +    void (*type_bool)(Visiter *v, bool *obj, const char *name, Error **errp);
> +    void (*type_str)(Visiter *v, char **obj, const char *name, Error **errp);
> +    void (*type_number)(Visiter *v, double *obj, const char *name, Error **errp);
> +
> +    /* May be NULL */
> +    void (*start_optional)(Visiter *v, bool *present, const char *name, Error **errp);
> +    void (*end_optional)(Visiter *v, Error **errp);
> +
> +    void (*start_handle)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
> +    void (*end_handle)(Visiter *v, Error **errp);
> +};
> +
> +static inline void visit_start_handle(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (v->start_handle) {
> +        v->start_handle(v, obj, kind, name, errp);
> +    }
> +}

IMO, all these inlines should be real functions and...

> +
> +static inline void visit_end_handle(Visiter *v, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (v->end_handle) {
> +        v->end_handle(v, errp);
> +    }
> +}
> +
> +static inline void visit_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->start_struct(v, obj, kind, name, errp);
> +}

... this could be:

if (!error_is_set(errp)) {
    v->start_struct(v, obj, kind, name, errp);
}

Also valid for other functions in this file.

> +
> +static inline void visit_end_struct(Visiter *v, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->end_struct(v, errp);
> +}
> +
> +static inline void visit_start_list(Visiter *v, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->start_list(v, name, errp);
> +}
> +
> +static inline GenericList *visit_next_list(Visiter *v, GenericList **list, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return 0;
> +    }
> +
> +    return v->next_list(v, list, errp);
> +}
> +
> +static inline void visit_end_list(Visiter *v, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->end_list(v, errp);
> +}
> +
> +static inline void visit_start_optional(Visiter *v, bool *present, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (v->start_optional) {
> +        v->start_optional(v, present, name, errp);
> +    }
> +}
> +
> +static inline void visit_end_optional(Visiter *v, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (v->end_optional) {
> +        v->end_optional(v, errp);
> +    }
> +}
> +
> +static inline void visit_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->type_enum(v, obj, kind, name, errp);
> +}
> +
> +static inline void visit_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->type_int(v, obj, name, errp);
> +}
> +
> +static inline void visit_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->type_bool(v, obj, name, errp);
> +}
> +
> +static inline void visit_type_str(Visiter *v, char **obj, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->type_str(v, obj, name, errp);
> +}
> +
> +static inline void visit_type_number(Visiter *v, double *obj, const char *name, Error **errp)
> +{
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    v->type_number(v, obj, name, errp);
> +}
> +
> +#endif

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

* Re: [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator
  2011-06-09 15:05   ` Luiz Capitulino
@ 2011-06-09 15:28     ` Michael Roth
  0 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-09 15:28 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 06/09/2011 10:05 AM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:33:03 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> 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.
>
> This is generating code that can't be built, because the qapi modules are
> being added after the code generator. I think we should do the opposite:
> the qapi modules have to be introduced before anything which uses them.

Makes sense.

>
> Also note that a patch adding a module should also update the Makefile, so
> that the module can be built.

Ok, I'll try to do this for the re-spin.

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter Michael Roth
@ 2011-06-09 15:30   ` Luiz Capitulino
  2011-06-09 15:41     ` Michael Roth
  2011-06-09 16:26   ` Peter Maydell
  2011-06-13 19:12   ` Luiz Capitulino
  2 siblings, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-09 15:30 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:08 -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>
> ---
>  qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/qmp-input-visiter.h |   26 +++++
>  2 files changed, 265 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qmp-input-visiter.c
>  create mode 100644 qapi/qmp-input-visiter.h
> 
> diff --git a/qapi/qmp-input-visiter.c b/qapi/qmp-input-visiter.c
> new file mode 100644
> index 0000000..6767e39
> --- /dev/null
> +++ b/qapi/qmp-input-visiter.c
> @@ -0,0 +1,239 @@
> +#include "qmp-input-visiter.h"
> +#include "qemu-queue.h"
> +#include "qemu-common.h"
> +#include "qemu-objects.h"
> +#include "qerror.h"
> +
> +#define QAPI_OBJECT_SIZE 512
> +
> +#define QIV_STACK_SIZE 1024
> +
> +typedef struct StackObject
> +{
> +    QObject *obj;
> +    QListEntry *entry;
> +} StackObject;
> +
> +struct QmpInputVisiter
> +{
> +    Visiter visiter;
> +    QObject *obj;
> +    StackObject stack[QIV_STACK_SIZE];
> +    int nb_stack;
> +};
> +
> +static QmpInputVisiter *to_qiv(Visiter *v)
> +{
> +    return container_of(v, QmpInputVisiter, visiter);
> +}
> +
> +static QObject *qmp_input_get_object(QmpInputVisiter *qiv, const char *name)
> +{
> +    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(QmpInputVisiter *qiv, QObject *obj)
> +{
> +    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++;
> +
> +    assert(qiv->nb_stack < QIV_STACK_SIZE); // FIXME

Can't this limit be reached if a client sends a nested object? Why
don't we make it dynamic and/or return an error if a limit is reached?

> +}
> +
> +static void qmp_input_pop(QmpInputVisiter *qiv)
> +{
> +    qiv->nb_stack--;
> +    assert(qiv->nb_stack >= 0); // FIXME
> +}
> +
> +static void qmp_input_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "object");
> +        return;
> +    }
> +
> +    qmp_input_push(qiv, qobj);
> +
> +    if (obj) {
> +        *obj = qemu_mallocz(QAPI_OBJECT_SIZE);

I'm not sure I understand how this is being handled. This is allocating
the struct size, right? What happens if struct size > QAPI_OBJECT_SIZE?

> +    }
> +}
> +
> +static void qmp_input_end_struct(Visiter *v, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +
> +    qmp_input_pop(qiv);
> +}
> +
> +static void qmp_input_start_list(Visiter *v, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "list");
> +        return;
> +    }
> +
> +    qmp_input_push(qiv, qobj);
> +}
> +
> +static GenericList *qmp_input_next_list(Visiter *v, GenericList **list, Error **errp)
> +{
> +    QmpInputVisiter *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(Visiter *v, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +
> +    qmp_input_pop(qiv);
> +}
> +
> +static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "integer");
> +        return;
> +    }
> +
> +    *obj = qint_get_int(qobject_to_qint(qobj));
> +}
> +
> +static void qmp_input_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
> +        return;
> +    }
> +
> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
> +}
> +
> +static void qmp_input_type_str(Visiter *v, char **obj, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
> +        return;
> +    }
> +
> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
> +}
> +
> +static void qmp_input_type_number(Visiter *v, double *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "double");
> +        return;
> +    }
> +
> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
> +}
> +
> +static void qmp_input_type_enum(Visiter *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(Visiter *v, bool *present,
> +                                     const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj) {
> +        *present = false;
> +        return;
> +    }
> +
> +    *present = true;
> +}
> +
> +static void qmp_input_end_optional(Visiter *v, Error **errp)
> +{
> +}
> +
> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v)
> +{
> +    return &v->visiter;
> +}
> +
> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj)
> +{
> +    QmpInputVisiter *v;
> +
> +    v = qemu_mallocz(sizeof(*v));
> +
> +    v->visiter.start_struct = qmp_input_start_struct;
> +    v->visiter.end_struct = qmp_input_end_struct;
> +    v->visiter.start_list = qmp_input_start_list;
> +    v->visiter.next_list = qmp_input_next_list;
> +    v->visiter.end_list = qmp_input_end_list;
> +    v->visiter.type_enum = qmp_input_type_enum;
> +    v->visiter.type_int = qmp_input_type_int;
> +    v->visiter.type_bool = qmp_input_type_bool;
> +    v->visiter.type_str = qmp_input_type_str;
> +    v->visiter.type_number = qmp_input_type_number;
> +    v->visiter.start_optional = qmp_input_start_optional;
> +    v->visiter.end_optional = qmp_input_end_optional;
> +
> +    v->obj = obj;
> +
> +    return v;
> +}
> diff --git a/qapi/qmp-input-visiter.h b/qapi/qmp-input-visiter.h
> new file mode 100644
> index 0000000..3e4d06f
> --- /dev/null
> +++ b/qapi/qmp-input-visiter.h
> @@ -0,0 +1,26 @@
> +/*
> + * Input Visiter
> + *
> + * 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_VISITER_H
> +#define QMP_INPUT_VISITER_H
> +
> +#include "qapi-visit-core.h"
> +#include "qobject.h"
> +
> +typedef struct QmpInputVisiter QmpInputVisiter;
> +
> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj);
> +
> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v);
> +
> +#endif

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-09 15:30   ` Luiz Capitulino
@ 2011-06-09 15:41     ` Michael Roth
  2011-06-09 15:55       ` Luiz Capitulino
  0 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-09 15:41 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 06/09/2011 10:30 AM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:33:08 -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>
>> ---
>>   qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
>>   qapi/qmp-input-visiter.h |   26 +++++
>>   2 files changed, 265 insertions(+), 0 deletions(-)
>>   create mode 100644 qapi/qmp-input-visiter.c
>>   create mode 100644 qapi/qmp-input-visiter.h
>>
>> diff --git a/qapi/qmp-input-visiter.c b/qapi/qmp-input-visiter.c
>> new file mode 100644
>> index 0000000..6767e39
>> --- /dev/null
>> +++ b/qapi/qmp-input-visiter.c
>> @@ -0,0 +1,239 @@
>> +#include "qmp-input-visiter.h"
>> +#include "qemu-queue.h"
>> +#include "qemu-common.h"
>> +#include "qemu-objects.h"
>> +#include "qerror.h"
>> +
>> +#define QAPI_OBJECT_SIZE 512
>> +
>> +#define QIV_STACK_SIZE 1024
>> +
>> +typedef struct StackObject
>> +{
>> +    QObject *obj;
>> +    QListEntry *entry;
>> +} StackObject;
>> +
>> +struct QmpInputVisiter
>> +{
>> +    Visiter visiter;
>> +    QObject *obj;
>> +    StackObject stack[QIV_STACK_SIZE];
>> +    int nb_stack;
>> +};
>> +
>> +static QmpInputVisiter *to_qiv(Visiter *v)
>> +{
>> +    return container_of(v, QmpInputVisiter, visiter);
>> +}
>> +
>> +static QObject *qmp_input_get_object(QmpInputVisiter *qiv, const char *name)
>> +{
>> +    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(QmpInputVisiter *qiv, QObject *obj)
>> +{
>> +    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++;
>> +
>> +    assert(qiv->nb_stack<  QIV_STACK_SIZE); // FIXME
>
> Can't this limit be reached if a client sends a nested object? Why
> don't we make it dynamic and/or return an error if a limit is reached?
>

Yup, I think that's what the fixme was for. It's been fixed in my tree, 
just sets an Error and returns instead now.

In reality the token limit added to the json parser with the set1 
patches would catch overrun attempts from the client though, so it's 
just an extra layer of protection.

>> +}
>> +
>> +static void qmp_input_pop(QmpInputVisiter *qiv)
>> +{
>> +    qiv->nb_stack--;
>> +    assert(qiv->nb_stack>= 0); // FIXME
>> +}
>> +
>> +static void qmp_input_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "object");
>> +        return;
>> +    }
>> +
>> +    qmp_input_push(qiv, qobj);
>> +
>> +    if (obj) {
>> +        *obj = qemu_mallocz(QAPI_OBJECT_SIZE);
>
> I'm not sure I understand how this is being handled. This is allocating
> the struct size, right? What happens if struct size>  QAPI_OBJECT_SIZE?
>

Badness :) We'll need to pick a reasonable value and note it in the 
schema documentation.

>> +    }
>> +}
>> +
>> +static void qmp_input_end_struct(Visiter *v, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +
>> +    qmp_input_pop(qiv);
>> +}
>> +
>> +static void qmp_input_start_list(Visiter *v, const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "list");
>> +        return;
>> +    }
>> +
>> +    qmp_input_push(qiv, qobj);
>> +}
>> +
>> +static GenericList *qmp_input_next_list(Visiter *v, GenericList **list, Error **errp)
>> +{
>> +    QmpInputVisiter *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(Visiter *v, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +
>> +    qmp_input_pop(qiv);
>> +}
>> +
>> +static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "integer");
>> +        return;
>> +    }
>> +
>> +    *obj = qint_get_int(qobject_to_qint(qobj));
>> +}
>> +
>> +static void qmp_input_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
>> +        return;
>> +    }
>> +
>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
>> +}
>> +
>> +static void qmp_input_type_str(Visiter *v, char **obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
>> +        return;
>> +    }
>> +
>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
>> +}
>> +
>> +static void qmp_input_type_number(Visiter *v, double *obj, const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "double");
>> +        return;
>> +    }
>> +
>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
>> +}
>> +
>> +static void qmp_input_type_enum(Visiter *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(Visiter *v, bool *present,
>> +                                     const char *name, Error **errp)
>> +{
>> +    QmpInputVisiter *qiv = to_qiv(v);
>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>> +
>> +    if (!qobj) {
>> +        *present = false;
>> +        return;
>> +    }
>> +
>> +    *present = true;
>> +}
>> +
>> +static void qmp_input_end_optional(Visiter *v, Error **errp)
>> +{
>> +}
>> +
>> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v)
>> +{
>> +    return&v->visiter;
>> +}
>> +
>> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj)
>> +{
>> +    QmpInputVisiter *v;
>> +
>> +    v = qemu_mallocz(sizeof(*v));
>> +
>> +    v->visiter.start_struct = qmp_input_start_struct;
>> +    v->visiter.end_struct = qmp_input_end_struct;
>> +    v->visiter.start_list = qmp_input_start_list;
>> +    v->visiter.next_list = qmp_input_next_list;
>> +    v->visiter.end_list = qmp_input_end_list;
>> +    v->visiter.type_enum = qmp_input_type_enum;
>> +    v->visiter.type_int = qmp_input_type_int;
>> +    v->visiter.type_bool = qmp_input_type_bool;
>> +    v->visiter.type_str = qmp_input_type_str;
>> +    v->visiter.type_number = qmp_input_type_number;
>> +    v->visiter.start_optional = qmp_input_start_optional;
>> +    v->visiter.end_optional = qmp_input_end_optional;
>> +
>> +    v->obj = obj;
>> +
>> +    return v;
>> +}
>> diff --git a/qapi/qmp-input-visiter.h b/qapi/qmp-input-visiter.h
>> new file mode 100644
>> index 0000000..3e4d06f
>> --- /dev/null
>> +++ b/qapi/qmp-input-visiter.h
>> @@ -0,0 +1,26 @@
>> +/*
>> + * Input Visiter
>> + *
>> + * 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_VISITER_H
>> +#define QMP_INPUT_VISITER_H
>> +
>> +#include "qapi-visit-core.h"
>> +#include "qobject.h"
>> +
>> +typedef struct QmpInputVisiter QmpInputVisiter;
>> +
>> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj);
>> +
>> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v);
>> +
>> +#endif
>

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-09 15:41     ` Michael Roth
@ 2011-06-09 15:55       ` Luiz Capitulino
  2011-06-09 16:26         ` Michael Roth
  0 siblings, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-09 15:55 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Thu, 09 Jun 2011 10:41:53 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> On 06/09/2011 10:30 AM, Luiz Capitulino wrote:
> > On Fri,  3 Jun 2011 17:33:08 -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>
> >> ---
> >>   qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
> >>   qapi/qmp-input-visiter.h |   26 +++++
> >>   2 files changed, 265 insertions(+), 0 deletions(-)
> >>   create mode 100644 qapi/qmp-input-visiter.c
> >>   create mode 100644 qapi/qmp-input-visiter.h
> >>
> >> diff --git a/qapi/qmp-input-visiter.c b/qapi/qmp-input-visiter.c
> >> new file mode 100644
> >> index 0000000..6767e39
> >> --- /dev/null
> >> +++ b/qapi/qmp-input-visiter.c
> >> @@ -0,0 +1,239 @@
> >> +#include "qmp-input-visiter.h"
> >> +#include "qemu-queue.h"
> >> +#include "qemu-common.h"
> >> +#include "qemu-objects.h"
> >> +#include "qerror.h"
> >> +
> >> +#define QAPI_OBJECT_SIZE 512
> >> +
> >> +#define QIV_STACK_SIZE 1024
> >> +
> >> +typedef struct StackObject
> >> +{
> >> +    QObject *obj;
> >> +    QListEntry *entry;
> >> +} StackObject;
> >> +
> >> +struct QmpInputVisiter
> >> +{
> >> +    Visiter visiter;
> >> +    QObject *obj;
> >> +    StackObject stack[QIV_STACK_SIZE];
> >> +    int nb_stack;
> >> +};
> >> +
> >> +static QmpInputVisiter *to_qiv(Visiter *v)
> >> +{
> >> +    return container_of(v, QmpInputVisiter, visiter);
> >> +}
> >> +
> >> +static QObject *qmp_input_get_object(QmpInputVisiter *qiv, const char *name)
> >> +{
> >> +    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(QmpInputVisiter *qiv, QObject *obj)
> >> +{
> >> +    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++;
> >> +
> >> +    assert(qiv->nb_stack<  QIV_STACK_SIZE); // FIXME
> >
> > Can't this limit be reached if a client sends a nested object? Why
> > don't we make it dynamic and/or return an error if a limit is reached?
> >
> 
> Yup, I think that's what the fixme was for. It's been fixed in my tree, 
> just sets an Error and returns instead now.
> 
> In reality the token limit added to the json parser with the set1 
> patches would catch overrun attempts from the client though, so it's 
> just an extra layer of protection.

Isn't this limit only in effect for individual tokens? Or does it also
catches the number of values in a dict?

> 
> >> +}
> >> +
> >> +static void qmp_input_pop(QmpInputVisiter *qiv)
> >> +{
> >> +    qiv->nb_stack--;
> >> +    assert(qiv->nb_stack>= 0); // FIXME
> >> +}
> >> +
> >> +static void qmp_input_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "object");
> >> +        return;
> >> +    }
> >> +
> >> +    qmp_input_push(qiv, qobj);
> >> +
> >> +    if (obj) {
> >> +        *obj = qemu_mallocz(QAPI_OBJECT_SIZE);
> >
> > I'm not sure I understand how this is being handled. This is allocating
> > the struct size, right? What happens if struct size>  QAPI_OBJECT_SIZE?
> >
> 
> Badness :) We'll need to pick a reasonable value and note it in the 
> schema documentation.

Isn't it possible to pass the struct size to visit_start_struct()? The
object itself is passed... Another (complex) solution would be to walk
through the dictionary's elements and calculate the struct size.

> 
> >> +    }
> >> +}
> >> +
> >> +static void qmp_input_end_struct(Visiter *v, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +
> >> +    qmp_input_pop(qiv);
> >> +}
> >> +
> >> +static void qmp_input_start_list(Visiter *v, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "list");
> >> +        return;
> >> +    }
> >> +
> >> +    qmp_input_push(qiv, qobj);
> >> +}
> >> +
> >> +static GenericList *qmp_input_next_list(Visiter *v, GenericList **list, Error **errp)
> >> +{
> >> +    QmpInputVisiter *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(Visiter *v, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +
> >> +    qmp_input_pop(qiv);
> >> +}
> >> +
> >> +static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "integer");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qint_get_int(qobject_to_qint(qobj));
> >> +}
> >> +
> >> +static void qmp_input_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
> >> +}
> >> +
> >> +static void qmp_input_type_str(Visiter *v, char **obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
> >> +}
> >> +
> >> +static void qmp_input_type_number(Visiter *v, double *obj, const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
> >> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "double");
> >> +        return;
> >> +    }
> >> +
> >> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
> >> +}
> >> +
> >> +static void qmp_input_type_enum(Visiter *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(Visiter *v, bool *present,
> >> +                                     const char *name, Error **errp)
> >> +{
> >> +    QmpInputVisiter *qiv = to_qiv(v);
> >> +    QObject *qobj = qmp_input_get_object(qiv, name);
> >> +
> >> +    if (!qobj) {
> >> +        *present = false;
> >> +        return;
> >> +    }
> >> +
> >> +    *present = true;
> >> +}
> >> +
> >> +static void qmp_input_end_optional(Visiter *v, Error **errp)
> >> +{
> >> +}
> >> +
> >> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v)
> >> +{
> >> +    return&v->visiter;
> >> +}
> >> +
> >> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj)
> >> +{
> >> +    QmpInputVisiter *v;
> >> +
> >> +    v = qemu_mallocz(sizeof(*v));
> >> +
> >> +    v->visiter.start_struct = qmp_input_start_struct;
> >> +    v->visiter.end_struct = qmp_input_end_struct;
> >> +    v->visiter.start_list = qmp_input_start_list;
> >> +    v->visiter.next_list = qmp_input_next_list;
> >> +    v->visiter.end_list = qmp_input_end_list;
> >> +    v->visiter.type_enum = qmp_input_type_enum;
> >> +    v->visiter.type_int = qmp_input_type_int;
> >> +    v->visiter.type_bool = qmp_input_type_bool;
> >> +    v->visiter.type_str = qmp_input_type_str;
> >> +    v->visiter.type_number = qmp_input_type_number;
> >> +    v->visiter.start_optional = qmp_input_start_optional;
> >> +    v->visiter.end_optional = qmp_input_end_optional;
> >> +
> >> +    v->obj = obj;
> >> +
> >> +    return v;
> >> +}
> >> diff --git a/qapi/qmp-input-visiter.h b/qapi/qmp-input-visiter.h
> >> new file mode 100644
> >> index 0000000..3e4d06f
> >> --- /dev/null
> >> +++ b/qapi/qmp-input-visiter.h
> >> @@ -0,0 +1,26 @@
> >> +/*
> >> + * Input Visiter
> >> + *
> >> + * 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_VISITER_H
> >> +#define QMP_INPUT_VISITER_H
> >> +
> >> +#include "qapi-visit-core.h"
> >> +#include "qobject.h"
> >> +
> >> +typedef struct QmpInputVisiter QmpInputVisiter;
> >> +
> >> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj);
> >> +
> >> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v);
> >> +
> >> +#endif
> >
> 

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-09 15:55       ` Luiz Capitulino
@ 2011-06-09 16:26         ` Michael Roth
  0 siblings, 0 replies; 52+ messages in thread
From: Michael Roth @ 2011-06-09 16:26 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On 06/09/2011 10:55 AM, Luiz Capitulino wrote:
> On Thu, 09 Jun 2011 10:41:53 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> On 06/09/2011 10:30 AM, Luiz Capitulino wrote:
>>> On Fri,  3 Jun 2011 17:33:08 -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>
>>>> ---
>>>>    qapi/qmp-input-visiter.c |  239 ++++++++++++++++++++++++++++++++++++++++++++++
>>>>    qapi/qmp-input-visiter.h |   26 +++++
>>>>    2 files changed, 265 insertions(+), 0 deletions(-)
>>>>    create mode 100644 qapi/qmp-input-visiter.c
>>>>    create mode 100644 qapi/qmp-input-visiter.h
>>>>
>>>> diff --git a/qapi/qmp-input-visiter.c b/qapi/qmp-input-visiter.c
>>>> new file mode 100644
>>>> index 0000000..6767e39
>>>> --- /dev/null
>>>> +++ b/qapi/qmp-input-visiter.c
>>>> @@ -0,0 +1,239 @@
>>>> +#include "qmp-input-visiter.h"
>>>> +#include "qemu-queue.h"
>>>> +#include "qemu-common.h"
>>>> +#include "qemu-objects.h"
>>>> +#include "qerror.h"
>>>> +
>>>> +#define QAPI_OBJECT_SIZE 512
>>>> +
>>>> +#define QIV_STACK_SIZE 1024
>>>> +
>>>> +typedef struct StackObject
>>>> +{
>>>> +    QObject *obj;
>>>> +    QListEntry *entry;
>>>> +} StackObject;
>>>> +
>>>> +struct QmpInputVisiter
>>>> +{
>>>> +    Visiter visiter;
>>>> +    QObject *obj;
>>>> +    StackObject stack[QIV_STACK_SIZE];
>>>> +    int nb_stack;
>>>> +};
>>>> +
>>>> +static QmpInputVisiter *to_qiv(Visiter *v)
>>>> +{
>>>> +    return container_of(v, QmpInputVisiter, visiter);
>>>> +}
>>>> +
>>>> +static QObject *qmp_input_get_object(QmpInputVisiter *qiv, const char *name)
>>>> +{
>>>> +    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(QmpInputVisiter *qiv, QObject *obj)
>>>> +{
>>>> +    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++;
>>>> +
>>>> +    assert(qiv->nb_stack<   QIV_STACK_SIZE); // FIXME
>>>
>>> Can't this limit be reached if a client sends a nested object? Why
>>> don't we make it dynamic and/or return an error if a limit is reached?
>>>
>>
>> Yup, I think that's what the fixme was for. It's been fixed in my tree,
>> just sets an Error and returns instead now.
>>
>> In reality the token limit added to the json parser with the set1
>> patches would catch overrun attempts from the client though, so it's
>> just an extra layer of protection.
>
> Isn't this limit only in effect for individual tokens? Or does it also
> catches the number of values in a dict?
>

You're right, looking again we have a limit on individual token size, 
and a limit on nested levels to avoid arbitrary levels of recursion in 
the parser. But the the number of entries that can be put into a 
dict/list are unbounded, so this check might actually needed.

We'll probably want to harden the parser/streamer stuff for case as 
well, to the point where we can put an upper bound on how large a QMP 
client-produced qobject can be. I'll look at a separate patch against 
master for this.

>>
>>>> +}
>>>> +
>>>> +static void qmp_input_pop(QmpInputVisiter *qiv)
>>>> +{
>>>> +    qiv->nb_stack--;
>>>> +    assert(qiv->nb_stack>= 0); // FIXME
>>>> +}
>>>> +
>>>> +static void qmp_input_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "object");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    qmp_input_push(qiv, qobj);
>>>> +
>>>> +    if (obj) {
>>>> +        *obj = qemu_mallocz(QAPI_OBJECT_SIZE);
>>>
>>> I'm not sure I understand how this is being handled. This is allocating
>>> the struct size, right? What happens if struct size>   QAPI_OBJECT_SIZE?
>>>
>>
>> Badness :) We'll need to pick a reasonable value and note it in the
>> schema documentation.
>
> Isn't it possible to pass the struct size to visit_start_struct()? The

Indeed! The generated code knows the struct type, so it could pass in 
the size as a parameter. I'll take a look at this.

> object itself is passed... Another (complex) solution would be to walk
> through the dictionary's elements and calculate the struct size.
>

The walking approach might have issues with optional fields and whatnot.

>>
>>>> +    }
>>>> +}
>>>> +
>>>> +static void qmp_input_end_struct(Visiter *v, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +
>>>> +    qmp_input_pop(qiv);
>>>> +}
>>>> +
>>>> +static void qmp_input_start_list(Visiter *v, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "list");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    qmp_input_push(qiv, qobj);
>>>> +}
>>>> +
>>>> +static GenericList *qmp_input_next_list(Visiter *v, GenericList **list, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *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(Visiter *v, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +
>>>> +    qmp_input_pop(qiv);
>>>> +}
>>>> +
>>>> +static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "integer");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qint_get_int(qobject_to_qint(qobj));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qbool_get_int(qobject_to_qbool(qobj));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_str(Visiter *v, char **obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_number(Visiter *v, double *obj, const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
>>>> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "double");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
>>>> +}
>>>> +
>>>> +static void qmp_input_type_enum(Visiter *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(Visiter *v, bool *present,
>>>> +                                     const char *name, Error **errp)
>>>> +{
>>>> +    QmpInputVisiter *qiv = to_qiv(v);
>>>> +    QObject *qobj = qmp_input_get_object(qiv, name);
>>>> +
>>>> +    if (!qobj) {
>>>> +        *present = false;
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    *present = true;
>>>> +}
>>>> +
>>>> +static void qmp_input_end_optional(Visiter *v, Error **errp)
>>>> +{
>>>> +}
>>>> +
>>>> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v)
>>>> +{
>>>> +    return&v->visiter;
>>>> +}
>>>> +
>>>> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj)
>>>> +{
>>>> +    QmpInputVisiter *v;
>>>> +
>>>> +    v = qemu_mallocz(sizeof(*v));
>>>> +
>>>> +    v->visiter.start_struct = qmp_input_start_struct;
>>>> +    v->visiter.end_struct = qmp_input_end_struct;
>>>> +    v->visiter.start_list = qmp_input_start_list;
>>>> +    v->visiter.next_list = qmp_input_next_list;
>>>> +    v->visiter.end_list = qmp_input_end_list;
>>>> +    v->visiter.type_enum = qmp_input_type_enum;
>>>> +    v->visiter.type_int = qmp_input_type_int;
>>>> +    v->visiter.type_bool = qmp_input_type_bool;
>>>> +    v->visiter.type_str = qmp_input_type_str;
>>>> +    v->visiter.type_number = qmp_input_type_number;
>>>> +    v->visiter.start_optional = qmp_input_start_optional;
>>>> +    v->visiter.end_optional = qmp_input_end_optional;
>>>> +
>>>> +    v->obj = obj;
>>>> +
>>>> +    return v;
>>>> +}
>>>> diff --git a/qapi/qmp-input-visiter.h b/qapi/qmp-input-visiter.h
>>>> new file mode 100644
>>>> index 0000000..3e4d06f
>>>> --- /dev/null
>>>> +++ b/qapi/qmp-input-visiter.h
>>>> @@ -0,0 +1,26 @@
>>>> +/*
>>>> + * Input Visiter
>>>> + *
>>>> + * 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_VISITER_H
>>>> +#define QMP_INPUT_VISITER_H
>>>> +
>>>> +#include "qapi-visit-core.h"
>>>> +#include "qobject.h"
>>>> +
>>>> +typedef struct QmpInputVisiter QmpInputVisiter;
>>>> +
>>>> +QmpInputVisiter *qmp_input_visiter_new(QObject *obj);
>>>> +
>>>> +Visiter *qmp_input_get_visiter(QmpInputVisiter *v);
>>>> +
>>>> +#endif
>>>
>>
>

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter Michael Roth
  2011-06-09 15:30   ` Luiz Capitulino
@ 2011-06-09 16:26   ` Peter Maydell
  2011-06-09 16:41     ` Michael Roth
  2011-06-13 19:12   ` Luiz Capitulino
  2 siblings, 1 reply; 52+ messages in thread
From: Peter Maydell @ 2011-06-09 16:26 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, lcapitulino, agl, qemu-devel, Jes.Sorensen

On 3 June 2011 23:33, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> A type of Visiter class

[randomly noted against this patch because this is where I happened
to notice it...]

Should be "Visitor" throughout (and in other patches), please?

-- PMM

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-09 16:26   ` Peter Maydell
@ 2011-06-09 16:41     ` Michael Roth
  2011-06-09 18:13       ` Anthony Liguori
  0 siblings, 1 reply; 52+ messages in thread
From: Michael Roth @ 2011-06-09 16:41 UTC (permalink / raw)
  To: Peter Maydell; +Cc: aliguori, lcapitulino, agl, qemu-devel, Jes.Sorensen

On 06/09/2011 11:26 AM, Peter Maydell wrote:
> On 3 June 2011 23:33, Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>> A type of Visiter class
>
> [randomly noted against this patch because this is where I happened
> to notice it...]
>
> Should be "Visitor" throughout (and in other patches), please?
>
> -- PMM

Stefan pointed that out too...I was hoping to bring "visiter" back in 
style, but we can change it :)

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

* Re: [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter Michael Roth
@ 2011-06-09 17:47   ` Luiz Capitulino
  2011-06-09 19:42     ` Anthony Liguori
  0 siblings, 1 reply; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-09 17:47 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:09 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> Type of Visiter class that serves as the inverse of the input visiter:
> 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>
> ---
>  qapi/qmp-output-visiter.c |  180 +++++++++++++++++++++++++++++++++++++++++++++
>  qapi/qmp-output-visiter.h |   27 +++++++
>  2 files changed, 207 insertions(+), 0 deletions(-)
>  create mode 100644 qapi/qmp-output-visiter.c
>  create mode 100644 qapi/qmp-output-visiter.h
> 
> diff --git a/qapi/qmp-output-visiter.c b/qapi/qmp-output-visiter.c
> new file mode 100644
> index 0000000..4a7cb36
> --- /dev/null
> +++ b/qapi/qmp-output-visiter.c
> @@ -0,0 +1,180 @@
> +#include "qmp-output-visiter.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 QmpOutputVisiter
> +{
> +    Visiter visiter;
> +    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 QmpOutputVisiter *to_qov(Visiter *v)
> +{
> +    return container_of(v, QmpOutputVisiter, visiter);
> +}
> +
> +static void qmp_output_push_obj(QmpOutputVisiter *qov, QObject *value)
> +{
> +    QStackEntry *e = qemu_mallocz(sizeof(*e));
> +
> +    e->value = value;
> +    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
> +}
> +
> +static QObject *qmp_output_pop(QmpOutputVisiter *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(QmpOutputVisiter *qov)
> +{
> +    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
> +    return e->value;
> +}
> +
> +static QObject *qmp_output_last(QmpOutputVisiter *qov)
> +{
> +    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
> +    return e->value;
> +}
> +
> +static void qmp_output_add_obj(QmpOutputVisiter *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));

I'm not sure I understand when we should discard an item like this,
shouldn't this be an assert()?

> +        qmp_output_push_obj(qov, value);
> +        break;
> +    }
> +}
> +
> +static void qmp_output_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    QDict *dict = qdict_new();
> +
> +    qmp_output_add(qov, name, dict);

This calls qmp_output_push() if the stack is empty...

> +    qmp_output_push(qov, dict);

...then it's called again here, so the element is added twice,
is this expected?

> +}
> +
> +static void qmp_output_end_struct(Visiter *v, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_pop(qov);
> +}
> +
> +static void qmp_output_start_list(Visiter *v, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *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(Visiter *v, GenericList **list, Error **errp)
> +{
> +    GenericList *retval = *list;
> +    *list = retval->next;
> +    return retval;
> +}
> +
> +static void qmp_output_end_list(Visiter *v, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_pop(qov);
> +}
> +
> +static void qmp_output_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_add(qov, name, qint_from_int(*obj));
> +}
> +
> +static void qmp_output_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_add(qov, name, qbool_from_int(*obj));
> +}
> +
> +static void qmp_output_type_str(Visiter *v, char **obj, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_add(qov, name, qstring_from_str(*obj));
> +}
> +
> +static void qmp_output_type_number(Visiter *v, double *obj, const char *name, Error **errp)
> +{
> +    QmpOutputVisiter *qov = to_qov(v);
> +    qmp_output_add(qov, name, qfloat_from_double(*obj));
> +}
> +
> +static void qmp_output_type_enum(Visiter *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(QmpOutputVisiter *qov)
> +{
> +    return qmp_output_first(qov);
> +}
> +
> +Visiter *qmp_output_get_visiter(QmpOutputVisiter *v)
> +{
> +    return &v->visiter;
> +}
> +
> +QmpOutputVisiter *qmp_output_visiter_new(void)
> +{
> +    QmpOutputVisiter *v;
> +
> +    v = qemu_mallocz(sizeof(*v));
> +
> +    v->visiter.start_struct = qmp_output_start_struct;
> +    v->visiter.end_struct = qmp_output_end_struct;
> +    v->visiter.start_list = qmp_output_start_list;
> +    v->visiter.next_list = qmp_output_next_list;
> +    v->visiter.end_list = qmp_output_end_list;
> +    v->visiter.type_enum = qmp_output_type_enum;
> +    v->visiter.type_int = qmp_output_type_int;
> +    v->visiter.type_bool = qmp_output_type_bool;
> +    v->visiter.type_str = qmp_output_type_str;
> +    v->visiter.type_number = qmp_output_type_number;
> +
> +    QTAILQ_INIT(&v->stack);
> +
> +    return v;
> +}
> diff --git a/qapi/qmp-output-visiter.h b/qapi/qmp-output-visiter.h
> new file mode 100644
> index 0000000..b04ab02
> --- /dev/null
> +++ b/qapi/qmp-output-visiter.h
> @@ -0,0 +1,27 @@
> +/*
> + * Output Visiter
> + *
> + * 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_VISITER_H
> +#define QMP_OUTPUT_VISITER_H
> +
> +#include "qapi-visit-core.h"
> +#include "qobject.h"
> +
> +typedef struct QmpOutputVisiter QmpOutputVisiter;
> +
> +QmpOutputVisiter *qmp_output_visiter_new(void);
> +
> +QObject *qmp_output_get_qobject(QmpOutputVisiter *v);
> +Visiter *qmp_output_get_visiter(QmpOutputVisiter *v);
> +
> +#endif

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

* Re: [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h
  2011-06-09 15:14   ` Luiz Capitulino
@ 2011-06-09 18:08     ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-09 18:08 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: Jes.Sorensen, agl, Michael Roth, qemu-devel

On 06/09/2011 10:14 AM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:33:07 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> Base definitions/includes for Visiter interface used by generated
>> visiter/marshalling code.
>>
>> Signed-off-by: Michael Roth<mdroth@linux.vnet.ibm.com>
>> ---
>>   qapi/qapi-visit-core.h |  187 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 files changed, 187 insertions(+), 0 deletions(-)
>>   create mode 100644 qapi/qapi-visit-core.h
>>
>> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
>> new file mode 100644
>> index 0000000..a5ba016
>> --- /dev/null
>> +++ b/qapi/qapi-visit-core.h
>> @@ -0,0 +1,187 @@
>> +/*
>> + * Core Definitions for QAPI Visiter 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_VISITER_CORE_H
>> +#define QAPI_VISITER_CORE_H
>> +
>> +#include "qapi/qapi-types-core.h"
>> +#include "error.h"
>> +#include<stdlib.h>
>> +
>> +typedef struct GenericList
>> +{
>> +    void *value;
>> +    struct GenericList *next;
>> +} GenericList;
>
> If there's a reason to not use our list API, it should be explained in
> the commit log.

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.

Regards,

Anthony Liguori

>
>> +
>> +typedef struct Visiter Visiter;
>> +
>> +struct Visiter
>> +{
>> +    /* Must be set */
>> +    void (*start_struct)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
>> +    void (*end_struct)(Visiter *v, Error **errp);
>> +
>> +    void (*start_list)(Visiter *v, const char *name, Error **errp);
>> +    GenericList *(*next_list)(Visiter *v, GenericList **list, Error **errp);
>> +    void (*end_list)(Visiter *v, Error **errp);
>> +
>> +    void (*type_enum)(Visiter *v, int *obj, const char *kind, const char *name, Error **errp);
>> +
>> +    void (*type_int)(Visiter *v, int64_t *obj, const char *name, Error **errp);
>> +    void (*type_bool)(Visiter *v, bool *obj, const char *name, Error **errp);
>> +    void (*type_str)(Visiter *v, char **obj, const char *name, Error **errp);
>> +    void (*type_number)(Visiter *v, double *obj, const char *name, Error **errp);
>> +
>> +    /* May be NULL */
>> +    void (*start_optional)(Visiter *v, bool *present, const char *name, Error **errp);
>> +    void (*end_optional)(Visiter *v, Error **errp);
>> +
>> +    void (*start_handle)(Visiter *v, void **obj, const char *kind, const char *name, Error **errp);
>> +    void (*end_handle)(Visiter *v, Error **errp);
>> +};
>> +
>> +static inline void visit_start_handle(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    if (v->start_handle) {
>> +        v->start_handle(v, obj, kind, name, errp);
>> +    }
>> +}
>
> IMO, all these inlines should be real functions and...
>
>> +
>> +static inline void visit_end_handle(Visiter *v, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    if (v->end_handle) {
>> +        v->end_handle(v, errp);
>> +    }
>> +}
>> +
>> +static inline void visit_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->start_struct(v, obj, kind, name, errp);
>> +}
>
> ... this could be:
>
> if (!error_is_set(errp)) {
>      v->start_struct(v, obj, kind, name, errp);
> }
>
> Also valid for other functions in this file.
>
>> +
>> +static inline void visit_end_struct(Visiter *v, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->end_struct(v, errp);
>> +}
>> +
>> +static inline void visit_start_list(Visiter *v, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->start_list(v, name, errp);
>> +}
>> +
>> +static inline GenericList *visit_next_list(Visiter *v, GenericList **list, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return 0;
>> +    }
>> +
>> +    return v->next_list(v, list, errp);
>> +}
>> +
>> +static inline void visit_end_list(Visiter *v, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->end_list(v, errp);
>> +}
>> +
>> +static inline void visit_start_optional(Visiter *v, bool *present, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    if (v->start_optional) {
>> +        v->start_optional(v, present, name, errp);
>> +    }
>> +}
>> +
>> +static inline void visit_end_optional(Visiter *v, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    if (v->end_optional) {
>> +        v->end_optional(v, errp);
>> +    }
>> +}
>> +
>> +static inline void visit_type_enum(Visiter *v, int *obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->type_enum(v, obj, kind, name, errp);
>> +}
>> +
>> +static inline void visit_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->type_int(v, obj, name, errp);
>> +}
>> +
>> +static inline void visit_type_bool(Visiter *v, bool *obj, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->type_bool(v, obj, name, errp);
>> +}
>> +
>> +static inline void visit_type_str(Visiter *v, char **obj, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->type_str(v, obj, name, errp);
>> +}
>> +
>> +static inline void visit_type_number(Visiter *v, double *obj, const char *name, Error **errp)
>> +{
>> +    if (error_is_set(errp)) {
>> +        return;
>> +    }
>> +
>> +    v->type_number(v, obj, name, errp);
>> +}
>> +
>> +#endif
>

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-09 16:41     ` Michael Roth
@ 2011-06-09 18:13       ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-09 18:13 UTC (permalink / raw)
  To: Michael Roth
  Cc: Peter Maydell, agl, Jes.Sorensen, qemu-devel, lcapitulino, aliguori

On 06/09/2011 11:41 AM, Michael Roth wrote:
> On 06/09/2011 11:26 AM, Peter Maydell wrote:
>> On 3 June 2011 23:33, Michael Roth<mdroth@linux.vnet.ibm.com> wrote:
>>> A type of Visiter class
>>
>> [randomly noted against this patch because this is where I happened
>> to notice it...]
>>
>> Should be "Visitor" throughout (and in other patches), please?

That was my Jersey-accent kicking in I think ;-)

Regards,

Anthony Liguori

>>
>> -- PMM
>
> Stefan pointed that out too...I was hoping to bring "visiter" back in
> style, but we can change it :)

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

* Re: [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter
  2011-06-09 17:47   ` Luiz Capitulino
@ 2011-06-09 19:42     ` Anthony Liguori
  0 siblings, 0 replies; 52+ messages in thread
From: Anthony Liguori @ 2011-06-09 19:42 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: Jes.Sorensen, agl, Michael Roth, qemu-devel

On 06/09/2011 12:47 PM, Luiz Capitulino wrote:
> On Fri,  3 Jun 2011 17:33:09 -0500
> Michael Roth<mdroth@linux.vnet.ibm.com>  wrote:
>
>> Type of Visiter class that serves as the inverse of the input visiter:
>> 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>
>> ---
>>   qapi/qmp-output-visiter.c |  180 +++++++++++++++++++++++++++++++++++++++++++++
>>   qapi/qmp-output-visiter.h |   27 +++++++
>>   2 files changed, 207 insertions(+), 0 deletions(-)
>>   create mode 100644 qapi/qmp-output-visiter.c
>>   create mode 100644 qapi/qmp-output-visiter.h
>>
>> diff --git a/qapi/qmp-output-visiter.c b/qapi/qmp-output-visiter.c
>> new file mode 100644
>> index 0000000..4a7cb36
>> --- /dev/null
>> +++ b/qapi/qmp-output-visiter.c
>> @@ -0,0 +1,180 @@
>> +#include "qmp-output-visiter.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 QmpOutputVisiter
>> +{
>> +    Visiter visiter;
>> +    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 QmpOutputVisiter *to_qov(Visiter *v)
>> +{
>> +    return container_of(v, QmpOutputVisiter, visiter);
>> +}
>> +
>> +static void qmp_output_push_obj(QmpOutputVisiter *qov, QObject *value)
>> +{
>> +    QStackEntry *e = qemu_mallocz(sizeof(*e));
>> +
>> +    e->value = value;
>> +    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
>> +}
>> +
>> +static QObject *qmp_output_pop(QmpOutputVisiter *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(QmpOutputVisiter *qov)
>> +{
>> +    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
>> +    return e->value;
>> +}
>> +
>> +static QObject *qmp_output_last(QmpOutputVisiter *qov)
>> +{
>> +    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
>> +    return e->value;
>> +}
>> +
>> +static void qmp_output_add_obj(QmpOutputVisiter *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));
>
> I'm not sure I understand when we should discard an item like this,
> shouldn't this be an assert()?
>
>> +        qmp_output_push_obj(qov, value);
>> +        break;
>> +    }
>> +}
>> +
>> +static void qmp_output_start_struct(Visiter *v, void **obj, const char *kind, const char *name, Error **errp)
>> +{
>> +    QmpOutputVisiter *qov = to_qov(v);
>> +    QDict *dict = qdict_new();
>> +
>> +    qmp_output_add(qov, name, dict);
>
> This calls qmp_output_push() if the stack is empty...
>
>> +    qmp_output_push(qov, dict);
>
> ...then it's called again here, so the element is added twice,
> is this expected?

There's a subtle behavior here that both of your comments are asking about.

Let's say you're trying to generate:

{ 'hello': { 'world': true } }

It'll generate a sequence of calls like:

1. start_struct('')
2. start_struct('hello')
3. marshal_bool('world')
4. end_struct()
5. end_struct()

At call (1), you've got an empty stack.  You need to start with 
something, so you start by pushing the element onto the stack.

This is sort of the boot strap bit to get a first element on the stack. 
  This is really designed to work with the following sequence in mind:

1. marshal_bool('world')
2. marshal_bool('foo')

In this case, the semantics are that the top-of-stack after (1) is bool 
world, but then after (2), that object is freed, and then the 
top-of-stack is bool foo.

This results in the slightly odd behavior of adding a dictionary twice 
to the stack when it's the top-level element but the behavior is 
entirely intentional.

You need to add it twice such that when you pop it on end_struct, you 
still have a reference that you can return in qmp_output_visitor_get_obj().

Regards,

Anthony Liguori

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

* Re: [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter
  2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter Michael Roth
  2011-06-09 15:30   ` Luiz Capitulino
  2011-06-09 16:26   ` Peter Maydell
@ 2011-06-13 19:12   ` Luiz Capitulino
  2 siblings, 0 replies; 52+ messages in thread
From: Luiz Capitulino @ 2011-06-13 19:12 UTC (permalink / raw)
  To: Michael Roth; +Cc: aliguori, agl, qemu-devel, Jes.Sorensen

On Fri,  3 Jun 2011 17:33:08 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> +static void qmp_input_type_int(Visiter *v, int64_t *obj, const char *name, Error **errp)
> +{
> +    QmpInputVisiter *qiv = to_qiv(v);
> +    QObject *qobj = qmp_input_get_object(qiv, name);
> +
> +    if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "integer");
> +        return;
> +    }
> +
> +    *obj = qint_get_int(qobject_to_qint(qobj));

Let me warn you for an error I just got: if 'name' is NULL and the if test is
true, then error_set() will segfault, because 'name' must not be NULL.

So either, we always pass 'name' in the generated code or we automatically
build a new string if 'name' is NULL.

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

end of thread, other threads:[~2011-06-13 19:13 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-03 22:32 [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Michael Roth
2011-06-03 22:32 ` [Qemu-devel] [PATCH v2][ 01/21] Add hard build dependency on glib Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 02/21] qlist: add qlist_first()/qlist_next() Michael Roth
2011-06-08 17:50   ` Luiz Capitulino
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 03/21] qapi: add module init types for qapi Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 04/21] qapi: add ordereddict/qapi.py helper libraries Michael Roth
2011-06-07 19:04   ` Anthony Liguori
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 05/21] qapi: add qapi-types.py code generator Michael Roth
2011-06-07 19:06   ` Anthony Liguori
2011-06-07 19:12     ` Luiz Capitulino
2011-06-07 19:54       ` Anthony Liguori
2011-06-09  7:00     ` Markus Armbruster
2011-06-09 15:05   ` Luiz Capitulino
2011-06-09 15:28     ` Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 06/21] qapi: add qapi-visit.py " Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 07/21] qapi: add qapi-commands.py " Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 08/21] qapi: add qapi-types-core.h Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 09/21] qapi: add qapi-visit-core.h Michael Roth
2011-06-09 15:14   ` Luiz Capitulino
2011-06-09 18:08     ` Anthony Liguori
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 10/21] qapi: add QMP input visiter Michael Roth
2011-06-09 15:30   ` Luiz Capitulino
2011-06-09 15:41     ` Michael Roth
2011-06-09 15:55       ` Luiz Capitulino
2011-06-09 16:26         ` Michael Roth
2011-06-09 16:26   ` Peter Maydell
2011-06-09 16:41     ` Michael Roth
2011-06-09 18:13       ` Anthony Liguori
2011-06-13 19:12   ` Luiz Capitulino
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 11/21] qapi: add QMP output visiter Michael Roth
2011-06-09 17:47   ` Luiz Capitulino
2011-06-09 19:42     ` Anthony Liguori
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 12/21] qapi: add QAPI dealloc visiter Michael Roth
2011-06-07 19:07   ` Anthony Liguori
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 13/21] qapi: add command registration/lookup functions Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 14/21] qapi: add QMP dispatch functions Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 15/21] qapi: add base declaration/types for QMP Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 16/21] qapi: test schema used for unit tests Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 17/21] qapi: add test-visiter, tests for gen. visiter code Michael Roth
2011-06-07 19:08   ` Anthony Liguori
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 18/21] qapi: Makefile changes to build test-visiter Michael Roth
2011-06-08 17:39   ` Luiz Capitulino
2011-06-08 17:55     ` Michael Roth
2011-06-08 18:00       ` Luiz Capitulino
2011-06-08 18:12     ` Anthony Liguori
2011-06-08 18:16       ` Luiz Capitulino
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 19/21] qapi: add test-qmp-commands, tests for gen. marshalling/dispatch code Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 20/21] qapi: Makefile changes to build test-qmp-commands Michael Roth
2011-06-03 22:33 ` [Qemu-devel] [PATCH v2][ 21/21] qapi: add QAPI code generation documentation Michael Roth
2011-06-08 16:43 ` [Qemu-devel] [QAPI+QGA 2/3] QAPI code generation infrastructure v2 Luiz Capitulino
2011-06-08 17:03   ` Michael Roth
2011-06-08 17:59     ` Luiz Capitulino

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.