qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection
@ 2012-07-24 17:20 Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import Michael Roth
                   ` (21 more replies)
  0 siblings, 22 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

These patches are based on origin/master, and can also be obtained from:

git://github.com/mdroth/qemu.git qidl-rfc2

= CHANGES SINCE RFC V1 =

 - QIDL'd cirrus_vga as a more interesting example
 - add support for QIDL-defined properties
 - pass all files through preprocessor before parsing QIDL annotations to
   gracefully handle #define's/#if's/etc
 - use code-injection/macros to make generated visitor/property code
   available to each compilation unit
 - drop schema generation, instead, expose the QIDL-generated, binary-specific
   schemas via QOM to make it easier to analyze migration compatibility given
   2 versions of QEMU
 - drop VMSTATE code generation, focus on exposing enough state that VMSTATE
   can be eventually be layered on top using qom_path + json_path to access
   all required fields
 - wrap annotations in QIDL(...) to better support arguments and namespacing
 - seperate parser (qidl_parser.py) from code-generation (qidl.py)
 - fix various parsing corner cases:
    - handling of embedded, non-pointer structs and nested struct declarations
    - handling of unsigned/union/int types
    - support expressions in QIDL() parameters and field declarations (to
      be evaluated in the context of the generated visitor function)

= OVERVIEW =

The goal of these patches is to explore how we can leverage an IDL to improve
device serialization/migration.

Patches 1-17 are all infrastructure, and the initial commits for the QIDL
parser/code generator/documentation.

Patches 18+ are our first users: the unit tests, RTC, and cirrus_vga.

After annotating a QOM device with QIDL you can up with something
this (using QOM-FUSE as an example):

    mdroth@loki:~/w/qom$ ls -l qidl/schemas/
    total 0
    drwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 CirrusVGAState
    drwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 ISACirrusVGAState
    drwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 PCICirrusVGAState
    drwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 PCIDevice
    drwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 RTCState
    -rw-r--r-- 1 mdroth mdroth 4096 Dec 31  1969 type
    drwxr-xr-x 2 mdroth mdroth 4096 Dec 31  1969 VGACommonState

    mdroth@loki:~/w/qom$ ls -l machine/unattached/device\[8\]/
    total 0
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 addr
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 command_serr_enable
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 legacy-addr
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 legacy-command_serr_enable
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 legacy-multifunction
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 legacy-romfile
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 multifunction
    lrwxr-xr-x 2 mdroth mdroth   4096 Dec 31  1969 parent_bus -> ../../../machine/i440fx/pci.0
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 rombar
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 romfile
    -rw-r--r-- 1 mdroth mdroth 175236 Dec 31  1969 state
    lrwxr-xr-x 2 mdroth mdroth   4096 Dec 31  1969 state_schema -> ../../../qidl/schemas/PCICirrusVGAState
    -rw-r--r-- 1 mdroth mdroth   4096 Dec 31  1969 type

    mdroth@loki:~/w/qom$ cat machine/unattached/device\[8\]/state
    {u'cirrus_vga': {u'cirrus_blt_srcpitch': 0, u'cirrus_blt_width': 0, \
    u'cirrus_blt_bgcol': 0, u'last_hw_cursor_size': 0, \
    u'real_vram_size': 4194304, u'cirrus_blt_pixelwidth': 0, \
    u'cirrus_blt_mode': 0, u'last_hw_cursor_y_start': 0, \
    u'cirrus_blt_srcaddr': 0, u'cirrus_srccounter': 0, \
    u'cirrus_hidden_palette': [0, 0, 0, 0, 0, ...

At this point I'd like to push to get QIDL in place to expose guest-visible
device state via qom-get so it can be used for pre/post-migration
analysis/verification of device state. I think this is useful in-and-of
itself, and should be fairly low risk.

With the infrastructure in place we can then look at leveraging it for
vmstate and/or a new protocol, and also to figure out a nice way to add
capabilities-based transformations for post-serialize/pre-deserialize to
improve migration compatibility for any wire protocol (QEMUFile/vmstate
or otherwise) we layer on top. VMState at least can be done incrementally, so
we can begin looking at this immediately.

= General/Future Plans =

This is all very much open to discussion, and I only have a general idea of
how we can leverage this to improve migration compatibility/support. That
said:

With everything in place, we'd now have a means to serialize device state into
QObjects (or whatever). We can then perform whatever transformations/mark-up
we need to do (based on capabilities negotation centering around per-device
capabilities, for example), and send the state over the wire for migration.

The wire protocol is then simply a matter of how we encode the transformed
QObject. So a BER protocol could be implemented by creating something analagous
to the JSON-encoding facilities in qjson.c. Or, we could just keep using JSON,
perhaps with compression on top.

Eventually we can extend this approach to send device properties and encode the
actual composition tree in such a way that we can create machine machines on
the target side and avoid the need to duplicate the command-line invocation,
though that will take some substantial re-architecting/removal of the various
factory interfaces and further QOMification.

I'm not planning on incorporating memory migration into this, but it may be
possible to extend this approach to events/data blocks as well.

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

* [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:12   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py Michael Roth
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile              |    4 +-
 scripts/qapi-visit.py |  352 -------------------------------------------------
 scripts/qapi_visit.py |  352 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/Makefile        |    4 +-
 4 files changed, 356 insertions(+), 356 deletions(-)
 delete mode 100644 scripts/qapi-visit.py
 create mode 100644 scripts/qapi_visit.py

diff --git a/Makefile b/Makefile
index ab82ef3..ea7174c 100644
--- a/Makefile
+++ b/Makefile
@@ -195,8 +195,8 @@ qapi-types.c qapi-types.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
 qapi-visit.c qapi-visit.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
 qmp-commands.h qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
deleted file mode 100644
index 04ef7c4..0000000
--- a/scripts/qapi-visit.py
+++ /dev/null
@@ -1,352 +0,0 @@
-#
-# QAPI visitor generator
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-#  Anthony Liguori <aliguori@us.ibm.com>
-#  Michael Roth    <mdroth@linux.vnet.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
-
-from ordereddict import OrderedDict
-from qapi import *
-import sys
-import os
-import getopt
-import errno
-
-def generate_visit_struct_body(field_prefix, name, members):
-    ret = mcgen('''
-if (!error_is_set(errp)) {
-''')
-    push_indent()
-
-    if len(field_prefix):
-        field_prefix = field_prefix + "."
-        ret += mcgen('''
-Error **errp = &err; /* from outer scope */
-Error *err = NULL;
-visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
-''',
-                name=name)
-    else:
-        ret += mcgen('''
-Error *err = NULL;
-visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
-''',
-                name=name)
-
-    ret += mcgen('''
-if (!err) {
-    if (!obj || *obj) {
-''')
-
-    push_indent()
-    push_indent()
-    for argname, argentry, optional, structured in parse_args(members):
-        if optional:
-            ret += mcgen('''
-visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
-if (obj && (*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 += generate_visit_struct_body(field_prefix + argname, argname, argentry)
-        else:
-            ret += mcgen('''
-visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
-''',
-                         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, &err);
-''')
-
-    pop_indent()
-    ret += mcgen('''
-
-    error_propagate(errp, err);
-    err = NULL;
-}
-''')
-
-    pop_indent()
-    pop_indent()
-    ret += mcgen('''
-        /* Always call end_struct if start_struct succeeded.  */
-        visit_end_struct(m, &err);
-    }
-    error_propagate(errp, err);
-}
-''')
-    return ret
-
-def generate_visit_struct(name, members):
-    ret = mcgen('''
-
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
-{
-''',
-                name=name)
-
-    push_indent()
-    ret += generate_visit_struct_body("", name, members)
-    pop_indent()
-
-    ret += mcgen('''
-}
-''')
-    return ret
-
-def generate_visit_list(name, members):
-    return mcgen('''
-
-void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
-{
-    GenericList *i, **prev = (GenericList **)obj;
-    Error *err = NULL;
-
-    if (!error_is_set(errp)) {
-        visit_start_list(m, name, &err);
-        if (!err) {
-            for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
-                %(name)sList *native_i = (%(name)sList *)i;
-                visit_type_%(name)s(m, &native_i->value, NULL, &err);
-            }
-            error_propagate(errp, err);
-            err = NULL;
-
-            /* Always call end_list if start_list succeeded.  */
-            visit_end_list(m, &err);
-        }
-        error_propagate(errp, err);
-    }
-}
-''',
-                name=name)
-
-def generate_visit_enum(name, members):
-    return mcgen('''
-
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
-{
-    visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
-}
-''',
-                 name=name)
-
-def generate_visit_union(name, members):
-    ret = generate_visit_enum('%sKind' % name, members.keys())
-
-    ret += mcgen('''
-
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
-{
-    Error *err = NULL;
-
-    if (!error_is_set(errp)) {
-        visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
-        if (!err) {
-            if (!obj || *obj) {
-                visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
-                if (!err) {
-                    switch ((*obj)->kind) {
-''',
-                 name=name)
-
-    push_indent()
-    push_indent()
-    for key in members:
-        ret += mcgen('''
-            case %(abbrev)s_KIND_%(enum)s:
-                visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
-                break;
-''',
-                abbrev = de_camel_case(name).upper(),
-                enum = c_fun(de_camel_case(key)).upper(),
-                c_type=members[key],
-                c_name=c_fun(key))
-
-    ret += mcgen('''
-            default:
-                abort();
-            }
-        }
-        error_propagate(errp, err);
-        err = NULL;
-    }
-''')
-    pop_indent()
-    ret += mcgen('''
-        /* Always call end_struct if start_struct succeeded.  */
-        visit_end_struct(m, &err);
-    }
-    error_propagate(errp, err);
-}
-''')
-
-    pop_indent();
-    ret += mcgen('''
-}
-''')
-
-    return ret
-
-def generate_declaration(name, members, genlist=True):
-    ret = mcgen('''
-
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
-''',
-                name=name)
-
-    if genlist:
-        ret += mcgen('''
-void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
-''',
-                 name=name)
-
-    return ret
-
-def generate_decl_enum(name, members, genlist=True):
-    return mcgen('''
-
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
-''',
-                name=name)
-
-try:
-    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
-                                   ["source", "header", "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'
-
-do_c = False
-do_h = False
-
-for o, a in opts:
-    if o in ("-p", "--prefix"):
-        prefix = a
-    elif o in ("-o", "--output-dir"):
-        output_dir = a + "/"
-    elif o in ("-c", "--source"):
-        do_c = True
-    elif o in ("-h", "--header"):
-        do_h = True
-
-if not do_c and not do_h:
-    do_c = True
-    do_h = True
-
-c_file = output_dir + prefix + c_file
-h_file = output_dir + prefix + h_file
-
-try:
-    os.makedirs(output_dir)
-except os.error, e:
-    if e.errno != errno.EEXIST:
-        raise
-
-def maybe_open(really, name, opt):
-    if really:
-        return open(name, opt)
-    else:
-        import StringIO
-        return StringIO.StringIO()
-
-fdef = maybe_open(do_c, c_file, 'w')
-fdecl = maybe_open(do_h, h_file, 'w')
-
-fdef.write(mcgen('''
-/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-/*
- * schema-defined QAPI visitor functions
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#include "%(header)s"
-''',
-                 header=basename(h_file)))
-
-fdecl.write(mcgen('''
-/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-/*
- * schema-defined QAPI visitor function
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#ifndef %(guard)s
-#define %(guard)s
-
-#include "qapi/qapi-visit-core.h"
-#include "%(prefix)sqapi-types.h"
-''',
-                  prefix=prefix, guard=guardname(h_file)))
-
-exprs = parse_schema(sys.stdin)
-
-for expr in exprs:
-    if expr.has_key('type'):
-        ret = generate_visit_struct(expr['type'], expr['data'])
-        ret += generate_visit_list(expr['type'], expr['data'])
-        fdef.write(ret)
-
-        ret = generate_declaration(expr['type'], expr['data'])
-        fdecl.write(ret)
-    elif expr.has_key('union'):
-        ret = generate_visit_union(expr['union'], expr['data'])
-        ret += generate_visit_list(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)
-
-fdecl.write('''
-#endif
-''')
-
-fdecl.flush()
-fdecl.close()
-
-fdef.flush()
-fdef.close()
diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
new file mode 100644
index 0000000..04ef7c4
--- /dev/null
+++ b/scripts/qapi_visit.py
@@ -0,0 +1,352 @@
+#
+# QAPI visitor generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def generate_visit_struct_body(field_prefix, name, members):
+    ret = mcgen('''
+if (!error_is_set(errp)) {
+''')
+    push_indent()
+
+    if len(field_prefix):
+        field_prefix = field_prefix + "."
+        ret += mcgen('''
+Error **errp = &err; /* from outer scope */
+Error *err = NULL;
+visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
+''',
+                name=name)
+    else:
+        ret += mcgen('''
+Error *err = NULL;
+visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+''',
+                name=name)
+
+    ret += mcgen('''
+if (!err) {
+    if (!obj || *obj) {
+''')
+
+    push_indent()
+    push_indent()
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
+if (obj && (*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 += generate_visit_struct_body(field_prefix + argname, argname, argentry)
+        else:
+            ret += mcgen('''
+visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
+''',
+                         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, &err);
+''')
+
+    pop_indent()
+    ret += mcgen('''
+
+    error_propagate(errp, err);
+    err = NULL;
+}
+''')
+
+    pop_indent()
+    pop_indent()
+    ret += mcgen('''
+        /* Always call end_struct if start_struct succeeded.  */
+        visit_end_struct(m, &err);
+    }
+    error_propagate(errp, err);
+}
+''')
+    return ret
+
+def generate_visit_struct(name, members):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+''',
+                name=name)
+
+    push_indent()
+    ret += generate_visit_struct_body("", name, members)
+    pop_indent()
+
+    ret += mcgen('''
+}
+''')
+    return ret
+
+def generate_visit_list(name, members):
+    return mcgen('''
+
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
+{
+    GenericList *i, **prev = (GenericList **)obj;
+    Error *err = NULL;
+
+    if (!error_is_set(errp)) {
+        visit_start_list(m, name, &err);
+        if (!err) {
+            for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
+                %(name)sList *native_i = (%(name)sList *)i;
+                visit_type_%(name)s(m, &native_i->value, NULL, &err);
+            }
+            error_propagate(errp, err);
+            err = NULL;
+
+            /* Always call end_list if start_list succeeded.  */
+            visit_end_list(m, &err);
+        }
+        error_propagate(errp, err);
+    }
+}
+''',
+                name=name)
+
+def generate_visit_enum(name, members):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
+{
+    visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
+}
+''',
+                 name=name)
+
+def generate_visit_union(name, members):
+    ret = generate_visit_enum('%sKind' % name, members.keys())
+
+    ret += mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+{
+    Error *err = NULL;
+
+    if (!error_is_set(errp)) {
+        visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+        if (!err) {
+            if (!obj || *obj) {
+                visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
+                if (!err) {
+                    switch ((*obj)->kind) {
+''',
+                 name=name)
+
+    push_indent()
+    push_indent()
+    for key in members:
+        ret += mcgen('''
+            case %(abbrev)s_KIND_%(enum)s:
+                visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
+                break;
+''',
+                abbrev = de_camel_case(name).upper(),
+                enum = c_fun(de_camel_case(key)).upper(),
+                c_type=members[key],
+                c_name=c_fun(key))
+
+    ret += mcgen('''
+            default:
+                abort();
+            }
+        }
+        error_propagate(errp, err);
+        err = NULL;
+    }
+''')
+    pop_indent()
+    ret += mcgen('''
+        /* Always call end_struct if start_struct succeeded.  */
+        visit_end_struct(m, &err);
+    }
+    error_propagate(errp, err);
+}
+''')
+
+    pop_indent();
+    ret += mcgen('''
+}
+''')
+
+    return ret
+
+def generate_declaration(name, members, genlist=True):
+    ret = mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
+''',
+                name=name)
+
+    if genlist:
+        ret += mcgen('''
+void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+''',
+                 name=name)
+
+    return ret
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                name=name)
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
+                                   ["source", "header", "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'
+
+do_c = False
+do_h = False
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+    elif o in ("-c", "--source"):
+        do_c = True
+    elif o in ("-h", "--header"):
+        do_h = True
+
+if not do_c and not do_h:
+    do_c = True
+    do_h = True
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+def maybe_open(really, name, opt):
+    if really:
+        return open(name, opt)
+    else:
+        import StringIO
+        return StringIO.StringIO()
+
+fdef = maybe_open(do_c, c_file, 'w')
+fdecl = maybe_open(do_h, h_file, 'w')
+
+fdef.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor functions
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "%(header)s"
+''',
+                 header=basename(h_file)))
+
+fdecl.write(mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI visitor function
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-visit-core.h"
+#include "%(prefix)sqapi-types.h"
+''',
+                  prefix=prefix, guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    if expr.has_key('type'):
+        ret = generate_visit_struct(expr['type'], expr['data'])
+        ret += generate_visit_list(expr['type'], expr['data'])
+        fdef.write(ret)
+
+        ret = generate_declaration(expr['type'], expr['data'])
+        fdecl.write(ret)
+    elif expr.has_key('union'):
+        ret = generate_visit_union(expr['union'], expr['data'])
+        ret += generate_visit_list(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)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
diff --git a/tests/Makefile b/tests/Makefile
index 9675ba7..8bbac75 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -55,8 +55,8 @@ tests/test-qapi-types.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qapi-visit.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_visit.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qmp-commands.h tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 03/22] qapi: qapi-commands.py -> qapi_commands.py Michael Roth
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile              |    8 +-
 scripts/qapi-types.py |  304 -------------------------------------------------
 scripts/qapi_types.py |  304 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/Makefile        |    4 +-
 4 files changed, 310 insertions(+), 310 deletions(-)
 delete mode 100644 scripts/qapi-types.py
 create mode 100644 scripts/qapi_types.py

diff --git a/Makefile b/Makefile
index ea7174c..894ff2f 100644
--- a/Makefile
+++ b/Makefile
@@ -182,8 +182,8 @@ include $(SRC_PATH)/tests/Makefile
 endif
 
 qapi-generated/qga-qapi-types.c qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
 qapi-generated/qga-qapi-visit.c qapi-generated/qga-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
@@ -192,8 +192,8 @@ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
 
 qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
 qapi-visit.c qapi-visit.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
deleted file mode 100644
index 4a734f5..0000000
--- a/scripts/qapi-types.py
+++ /dev/null
@@ -1,304 +0,0 @@
-#
-# QAPI types generator
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-#  Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
-
-from ordereddict import OrderedDict
-from qapi import *
-import sys
-import os
-import getopt
-import errno
-
-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_enum_lookup(name, values):
-    ret = mcgen('''
-const char *%(name)s_lookup[] = {
-''',
-                         name=name)
-    i = 0
-    for value in values:
-        ret += mcgen('''
-    "%(value)s",
-''',
-                     value=value.lower())
-
-    ret += mcgen('''
-    NULL,
-};
-
-''')
-    return ret
-
-def generate_enum(name, values):
-    lookup_decl = mcgen('''
-extern const char *%(name)s_lookup[];
-''',
-                name=name)
-
-    enum_decl = mcgen('''
-typedef enum %(name)s
-{
-''',
-                name=name)
-
-    # append automatically generated _MAX value
-    enum_values = values + [ 'MAX' ]
-
-    i = 0
-    for value in enum_values:
-        enum_decl += mcgen('''
-    %(abbrev)s_%(value)s = %(i)d,
-''',
-                     abbrev=de_camel_case(name).upper(),
-                     value=c_fun(value).upper(),
-                     i=i)
-        i += 1
-
-    enum_decl += mcgen('''
-} %(name)s;
-''',
-                 name=name)
-
-    return lookup_decl + enum_decl
-
-def generate_union(name, typeinfo):
-    ret = mcgen('''
-struct %(name)s
-{
-    %(name)sKind kind;
-    union {
-        void *data;
-''',
-                name=name)
-
-    for key in typeinfo:
-        ret += mcgen('''
-        %(c_type)s %(c_name)s;
-''',
-                     c_type=c_type(typeinfo[key]),
-                     c_name=c_fun(key))
-
-    ret += mcgen('''
-    };
-};
-''')
-
-    return ret
-
-def generate_type_cleanup_decl(name):
-    ret = mcgen('''
-void qapi_free_%(type)s(%(c_type)s obj);
-''',
-                c_type=c_type(name),type=name)
-    return ret
-
-def generate_type_cleanup(name):
-    ret = mcgen('''
-void qapi_free_%(type)s(%(c_type)s obj)
-{
-    QapiDeallocVisitor *md;
-    Visitor *v;
-
-    if (!obj) {
-        return;
-    }
-
-    md = qapi_dealloc_visitor_new();
-    v = qapi_dealloc_get_visitor(md);
-    visit_type_%(type)s(v, &obj, NULL, NULL);
-    qapi_dealloc_visitor_cleanup(md);
-}
-''',
-                c_type=c_type(name),type=name)
-    return ret
-
-
-try:
-    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
-                                   ["source", "header", "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'
-
-do_c = False
-do_h = False
-
-for o, a in opts:
-    if o in ("-p", "--prefix"):
-        prefix = a
-    elif o in ("-o", "--output-dir"):
-        output_dir = a + "/"
-    elif o in ("-c", "--source"):
-        do_c = True
-    elif o in ("-h", "--header"):
-        do_h = True
-
-if not do_c and not do_h:
-    do_c = True
-    do_h = True
-
-c_file = output_dir + prefix + c_file
-h_file = output_dir + prefix + h_file
-
-try:
-    os.makedirs(output_dir)
-except os.error, e:
-    if e.errno != errno.EEXIST:
-        raise
-
-def maybe_open(really, name, opt):
-    if really:
-        return open(name, opt)
-    else:
-        import StringIO
-        return StringIO.StringIO()
-
-fdef = maybe_open(do_c, c_file, 'w')
-fdecl = maybe_open(do_h, h_file, 'w')
-
-fdef.write(mcgen('''
-/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-/*
- * deallocation functions for schema-defined QAPI types
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *  Michael Roth      <mdroth@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#include "qapi/qapi-dealloc-visitor.h"
-#include "%(prefix)sqapi-types.h"
-#include "%(prefix)sqapi-visit.h"
-
-''',             prefix=prefix))
-
-fdecl.write(mcgen('''
-/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-/*
- * schema-defined QAPI types
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#ifndef %(guard)s
-#define %(guard)s
-
-#include "qapi/qapi-types-core.h"
-''',
-                  guard=guardname(h_file)))
-
-exprs = parse_schema(sys.stdin)
-exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
-
-for expr in exprs:
-    ret = "\n"
-    if expr.has_key('type'):
-        ret += generate_fwd_struct(expr['type'], expr['data'])
-    elif expr.has_key('enum'):
-        ret += generate_enum(expr['enum'], expr['data'])
-        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
-    elif expr.has_key('union'):
-        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
-        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
-        fdef.write(generate_enum_lookup('%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'] + "List")
-        fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
-        ret += generate_type_cleanup_decl(expr['type'])
-        fdef.write(generate_type_cleanup(expr['type']) + "\n")
-    elif expr.has_key('union'):
-        ret += generate_union(expr['union'], expr['data'])
-        ret += generate_type_cleanup_decl(expr['union'] + "List")
-        fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
-        ret += generate_type_cleanup_decl(expr['union'])
-        fdef.write(generate_type_cleanup(expr['union']) + "\n")
-    else:
-        continue
-    fdecl.write(ret)
-
-fdecl.write('''
-#endif
-''')
-
-fdecl.flush()
-fdecl.close()
-
-fdef.flush()
-fdef.close()
diff --git a/scripts/qapi_types.py b/scripts/qapi_types.py
new file mode 100644
index 0000000..4a734f5
--- /dev/null
+++ b/scripts/qapi_types.py
@@ -0,0 +1,304 @@
+#
+# QAPI types generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+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_enum_lookup(name, values):
+    ret = mcgen('''
+const char *%(name)s_lookup[] = {
+''',
+                         name=name)
+    i = 0
+    for value in values:
+        ret += mcgen('''
+    "%(value)s",
+''',
+                     value=value.lower())
+
+    ret += mcgen('''
+    NULL,
+};
+
+''')
+    return ret
+
+def generate_enum(name, values):
+    lookup_decl = mcgen('''
+extern const char *%(name)s_lookup[];
+''',
+                name=name)
+
+    enum_decl = mcgen('''
+typedef enum %(name)s
+{
+''',
+                name=name)
+
+    # append automatically generated _MAX value
+    enum_values = values + [ 'MAX' ]
+
+    i = 0
+    for value in enum_values:
+        enum_decl += mcgen('''
+    %(abbrev)s_%(value)s = %(i)d,
+''',
+                     abbrev=de_camel_case(name).upper(),
+                     value=c_fun(value).upper(),
+                     i=i)
+        i += 1
+
+    enum_decl += mcgen('''
+} %(name)s;
+''',
+                 name=name)
+
+    return lookup_decl + enum_decl
+
+def generate_union(name, typeinfo):
+    ret = mcgen('''
+struct %(name)s
+{
+    %(name)sKind kind;
+    union {
+        void *data;
+''',
+                name=name)
+
+    for key in typeinfo:
+        ret += mcgen('''
+        %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(typeinfo[key]),
+                     c_name=c_fun(key))
+
+    ret += mcgen('''
+    };
+};
+''')
+
+    return ret
+
+def generate_type_cleanup_decl(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj);
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+def generate_type_cleanup(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj)
+{
+    QapiDeallocVisitor *md;
+    Visitor *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visitor_new();
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
+                                   ["source", "header", "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'
+
+do_c = False
+do_h = False
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+    elif o in ("-c", "--source"):
+        do_c = True
+    elif o in ("-h", "--header"):
+        do_h = True
+
+if not do_c and not do_h:
+    do_c = True
+    do_h = True
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+def maybe_open(really, name, opt):
+    if really:
+        return open(name, opt)
+    else:
+        import StringIO
+        return StringIO.StringIO()
+
+fdef = maybe_open(do_c, c_file, 'w')
+fdecl = maybe_open(do_h, h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * deallocation functions for schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',             prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI types
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-types-core.h"
+''',
+                  guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_fwd_struct(expr['type'], expr['data'])
+    elif expr.has_key('enum'):
+        ret += generate_enum(expr['enum'], expr['data'])
+        fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
+    elif expr.has_key('union'):
+        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+        fdef.write(generate_enum_lookup('%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'] + "List")
+        fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
+        ret += generate_type_cleanup_decl(expr['type'])
+        fdef.write(generate_type_cleanup(expr['type']) + "\n")
+    elif expr.has_key('union'):
+        ret += generate_union(expr['union'], expr['data'])
+        ret += generate_type_cleanup_decl(expr['union'] + "List")
+        fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
+        ret += generate_type_cleanup_decl(expr['union'])
+        fdef.write(generate_type_cleanup(expr['union']) + "\n")
+    else:
+        continue
+    fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
+
+fdef.flush()
+fdef.close()
diff --git a/tests/Makefile b/tests/Makefile
index 8bbac75..45b9334 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -52,8 +52,8 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools
 tests/test-iov$(EXESUF): tests/test-iov.o iov.o
 
 tests/test-qapi-types.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qapi-visit.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 03/22] qapi: qapi-commands.py -> qapi_commands.py
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module Michael Roth
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile                 |    8 +-
 scripts/qapi-commands.py |  476 ----------------------------------------------
 scripts/qapi_commands.py |  476 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/Makefile           |    4 +-
 4 files changed, 482 insertions(+), 482 deletions(-)
 delete mode 100644 scripts/qapi-commands.py
 create mode 100644 scripts/qapi_commands.py

diff --git a/Makefile b/Makefile
index 894ff2f..ea9537e 100644
--- a/Makefile
+++ b/Makefile
@@ -188,8 +188,8 @@ qapi-generated/qga-qapi-visit.c qapi-generated/qga-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
 qapi-generated/qga-qmp-commands.h qapi-generated/qga-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_commands.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
 
 qapi-types.c qapi-types.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_types.py
@@ -198,8 +198,8 @@ qapi-visit.c qapi-visit.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
 qmp-commands.h qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_commands.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
 
 QGALIB_OBJ=$(addprefix qapi-generated/, qga-qapi-types.o qga-qapi-visit.o qga-qmp-marshal.o)
 QGALIB_GEN=$(addprefix qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
deleted file mode 100644
index 9eed40e..0000000
--- a/scripts/qapi-commands.py
+++ /dev/null
@@ -1,476 +0,0 @@
-#
-# QAPI command marshaller generator
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-#  Anthony Liguori <aliguori@us.ibm.com>
-#  Michael Roth    <mdroth@linux.vnet.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPLv2.
-# See the COPYING.LIB file in the top-level directory.
-
-from ordereddict import OrderedDict
-from qapi import *
-import sys
-import os
-import getopt
-import errno
-
-def type_visitor(name):
-    if type(name) == list:
-        return 'visit_type_%sList' % name[0]
-    else:
-        return 'visit_type_%s' % name
-
-def generate_decl_enum(name, members, genlist=True):
-    return mcgen('''
-
-void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
-''',
-                 visitor=type_visitor(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_fun(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_fun(name), args=arglist, retval=retval).rstrip()
-    if ret_type:
-        ret += "\n" + mcgen(''''
-if (!error_is_set(errp)) {
-    %(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_fun(name)
-
-def gen_visitor_output_containers_decl(ret_type):
-    ret = ""
-    push_indent()
-    if ret_type:
-        ret += mcgen('''
-QmpOutputVisitor *mo;
-QapiDeallocVisitor *md;
-Visitor *v;
-''')
-    pop_indent()
-
-    return ret
-
-def gen_visitor_input_containers_decl(args):
-    ret = ""
-
-    push_indent()
-    if len(args) > 0:
-        ret += mcgen('''
-QmpInputVisitor *mi;
-QapiDeallocVisitor *md;
-Visitor *v;
-''')
-    pop_indent()
-
-    return ret.rstrip()
-
-def gen_visitor_input_vars_decl(args):
-    ret = ""
-    push_indent()
-    for argname, argtype, optional, structured in parse_args(args):
-        if optional:
-            ret += mcgen('''
-bool has_%(argname)s = false;
-''',
-                         argname=c_var(argname))
-        if c_type(argtype).endswith("*"):
-            ret += mcgen('''
-%(argtype)s %(argname)s = NULL;
-''',
-                         argname=c_var(argname), argtype=c_type(argtype))
-        else:
-            ret += mcgen('''
-%(argtype)s %(argname)s;
-''',
-                         argname=c_var(argname), argtype=c_type(argtype))
-
-    pop_indent()
-    return ret.rstrip()
-
-def gen_visitor_input_block(args, obj, dealloc=False):
-    ret = ""
-    if len(args) == 0:
-        return ret
-
-    push_indent()
-
-    if dealloc:
-        ret += mcgen('''
-md = qapi_dealloc_visitor_new();
-v = qapi_dealloc_get_visitor(md);
-''')
-    else:
-        ret += mcgen('''
-mi = qmp_input_visitor_new_strict(%(obj)s);
-v = qmp_input_get_visitor(mi);
-''',
-                     obj=obj)
-
-    for argname, argtype, optional, structured in parse_args(args):
-        if optional:
-            ret += mcgen('''
-visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
-if (has_%(c_name)s) {
-''',
-                         c_name=c_var(argname), name=argname)
-            push_indent()
-        ret += mcgen('''
-%(visitor)s(v, &%(c_name)s, "%(name)s", errp);
-''',
-                     c_name=c_var(argname), name=argname, argtype=argtype,
-                     visitor=type_visitor(argtype))
-        if optional:
-            pop_indent()
-            ret += mcgen('''
-}
-visit_end_optional(v, errp);
-''')
-
-    if dealloc:
-        ret += mcgen('''
-qapi_dealloc_visitor_cleanup(md);
-''')
-    else:
-        ret += mcgen('''
-qmp_input_visitor_cleanup(mi);
-''')
-    pop_indent()
-    return ret.rstrip()
-
-def gen_marshal_output(name, args, ret_type, middle_mode):
-    if not ret_type:
-        return ""
-
-    ret = mcgen('''
-static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
-{
-    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
-    QmpOutputVisitor *mo = qmp_output_visitor_new();
-    Visitor *v;
-
-    v = qmp_output_get_visitor(mo);
-    %(visitor)s(v, &ret_in, "unused", errp);
-    if (!error_is_set(errp)) {
-        *ret_out = qmp_output_get_qobject(mo);
-    }
-    qmp_output_visitor_cleanup(mo);
-    v = qapi_dealloc_get_visitor(md);
-    %(visitor)s(v, &ret_in, "unused", errp);
-    qapi_dealloc_visitor_cleanup(md);
-}
-''',
-                c_ret_type=c_type(ret_type), c_name=c_fun(name),
-                visitor=type_visitor(ret_type))
-
-    return ret
-
-def gen_marshal_input_decl(name, args, ret_type, middle_mode):
-    if middle_mode:
-        return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name)
-    else:
-        return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name)
-
-
-
-def gen_marshal_input(name, args, ret_type, middle_mode):
-    hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
-
-    ret = mcgen('''
-%(header)s
-{
-''',
-                header=hdr)
-
-    if middle_mode:
-        ret += mcgen('''
-    Error *local_err = NULL;
-    Error **errp = &local_err;
-    QDict *args = (QDict *)qdict;
-''')
-
-    if ret_type:
-        if c_type(ret_type).endswith("*"):
-            retval = "    %s retval = NULL;" % c_type(ret_type)
-        else:
-            retval = "    %s retval;" % c_type(ret_type)
-        ret += mcgen('''
-%(retval)s
-''',
-                     retval=retval)
-
-    if len(args) > 0:
-        ret += mcgen('''
-%(visitor_input_containers_decl)s
-%(visitor_input_vars_decl)s
-
-%(visitor_input_block)s
-
-''',
-                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
-                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
-                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
-    else:
-        ret += mcgen('''
-    (void)args;
-''')
-
-    ret += mcgen('''
-    if (error_is_set(errp)) {
-        goto out;
-    }
-%(sync_call)s
-''',
-                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
-    ret += mcgen('''
-
-out:
-''')
-    ret += mcgen('''
-%(visitor_input_block_cleanup)s
-''',
-                 visitor_input_block_cleanup=gen_visitor_input_block(args, None,
-                                                                     dealloc=True))
-
-    if middle_mode:
-        ret += mcgen('''
-
-    if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        return -1;
-    }
-    return 0;
-''')
-    else:
-        ret += mcgen('''
-    return;
-''')
-
-    ret += mcgen('''
-}
-''')
-
-    return ret
-
-def option_value_matches(opt, val, cmd):
-    if opt in cmd and cmd[opt] == val:
-        return True
-    return False
-
-def gen_registry(commands):
-    registry=""
-    push_indent()
-    for cmd in commands:
-        options = 'QCO_NO_OPTIONS'
-        if option_value_matches('success-response', 'no', cmd):
-            options = 'QCO_NO_SUCCESS_RESP'
-
-        registry += mcgen('''
-qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
-''',
-                     name=cmd['command'], c_name=c_fun(cmd['command']),
-                     opts=options)
-    pop_indent()
-    ret = mcgen('''
-static void qmp_init_marshal(void)
-{
-%(registry)s
-}
-
-qapi_init(qmp_init_marshal);
-''',
-                registry=registry.rstrip())
-    return ret
-
-def gen_command_decl_prologue(header, guard, prefix=""):
-    ret = mcgen('''
-/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-/*
- * schema-defined QAPI function prototypes
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#ifndef %(guard)s
-#define %(guard)s
-
-#include "%(prefix)sqapi-types.h"
-#include "error.h"
-
-''',
-                 header=basename(header), guard=guardname(header), prefix=prefix)
-    return ret
-
-def gen_command_def_prologue(prefix="", proxy=False):
-    ret = mcgen('''
-/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-/*
- * schema-defined QMP->QAPI command dispatch
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#include "qemu-objects.h"
-#include "qapi/qmp-core.h"
-#include "qapi/qapi-visit-core.h"
-#include "qapi/qmp-output-visitor.h"
-#include "qapi/qmp-input-visitor.h"
-#include "qapi/qapi-dealloc-visitor.h"
-#include "%(prefix)sqapi-types.h"
-#include "%(prefix)sqapi-visit.h"
-
-''',
-                prefix=prefix)
-    if not proxy:
-        ret += '#include "%sqmp-commands.h"' % prefix
-    return ret + "\n\n"
-
-
-try:
-    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m",
-                                   ["source", "header", "prefix=",
-                                    "output-dir=", "type=", "middle"])
-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'
-middle_mode = False
-
-do_c = False
-do_h = False
-
-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
-    elif o in ("-m", "--middle"):
-        middle_mode = True
-    elif o in ("-c", "--source"):
-        do_c = True
-    elif o in ("-h", "--header"):
-        do_h = True
-
-if not do_c and not do_h:
-    do_c = True
-    do_h = True
-
-c_file = output_dir + prefix + c_file
-h_file = output_dir + prefix + h_file
-
-def maybe_open(really, name, opt):
-    if really:
-        return open(name, opt)
-    else:
-        import StringIO
-        return StringIO.StringIO()
-
-try:
-    os.makedirs(output_dir)
-except os.error, e:
-    if e.errno != errno.EEXIST:
-        raise
-
-exprs = parse_schema(sys.stdin)
-commands = filter(lambda expr: expr.has_key('command'), exprs)
-commands = filter(lambda expr: not expr.has_key('gen'), commands)
-
-if dispatch_type == "sync":
-    fdecl = maybe_open(do_h, h_file, 'w')
-    fdef = maybe_open(do_c, 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, middle_mode) + "\n"
-            fdef.write(ret)
-
-        if middle_mode:
-            fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
-
-        ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
-        fdef.write(ret)
-
-    fdecl.write("\n#endif\n");
-
-    if not middle_mode:
-        ret = gen_registry(commands)
-        fdef.write(ret)
-
-    fdef.flush()
-    fdef.close()
-    fdecl.flush()
-    fdecl.close()
diff --git a/scripts/qapi_commands.py b/scripts/qapi_commands.py
new file mode 100644
index 0000000..9eed40e
--- /dev/null
+++ b/scripts/qapi_commands.py
@@ -0,0 +1,476 @@
+#
+# QAPI command marshaller generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+def type_visitor(name):
+    if type(name) == list:
+        return 'visit_type_%sList' % name[0]
+    else:
+        return 'visit_type_%s' % name
+
+def generate_decl_enum(name, members, genlist=True):
+    return mcgen('''
+
+void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+''',
+                 visitor=type_visitor(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_fun(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_fun(name), args=arglist, retval=retval).rstrip()
+    if ret_type:
+        ret += "\n" + mcgen(''''
+if (!error_is_set(errp)) {
+    %(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_fun(name)
+
+def gen_visitor_output_containers_decl(ret_type):
+    ret = ""
+    push_indent()
+    if ret_type:
+        ret += mcgen('''
+QmpOutputVisitor *mo;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret
+
+def gen_visitor_input_containers_decl(args):
+    ret = ""
+
+    push_indent()
+    if len(args) > 0:
+        ret += mcgen('''
+QmpInputVisitor *mi;
+QapiDeallocVisitor *md;
+Visitor *v;
+''')
+    pop_indent()
+
+    return ret.rstrip()
+
+def gen_visitor_input_vars_decl(args):
+    ret = ""
+    push_indent()
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+bool has_%(argname)s = false;
+''',
+                         argname=c_var(argname))
+        if c_type(argtype).endswith("*"):
+            ret += mcgen('''
+%(argtype)s %(argname)s = NULL;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+        else:
+            ret += mcgen('''
+%(argtype)s %(argname)s;
+''',
+                         argname=c_var(argname), argtype=c_type(argtype))
+
+    pop_indent()
+    return ret.rstrip()
+
+def gen_visitor_input_block(args, obj, dealloc=False):
+    ret = ""
+    if len(args) == 0:
+        return ret
+
+    push_indent()
+
+    if dealloc:
+        ret += mcgen('''
+md = qapi_dealloc_visitor_new();
+v = qapi_dealloc_get_visitor(md);
+''')
+    else:
+        ret += mcgen('''
+mi = qmp_input_visitor_new_strict(%(obj)s);
+v = qmp_input_get_visitor(mi);
+''',
+                     obj=obj)
+
+    for argname, argtype, optional, structured in parse_args(args):
+        if optional:
+            ret += mcgen('''
+visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
+if (has_%(c_name)s) {
+''',
+                         c_name=c_var(argname), name=argname)
+            push_indent()
+        ret += mcgen('''
+%(visitor)s(v, &%(c_name)s, "%(name)s", errp);
+''',
+                     c_name=c_var(argname), name=argname, argtype=argtype,
+                     visitor=type_visitor(argtype))
+        if optional:
+            pop_indent()
+            ret += mcgen('''
+}
+visit_end_optional(v, errp);
+''')
+
+    if dealloc:
+        ret += mcgen('''
+qapi_dealloc_visitor_cleanup(md);
+''')
+    else:
+        ret += mcgen('''
+qmp_input_visitor_cleanup(mi);
+''')
+    pop_indent()
+    return ret.rstrip()
+
+def gen_marshal_output(name, args, ret_type, middle_mode):
+    if not ret_type:
+        return ""
+
+    ret = mcgen('''
+static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
+{
+    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+    QmpOutputVisitor *mo = qmp_output_visitor_new();
+    Visitor *v;
+
+    v = qmp_output_get_visitor(mo);
+    %(visitor)s(v, &ret_in, "unused", errp);
+    if (!error_is_set(errp)) {
+        *ret_out = qmp_output_get_qobject(mo);
+    }
+    qmp_output_visitor_cleanup(mo);
+    v = qapi_dealloc_get_visitor(md);
+    %(visitor)s(v, &ret_in, "unused", errp);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_ret_type=c_type(ret_type), c_name=c_fun(name),
+                visitor=type_visitor(ret_type))
+
+    return ret
+
+def gen_marshal_input_decl(name, args, ret_type, middle_mode):
+    if middle_mode:
+        return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name)
+    else:
+        return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name)
+
+
+
+def gen_marshal_input(name, args, ret_type, middle_mode):
+    hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
+
+    ret = mcgen('''
+%(header)s
+{
+''',
+                header=hdr)
+
+    if middle_mode:
+        ret += mcgen('''
+    Error *local_err = NULL;
+    Error **errp = &local_err;
+    QDict *args = (QDict *)qdict;
+''')
+
+    if ret_type:
+        if c_type(ret_type).endswith("*"):
+            retval = "    %s retval = NULL;" % c_type(ret_type)
+        else:
+            retval = "    %s retval;" % c_type(ret_type)
+        ret += mcgen('''
+%(retval)s
+''',
+                     retval=retval)
+
+    if len(args) > 0:
+        ret += mcgen('''
+%(visitor_input_containers_decl)s
+%(visitor_input_vars_decl)s
+
+%(visitor_input_block)s
+
+''',
+                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
+                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
+                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
+    else:
+        ret += mcgen('''
+    (void)args;
+''')
+
+    ret += mcgen('''
+    if (error_is_set(errp)) {
+        goto out;
+    }
+%(sync_call)s
+''',
+                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
+    ret += mcgen('''
+
+out:
+''')
+    ret += mcgen('''
+%(visitor_input_block_cleanup)s
+''',
+                 visitor_input_block_cleanup=gen_visitor_input_block(args, None,
+                                                                     dealloc=True))
+
+    if middle_mode:
+        ret += mcgen('''
+
+    if (local_err) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+        return -1;
+    }
+    return 0;
+''')
+    else:
+        ret += mcgen('''
+    return;
+''')
+
+    ret += mcgen('''
+}
+''')
+
+    return ret
+
+def option_value_matches(opt, val, cmd):
+    if opt in cmd and cmd[opt] == val:
+        return True
+    return False
+
+def gen_registry(commands):
+    registry=""
+    push_indent()
+    for cmd in commands:
+        options = 'QCO_NO_OPTIONS'
+        if option_value_matches('success-response', 'no', cmd):
+            options = 'QCO_NO_SUCCESS_RESP'
+
+        registry += mcgen('''
+qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
+''',
+                     name=cmd['command'], c_name=c_fun(cmd['command']),
+                     opts=options)
+    pop_indent()
+    ret = mcgen('''
+static void qmp_init_marshal(void)
+{
+%(registry)s
+}
+
+qapi_init(qmp_init_marshal);
+''',
+                registry=registry.rstrip())
+    return ret
+
+def gen_command_decl_prologue(header, guard, prefix=""):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QAPI function prototypes
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "%(prefix)sqapi-types.h"
+#include "error.h"
+
+''',
+                 header=basename(header), guard=guardname(header), prefix=prefix)
+    return ret
+
+def gen_command_def_prologue(prefix="", proxy=False):
+    ret = mcgen('''
+/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * schema-defined QMP->QAPI command dispatch
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-objects.h"
+#include "qapi/qmp-core.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',
+                prefix=prefix)
+    if not proxy:
+        ret += '#include "%sqmp-commands.h"' % prefix
+    return ret + "\n\n"
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m",
+                                   ["source", "header", "prefix=",
+                                    "output-dir=", "type=", "middle"])
+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'
+middle_mode = False
+
+do_c = False
+do_h = False
+
+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
+    elif o in ("-m", "--middle"):
+        middle_mode = True
+    elif o in ("-c", "--source"):
+        do_c = True
+    elif o in ("-h", "--header"):
+        do_h = True
+
+if not do_c and not do_h:
+    do_c = True
+    do_h = True
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+def maybe_open(really, name, opt):
+    if really:
+        return open(name, opt)
+    else:
+        import StringIO
+        return StringIO.StringIO()
+
+try:
+    os.makedirs(output_dir)
+except os.error, e:
+    if e.errno != errno.EEXIST:
+        raise
+
+exprs = parse_schema(sys.stdin)
+commands = filter(lambda expr: expr.has_key('command'), exprs)
+commands = filter(lambda expr: not expr.has_key('gen'), commands)
+
+if dispatch_type == "sync":
+    fdecl = maybe_open(do_h, h_file, 'w')
+    fdef = maybe_open(do_c, 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, middle_mode) + "\n"
+            fdef.write(ret)
+
+        if middle_mode:
+            fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
+
+        ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
+        fdef.write(ret)
+
+    fdecl.write("\n#endif\n");
+
+    if not middle_mode:
+        ret = gen_registry(commands)
+        fdef.write(ret)
+
+    fdef.flush()
+    fdef.close()
+    fdecl.flush()
+    fdecl.close()
diff --git a/tests/Makefile b/tests/Makefile
index 45b9334..7cfd3d8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -58,8 +58,8 @@ tests/test-qapi-visit.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qmp-commands.h tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_commands.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 
 
 tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (2 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 03/22] qapi: qapi-commands.py -> qapi_commands.py Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:13   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions Michael Roth
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi_visit.py |  143 +++++++++++++++++++++++++------------------------
 1 file changed, 74 insertions(+), 69 deletions(-)

diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index 04ef7c4..25707f5 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -224,55 +224,57 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e
 ''',
                 name=name)
 
-try:
-    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
-                                   ["source", "header", "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'
-
-do_c = False
-do_h = False
-
-for o, a in opts:
-    if o in ("-p", "--prefix"):
-        prefix = a
-    elif o in ("-o", "--output-dir"):
-        output_dir = a + "/"
-    elif o in ("-c", "--source"):
+def main(argv=[]):
+    try:
+        opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
+                                       ["source", "header", "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'
+
+    do_c = False
+    do_h = False
+
+    for o, a in opts:
+        if o in ("-p", "--prefix"):
+            prefix = a
+        elif o in ("-o", "--output-dir"):
+            output_dir = a + "/"
+        elif o in ("-c", "--source"):
+            do_c = True
+        elif o in ("-h", "--header"):
+            do_h = True
+
+    if not do_c and not do_h:
         do_c = True
-    elif o in ("-h", "--header"):
         do_h = True
 
-if not do_c and not do_h:
-    do_c = True
-    do_h = True
+    c_file = output_dir + prefix + c_file
+    h_file = output_dir + prefix + h_file
 
-c_file = output_dir + prefix + c_file
-h_file = output_dir + prefix + h_file
+    try:
+        os.makedirs(output_dir)
+    except os.error, e:
+        if e.errno != errno.EEXIST:
+            raise
 
-try:
-    os.makedirs(output_dir)
-except os.error, e:
-    if e.errno != errno.EEXIST:
-        raise
-
-def maybe_open(really, name, opt):
-    if really:
-        return open(name, opt)
-    else:
-        import StringIO
-        return StringIO.StringIO()
+    def maybe_open(really, name, opt):
+        if really:
+            return open(name, opt)
+        else:
+            import StringIO
+            return StringIO.StringIO()
 
-fdef = maybe_open(do_c, c_file, 'w')
-fdecl = maybe_open(do_h, h_file, 'w')
+    fdef = maybe_open(do_c, c_file, 'w')
+    fdecl = maybe_open(do_h, h_file, 'w')
 
-fdef.write(mcgen('''
+    fdef.write(mcgen('''
 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
 
 /*
@@ -292,7 +294,7 @@ fdef.write(mcgen('''
 ''',
                  header=basename(h_file)))
 
-fdecl.write(mcgen('''
+    fdecl.write(mcgen('''
 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
 
 /*
@@ -316,37 +318,40 @@ fdecl.write(mcgen('''
 ''',
                   prefix=prefix, guard=guardname(h_file)))
 
-exprs = parse_schema(sys.stdin)
+    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)
+    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'])
-        ret += generate_visit_list(expr['union'], 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'])
+            ret += generate_visit_list(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('%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)
+            ret = generate_decl_enum(expr['enum'], expr['data'])
+            fdecl.write(ret)
 
-fdecl.write('''
+    fdecl.write('''
 #endif
-''')
+    ''')
+
+    fdecl.flush()
+    fdecl.close()
 
-fdecl.flush()
-fdecl.close()
+    fdef.flush()
+    fdef.close()
 
-fdef.flush()
-fdef.close()
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (3 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:16   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 06/22] qapi: add visitor interfaces for arrays Michael Roth
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

Add support for arrays in the code generators.

Complex field descriptions can now be used to provide additional
information to the visitor generators, such as the max size of an array,
or the field within a struct to use to determine how many elements are
present in the array to avoid serializing uninitialized elements.

Add handling for these in the code generators as well.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi.py          |   10 ++++++++--
 scripts/qapi_commands.py |    8 ++++----
 scripts/qapi_types.py    |    2 +-
 scripts/qapi_visit.py    |   34 +++++++++++++++++++++++++++-------
 4 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8082af3..39bb74e 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -99,12 +99,16 @@ def parse_args(typeinfo):
         argentry = typeinfo[member]
         optional = False
         structured = False
+        annotated = False
         if member.startswith('*'):
             argname = member[1:]
             optional = True
         if isinstance(argentry, OrderedDict):
-            structured = True
-        yield (argname, argentry, optional, structured)
+            if argentry.has_key('<annotated>'):
+                annotated = True
+            else:
+                structured = True
+        yield (argname, argentry, optional, structured, annotated)
 
 def de_camel_case(name):
     new_name = ''
@@ -177,6 +181,8 @@ def c_type(name):
         return 'void'
     elif name == name.upper():
         return '%sEvent *' % camel_case(name)
+    elif name.replace("u", "").replace("int", "") in ["8", "16", "32", "64"]:
+        return name + "_t"
     else:
         return '%s *' % name
 
diff --git a/scripts/qapi_commands.py b/scripts/qapi_commands.py
index 9eed40e..52221d6 100644
--- a/scripts/qapi_commands.py
+++ b/scripts/qapi_commands.py
@@ -32,7 +32,7 @@ void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
 
 def generate_command_decl(name, args, ret_type):
     arglist=""
-    for argname, argtype, optional, structured in parse_args(args):
+    for argname, argtype, optional, structured, annotated in parse_args(args):
         argtype = c_type(argtype)
         if argtype == "char *":
             argtype = "const char *"
@@ -50,7 +50,7 @@ def gen_sync_call(name, args, ret_type, indent=0):
     retval=""
     if ret_type:
         retval = "retval = "
-    for argname, argtype, optional, structured in parse_args(args):
+    for argname, argtype, optional, structured, annotated in parse_args(args):
         if optional:
             arglist += "has_%s, " % c_var(argname)
         arglist += "%s, " % (c_var(argname))
@@ -106,7 +106,7 @@ Visitor *v;
 def gen_visitor_input_vars_decl(args):
     ret = ""
     push_indent()
-    for argname, argtype, optional, structured in parse_args(args):
+    for argname, argtype, optional, structured, annotated in parse_args(args):
         if optional:
             ret += mcgen('''
 bool has_%(argname)s = false;
@@ -145,7 +145,7 @@ v = qmp_input_get_visitor(mi);
 ''',
                      obj=obj)
 
-    for argname, argtype, optional, structured in parse_args(args):
+    for argname, argtype, optional, structured, annotated in parse_args(args):
         if optional:
             ret += mcgen('''
 visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
diff --git a/scripts/qapi_types.py b/scripts/qapi_types.py
index 4a734f5..fb2b9ea 100644
--- a/scripts/qapi_types.py
+++ b/scripts/qapi_types.py
@@ -35,7 +35,7 @@ struct %(name)s
 ''',
           name=structname)
 
-    for argname, argentry, optional, structured in parse_args(members):
+    for argname, argentry, optional, structured, annotated in parse_args(members):
         if optional:
             ret += mcgen('''
     bool has_%(c_name)s;
diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index 25707f5..9839e3c 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -16,6 +16,22 @@ import sys
 import os
 import getopt
 import errno
+import types
+
+def generate_visit_array_body(name, info):
+    ret = mcgen('''
+visit_start_array(m, (void **)obj, "%(name)s", %(count)s, sizeof(%(type)s), errp);
+int %(name)s_i;
+for (%(name)s_i = 0; %(name)s_i < %(count)s; %(name)s_i++) {
+    visit_type_%(type_short)s(m, &(*obj)->%(name)s[%(name)s_i], NULL, errp);
+    visit_next_array(m, errp);
+}
+visit_end_array(m, errp);
+''',
+                name=name, type=c_type(info['type'][0]),
+                type_short=info['type'][0],
+                count=info['array_size'])
+    return ret
 
 def generate_visit_struct_body(field_prefix, name, members):
     ret = mcgen('''
@@ -45,10 +61,10 @@ if (!err) {
 
     push_indent()
     push_indent()
-    for argname, argentry, optional, structured in parse_args(members):
+    for argname, argentry, optional, structured, annotated in parse_args(members):
         if optional:
             ret += mcgen('''
-visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
+visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp);
 if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
 ''',
                          c_prefix=c_var(field_prefix), prefix=field_prefix,
@@ -58,12 +74,16 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
         if structured:
             ret += generate_visit_struct_body(field_prefix + argname, argname, argentry)
         else:
-            ret += mcgen('''
-visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
+            if annotated:
+                if isinstance(argentry['type'], types.ListType):
+                    ret += generate_visit_array_body(argname, argentry)
+            else:
+                ret += mcgen('''
+visit_type_%(type)s(m, 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)
+                             c_prefix=c_var(field_prefix), prefix=field_prefix,
+                             type=type_name(argentry), c_name=c_var(argname),
+                             name=argname)
 
         if optional:
             pop_indent()
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 06/22] qapi: add visitor interfaces for arrays
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (4 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:18   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support generating static functions Michael Roth
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qapi-visit-core.c |   25 +++++++++++++++++++++++++
 qapi/qapi-visit-core.h |    8 ++++++++
 scripts/qapi_visit.py  |   28 ++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 7a82b63..631387d 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -311,3 +311,28 @@ void input_type_enum(Visitor *v, int *obj, const char *strings[],
     g_free(enum_str);
     *obj = value;
 }
+
+void visit_start_array(Visitor *v, void **obj, const char *name,
+                       size_t elem_count, size_t elem_size, Error **errp)
+{
+    g_assert(v->start_array);
+    if (!error_is_set(errp)) {
+        v->start_array(v, obj, name, elem_count, elem_size, errp);
+    }
+}
+
+void visit_next_array(Visitor *v, Error **errp)
+{
+    g_assert(v->next_array);
+    if (!error_is_set(errp)) {
+        v->next_array(v, errp);
+    }
+}
+
+void visit_end_array(Visitor *v, Error **errp)
+{
+    g_assert(v->end_array);
+    if (!error_is_set(errp)) {
+        v->end_array(v, errp);
+    }
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
index 60aceda..4a7bdb6 100644
--- a/qapi/qapi-visit-core.h
+++ b/qapi/qapi-visit-core.h
@@ -43,6 +43,10 @@ struct Visitor
     void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
     void (*type_number)(Visitor *v, double *obj, const char *name,
                         Error **errp);
+    void (*start_array)(Visitor *v, void **obj, const char *name,
+                        size_t elem_count, size_t elem_size, Error **errp);
+    void (*next_array)(Visitor *v, Error **errp);
+    void (*end_array)(Visitor *v, Error **errp);
 
     /* May be NULL */
     void (*start_optional)(Visitor *v, bool *present, const char *name,
@@ -91,5 +95,9 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
 void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
 void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
 void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
+void visit_start_array(Visitor *v, void **obj, const char *name,
+                       size_t elem_count, size_t elem_size, Error **errp);
+void visit_next_array(Visitor *v, Error **errp);
+void visit_end_array(Visitor *v, Error **errp);
 
 #endif
diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index 9839e3c..bf93bfe 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -33,6 +33,34 @@ visit_end_array(m, errp);
                 count=info['array_size'])
     return ret
 
+def generate_visit_array_body(name, info):
+    if info['array_size'][0].isdigit():
+        array_size = info['array_size']
+    elif info['array_size'][0] == '(' and info['array_size'][-1] == ')':
+        array_size = info['array_size']
+    else:
+        array_size = "(*obj)->%s" % info['array_size']
+
+    if info.has_key('array_capacity'):
+        array_capacity = info['array_capacity']
+    else:
+        array_capacity = array_size
+
+    ret = mcgen('''
+visit_start_array(m, (void **)obj, "%(name)s", %(array_capacity)s, sizeof(%(type)s), errp);
+int %(name)s_i;
+for (%(name)s_i = 0; %(name)s_i < %(array_size)s; %(name)s_i++) {
+    visit_type_%(type_short)s(m, &(*obj)->%(name)s[%(name)s_i], NULL, errp);
+    visit_next_array(m, errp);
+}
+visit_end_array(m, errp);
+''',
+                name=name, type=c_type(info['type'][0]),
+                type_short=info['type'][0],
+                array_size=array_size,
+                array_capacity=array_capacity)
+    return ret
+
 def generate_visit_struct_body(field_prefix, name, members):
     ret = mcgen('''
 if (!error_is_set(errp)) {
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support generating static functions
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (5 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 06/22] qapi: add visitor interfaces for arrays Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:19   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 08/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs Michael Roth
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

qidl embeds visitor code into object files rather than linking against
seperate files, so allow for static declarations when we're using
qapi_visit.py as a library as we do with qidl.py

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi_visit.py |   51 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index bf93bfe..864acb2 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -139,13 +139,16 @@ visit_end_optional(m, &err);
 ''')
     return ret
 
-def generate_visit_struct(name, members):
+def generate_visit_struct(name, members, static=False):
+    ret_type = "void"
+    if static:
+        ret_type = "static " + ret_type
     ret = mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
 {
 ''',
-                name=name)
+                name=name, ret_type=ret_type)
 
     push_indent()
     ret += generate_visit_struct_body("", name, members)
@@ -156,10 +159,13 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
 ''')
     return ret
 
-def generate_visit_list(name, members):
+def generate_visit_list(name, members, static=False):
+    ret_type = "void"
+    if static:
+        ret_type = "static " + ret_type
     return mcgen('''
 
-void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
+%(ret_type)s visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
 {
     GenericList *i, **prev = (GenericList **)obj;
     Error *err = NULL;
@@ -181,19 +187,22 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name,
     }
 }
 ''',
-                name=name)
+                name=name, ret_type=ret_type)
 
-def generate_visit_enum(name, members):
+def generate_visit_enum(name, members, static=False):
+    ret_type = "void"
+    if static:
+        ret_type = "static " + ret_type
     return mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
 {
     visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
 }
 ''',
-                 name=name)
+                 name=name, ret_type=ret_type)
 
-def generate_visit_union(name, members):
+def generate_visit_union(name, members, static=False):
     ret = generate_visit_enum('%sKind' % name, members.keys())
 
     ret += mcgen('''
@@ -250,27 +259,33 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
 
     return ret
 
-def generate_declaration(name, members, genlist=True):
+def generate_declaration(name, members, genlist=True, static=False):
+    ret_type = "void"
+    if static:
+        ret_type = "static " + ret_type
     ret = mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
 ''',
-                name=name)
+                name=name, ret_type=ret_type)
 
     if genlist:
         ret += mcgen('''
-void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
+%(ret_type)s visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
 ''',
-                 name=name)
+                 name=name, ret_type=ret_type)
 
     return ret
 
-def generate_decl_enum(name, members, genlist=True):
+def generate_decl_enum(name, members, genlist=True, static=False):
+    ret_type = "void"
+    if static:
+        ret_type = "static " + ret_type
     return mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
 ''',
-                name=name)
+                name=name, ret_type=ret_type)
 
 def main(argv=[]):
     try:
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 08/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (6 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support generating static functions Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:21   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 09/22] qapi: QmpOutputVisitor, implement array handling Michael Roth
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi_visit.py |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
index 864acb2..8f8cdca 100644
--- a/scripts/qapi_visit.py
+++ b/scripts/qapi_visit.py
@@ -105,6 +105,15 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
             if annotated:
                 if isinstance(argentry['type'], types.ListType):
                     ret += generate_visit_array_body(argname, argentry)
+                elif argentry.has_key('<embedded struct>'):
+                    tmp_ptr_name = "%s_%s_ptr" % (c_var(field_prefix).replace(".", ""), c_var(argname))
+                    ret += mcgen('''
+%(type)s *%(tmp_ptr)s = &(*obj)->%(c_prefix)s%(c_name)s;
+visit_type_%(type)s(m, (obj && *obj) ? &%(tmp_ptr)s : NULL, "%(name)s", errp);
+''',
+                                 c_prefix=c_var(field_prefix), prefix=field_prefix,
+                                 type=type_name(argentry['type']), c_name=c_var(argname),
+                                 name=argname, tmp_ptr=tmp_ptr_name)
             else:
                 ret += mcgen('''
 visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp);
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 09/22] qapi: QmpOutputVisitor, implement array handling
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (7 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 08/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust Michael Roth
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/qmp-output-visitor.c |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index 2bce9d5..78e8ff4 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -181,6 +181,24 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
     qmp_output_add(qov, name, qfloat_from_double(*obj));
 }
 
+static void qmp_output_start_array(Visitor *v, void **obj, const char *name,
+                                   size_t elem_count, size_t elem_size,
+                                   Error **errp)
+{
+    qmp_output_start_list(v, name, errp);
+}
+
+
+static void qmp_output_next_array(Visitor *v, Error **errp)
+{
+}
+
+static void qmp_output_end_array(Visitor *v, Error **errp)
+{
+    QmpOutputVisitor *qov = to_qov(v);
+    qmp_output_pop(qov);
+}
+
 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
 {
     QObject *obj = qmp_output_first(qov);
@@ -228,6 +246,9 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
     v->visitor.type_bool = qmp_output_type_bool;
     v->visitor.type_str = qmp_output_type_str;
     v->visitor.type_number = qmp_output_type_number;
+    v->visitor.start_array = qmp_output_start_array;
+    v->visitor.next_array = qmp_output_next_array;
+    v->visitor.end_array = qmp_output_end_array;
 
     QTAILQ_INIT(&v->stack);
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (8 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 09/22] qapi: QmpOutputVisitor, implement array handling Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:23   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 11/22] qapi: add open-coded visitor for struct tm types Michael Roth
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

Currently the QAPI JSON parser expects a very particular style of code
indentation, the major one being that terminating curly/square brackets are
not on placed on a seperate line. This is incompatible with most
pretty-print formats, so make it a little more robust by supporting
these cases.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi.py |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 39bb74e..e0c694d 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -70,7 +70,7 @@ def parse_schema(fp):
         if line.startswith('#') or line == '\n':
             continue
 
-        if line.startswith(' '):
+        if line[0] in ['}', ']', ' ', '\t']:
             expr += line
         elif expr:
             expr_eval = evaluate(expr)
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 11/22] qapi: add open-coded visitor for struct tm types
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (9 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:24   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 12/22] qom-fuse: workaround for truncated properties > 4096 Michael Roth
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qapi/Makefile.objs     |    1 +
 qapi/misc-qapi-visit.c |   14 ++++++++++++++
 qapi/qapi-visit-core.h |    3 +++
 3 files changed, 18 insertions(+)
 create mode 100644 qapi/misc-qapi-visit.c

diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index 5f5846e..7604b52 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -1,3 +1,4 @@
 qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
 qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
 qapi-obj-y += string-input-visitor.o string-output-visitor.o opts-visitor.o
+qapi-obj-y += misc-qapi-visit.o
diff --git a/qapi/misc-qapi-visit.c b/qapi/misc-qapi-visit.c
new file mode 100644
index 0000000..a44773d
--- /dev/null
+++ b/qapi/misc-qapi-visit.c
@@ -0,0 +1,14 @@
+#include <time.h>
+#include "qidl.h"
+
+void visit_type_tm(Visitor *v, struct tm *obj, const char *name, Error **errp)
+{
+    visit_start_struct(v, NULL, "struct tm", name, 0, errp);
+    visit_type_int32(v, &obj->tm_year, "tm_year", errp);
+    visit_type_int32(v, &obj->tm_mon, "tm_mon", errp);
+    visit_type_int32(v, &obj->tm_mday, "tm_mday", errp);
+    visit_type_int32(v, &obj->tm_hour, "tm_hour", errp);
+    visit_type_int32(v, &obj->tm_min, "tm_min", errp);
+    visit_type_int32(v, &obj->tm_sec, "tm_sec", errp);
+    visit_end_struct(v, errp);
+}
diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
index 4a7bdb6..6af9f5e 100644
--- a/qapi/qapi-visit-core.h
+++ b/qapi/qapi-visit-core.h
@@ -100,4 +100,7 @@ void visit_start_array(Visitor *v, void **obj, const char *name,
 void visit_next_array(Visitor *v, Error **errp);
 void visit_end_array(Visitor *v, Error **errp);
 
+/* misc. visitors */
+void visit_type_tm(Visitor *m, struct tm *obj, const char *name, Error **errp);
+
 #endif
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 12/22] qom-fuse: workaround for truncated properties > 4096
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (10 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 11/22] qapi: add open-coded visitor for struct tm types Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:26   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 13/22] module additions for schema registration Michael Roth
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

We currently hard-code property size at 4096 for the purposes of
getattr()/stat()/etc. For 'state' properties we can exceed this easily,
leading to truncated responses.

Instead, for a particular property, make it
max(4096, most_recent_property_size * 2). This allows some
head-room for properties that change size periodically (numbers,
strings, state properties containing arrays, etc)

Also, implement a simple property cache to avoid spinning on qom-get
if an application reads beyond the actual size. This also allows us
to use a snapshot of a single qom-get that persists across read()'s.
Old Cache entries are evicted as soon as we attempt to read() from
offset 0 again.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 QMP/qom-fuse |   24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/QMP/qom-fuse b/QMP/qom-fuse
index 5c6754a..bd43f29 100755
--- a/QMP/qom-fuse
+++ b/QMP/qom-fuse
@@ -26,6 +26,7 @@ class QOMFS(Fuse):
         self.qmp.connect()
         self.ino_map = {}
         self.ino_count = 1
+        self.prop_cache = {}
 
     def get_ino(self, path):
         if self.ino_map.has_key(path):
@@ -67,12 +68,16 @@ class QOMFS(Fuse):
         if not self.is_property(path):
             return -ENOENT
 
-        path, prop = path.rsplit('/', 1)
-        try:
-            data = str(self.qmp.command('qom-get', path=path, property=prop))
-            data += '\n' # make values shell friendly
-        except:
-            return -EPERM
+        # avoid extra calls to qom-get by using cached value when offset > 0
+        if offset == 0 or not self.prop_cache.has_key(path):
+            directory, prop = path.rsplit('/', 1)
+            try:
+                resp = str(self.qmp.command('qom-get', path=directory, property=prop))
+                self.prop_cache[path] = resp + '\n' # make values shell friendly
+            except:
+                return -EPERM
+
+        data = self.prop_cache[path]
 
         if offset > len(data):
             return ''
@@ -111,13 +116,18 @@ class QOMFS(Fuse):
                                        0,
                                        0))
         elif self.is_property(path):
+            directory, prop = path.rsplit('/', 1)
+            try:
+                resp = str(self.qmp.command('qom-get', path=directory, property=prop))
+            except:
+                return -ENOENT
             value = posix.stat_result((0644 | stat.S_IFREG,
                                        self.get_ino(path),
                                        0,
                                        1,
                                        1000,
                                        1000,
-                                       4096,
+                                       max(len(resp) * 2, 4096),
                                        0,
                                        0,
                                        0))
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 13/22] module additions for schema registration
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (11 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 12/22] qom-fuse: workaround for truncated properties > 4096 Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 14/22] qdev: move Property-related declarations to qdev-properties.h Michael Roth
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


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

diff --git a/module.h b/module.h
index c4ccd57..cb81aa2 100644
--- a/module.h
+++ b/module.h
@@ -25,6 +25,7 @@ typedef enum {
     MODULE_INIT_MACHINE,
     MODULE_INIT_QAPI,
     MODULE_INIT_QOM,
+    MODULE_INIT_QIDL,
     MODULE_INIT_MAX
 } module_init_type;
 
@@ -32,6 +33,7 @@ typedef enum {
 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
 #define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
 #define type_init(function) module_init(function, MODULE_INIT_QOM)
+#define qidl_init(function) module_init(function, MODULE_INIT_QIDL)
 
 void register_module_init(void (*fn)(void), module_init_type type);
 
diff --git a/vl.c b/vl.c
index 8904db1..57ce033 100644
--- a/vl.c
+++ b/vl.c
@@ -2309,6 +2309,7 @@ int main(int argc, char **argv, char **envp)
     }
 
     module_call_init(MODULE_INIT_QOM);
+    module_call_init(MODULE_INIT_QIDL);
 
     runstate_init();
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 14/22] qdev: move Property-related declarations to qdev-properties.h
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (12 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 13/22] module additions for schema registration Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 22:28   ` Anthony Liguori
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 15/22] qidl: Add documentation Michael Roth
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hw/qdev-properties.h |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/qdev.h            |  126 +-----------------------------------------------
 2 files changed, 131 insertions(+), 125 deletions(-)
 create mode 100644 hw/qdev-properties.h

diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
new file mode 100644
index 0000000..329ef70
--- /dev/null
+++ b/hw/qdev-properties.h
@@ -0,0 +1,130 @@
+#ifndef QDEV_PROPERTIES_H
+#define QDEV_PROPERTIES_H
+
+#include "qemu/object.h"
+#include "qemu-queue.h"
+
+typedef struct Property Property;
+
+typedef struct PropertyInfo PropertyInfo;
+
+struct Property {
+    const char   *name;
+    PropertyInfo *info;
+    int          offset;
+    uint8_t      bitnr;
+    uint8_t      qtype;
+    int64_t      defval;
+};
+
+struct PropertyInfo {
+    const char *name;
+    const char *legacy_name;
+    const char **enum_table;
+    int (*parse)(DeviceState *dev, Property *prop, const char *str);
+    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
+    ObjectPropertyAccessor *get;
+    ObjectPropertyAccessor *set;
+    ObjectPropertyRelease *release;
+};
+
+typedef struct GlobalProperty {
+    const char *driver;
+    const char *property;
+    const char *value;
+    QTAILQ_ENTRY(GlobalProperty) next;
+} GlobalProperty;
+
+extern PropertyInfo qdev_prop_bit;
+extern PropertyInfo qdev_prop_uint8;
+extern PropertyInfo qdev_prop_uint16;
+extern PropertyInfo qdev_prop_uint32;
+extern PropertyInfo qdev_prop_int32;
+extern PropertyInfo qdev_prop_uint64;
+extern PropertyInfo qdev_prop_hex8;
+extern PropertyInfo qdev_prop_hex32;
+extern PropertyInfo qdev_prop_hex64;
+extern PropertyInfo qdev_prop_string;
+extern PropertyInfo qdev_prop_chr;
+extern PropertyInfo qdev_prop_ptr;
+extern PropertyInfo qdev_prop_macaddr;
+extern PropertyInfo qdev_prop_losttickpolicy;
+extern PropertyInfo qdev_prop_bios_chs_trans;
+extern PropertyInfo qdev_prop_drive;
+extern PropertyInfo qdev_prop_netdev;
+extern PropertyInfo qdev_prop_vlan;
+extern PropertyInfo qdev_prop_pci_devfn;
+extern PropertyInfo qdev_prop_blocksize;
+extern PropertyInfo qdev_prop_pci_host_devaddr;
+
+#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
+        .name      = (_name),                                    \
+        .info      = &(_prop),                                   \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(_type,typeof_field(_state, _field)),    \
+        }
+#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
+        .name      = (_name),                                           \
+        .info      = &(_prop),                                          \
+        .offset    = offsetof(_state, _field)                           \
+            + type_check(_type,typeof_field(_state, _field)),           \
+        .qtype     = QTYPE_QINT,                                        \
+        .defval    = (_type)_defval,                                    \
+        }
+#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
+        .name      = (_name),                                    \
+        .info      = &(qdev_prop_bit),                           \
+        .bitnr    = (_bit),                                      \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(uint32_t,typeof_field(_state, _field)), \
+        .qtype     = QTYPE_QBOOL,                                \
+        .defval    = (bool)_defval,                              \
+        }
+
+#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
+#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
+#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
+#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
+#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
+#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
+#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
+#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
+#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
+
+#define DEFINE_PROP_PTR(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
+#define DEFINE_PROP_CHR(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
+#define DEFINE_PROP_STRING(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
+#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
+#define DEFINE_PROP_VLAN(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
+#define DEFINE_PROP_DRIVE(_n, _s, _f) \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
+#define DEFINE_PROP_MACADDR(_n, _s, _f)         \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
+#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
+                        LostTickPolicy)
+#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
+#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
+#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
+
+#define DEFINE_PROP_END_OF_LIST()               \
+    {}
+
+#endif
diff --git a/hw/qdev.h b/hw/qdev.h
index a2cbd9d..c9b5453 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -8,10 +8,7 @@
 #include "qapi/qapi-visit-core.h"
 #include "qemu/object.h"
 #include "error.h"
-
-typedef struct Property Property;
-
-typedef struct PropertyInfo PropertyInfo;
+#include "qdev-properties.h"
 
 typedef struct CompatProperty CompatProperty;
 
@@ -122,33 +119,6 @@ struct BusState {
     QLIST_ENTRY(BusState) sibling;
 };
 
-struct Property {
-    const char   *name;
-    PropertyInfo *info;
-    int          offset;
-    uint8_t      bitnr;
-    uint8_t      qtype;
-    int64_t      defval;
-};
-
-struct PropertyInfo {
-    const char *name;
-    const char *legacy_name;
-    const char **enum_table;
-    int (*parse)(DeviceState *dev, Property *prop, const char *str);
-    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
-    ObjectPropertyAccessor *get;
-    ObjectPropertyAccessor *set;
-    ObjectPropertyRelease *release;
-};
-
-typedef struct GlobalProperty {
-    const char *driver;
-    const char *property;
-    const char *value;
-    QTAILQ_ENTRY(GlobalProperty) next;
-} GlobalProperty;
-
 /*** Board API.  This should go away once we have a machine config file.  ***/
 
 DeviceState *qdev_create(BusState *bus, const char *name);
@@ -215,100 +185,6 @@ void do_info_qdm(Monitor *mon);
 int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
-/*** qdev-properties.c ***/
-
-extern PropertyInfo qdev_prop_bit;
-extern PropertyInfo qdev_prop_uint8;
-extern PropertyInfo qdev_prop_uint16;
-extern PropertyInfo qdev_prop_uint32;
-extern PropertyInfo qdev_prop_int32;
-extern PropertyInfo qdev_prop_uint64;
-extern PropertyInfo qdev_prop_hex8;
-extern PropertyInfo qdev_prop_hex32;
-extern PropertyInfo qdev_prop_hex64;
-extern PropertyInfo qdev_prop_string;
-extern PropertyInfo qdev_prop_chr;
-extern PropertyInfo qdev_prop_ptr;
-extern PropertyInfo qdev_prop_macaddr;
-extern PropertyInfo qdev_prop_losttickpolicy;
-extern PropertyInfo qdev_prop_bios_chs_trans;
-extern PropertyInfo qdev_prop_drive;
-extern PropertyInfo qdev_prop_netdev;
-extern PropertyInfo qdev_prop_vlan;
-extern PropertyInfo qdev_prop_pci_devfn;
-extern PropertyInfo qdev_prop_blocksize;
-extern PropertyInfo qdev_prop_pci_host_devaddr;
-
-#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
-        .name      = (_name),                                    \
-        .info      = &(_prop),                                   \
-        .offset    = offsetof(_state, _field)                    \
-            + type_check(_type,typeof_field(_state, _field)),    \
-        }
-#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
-        .name      = (_name),                                           \
-        .info      = &(_prop),                                          \
-        .offset    = offsetof(_state, _field)                           \
-            + type_check(_type,typeof_field(_state, _field)),           \
-        .qtype     = QTYPE_QINT,                                        \
-        .defval    = (_type)_defval,                                    \
-        }
-#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
-        .name      = (_name),                                    \
-        .info      = &(qdev_prop_bit),                           \
-        .bitnr    = (_bit),                                      \
-        .offset    = offsetof(_state, _field)                    \
-            + type_check(uint32_t,typeof_field(_state, _field)), \
-        .qtype     = QTYPE_QBOOL,                                \
-        .defval    = (bool)_defval,                              \
-        }
-
-#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
-#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
-#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
-#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
-#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
-#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
-#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
-#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
-#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
-
-#define DEFINE_PROP_PTR(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
-#define DEFINE_PROP_CHR(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
-#define DEFINE_PROP_STRING(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
-#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
-#define DEFINE_PROP_VLAN(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
-#define DEFINE_PROP_DRIVE(_n, _s, _f) \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
-#define DEFINE_PROP_MACADDR(_n, _s, _f)         \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
-#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
-                        LostTickPolicy)
-#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
-#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
-#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
-
-#define DEFINE_PROP_END_OF_LIST()               \
-    {}
-
 /* Set properties between creation and init.  */
 void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
 int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 15/22] qidl: Add documentation
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (13 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 14/22] qdev: move Property-related declarations to qdev-properties.h Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 16/22] qidl: parser, initial import from qc.git Michael Roth
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 docs/qidl.txt |  331 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 331 insertions(+)
 create mode 100644 docs/qidl.txt

diff --git a/docs/qidl.txt b/docs/qidl.txt
new file mode 100644
index 0000000..30921b7
--- /dev/null
+++ b/docs/qidl.txt
@@ -0,0 +1,331 @@
+How to Serialize Device State with QIDL
+======================================
+
+This document describes how to implement save/restore of a device in QEMU using
+the QIDL compiler.  The QIDL compiler makes it easier to support live
+migration in devices by converging the serialization description with the
+device type declaration.  It has the following features:
+
+ 1. Single description of device state and how to serialize
+
+ 2. Fully inclusive serialization description--fields that aren't serialized
+    are explicitly marked as such including the reason why.
+
+ 3. Optimized for the common case.  Even without any special annotations,
+    many devices will Just Work out of the box.
+
+ 4. Build time schema definition.  Since QIDL runs at build time, we have full
+    access to the schema during the build which means we can fail the build if
+    the schema breaks.
+
+For the rest, of the document, the following simple device will be used as an
+example.
+
+    typedef struct SerialDevice {
+        SysBusDevice parent;
+    
+        uint8_t thr;            // transmit holding register
+        uint8_t lsr;            // line status register
+        uint8_t ier;            // interrupt enable register
+    
+        int int_pending;        // whether we have a pending queued interrupt
+        CharDriverState *chr;   // backend
+    } SerialDevice;
+
+Getting Started
+---------------
+
+The first step is to move your device struct definition to a header file.  This
+header file should only contain the struct definition and any preprocessor
+declarations you need to define the structure.  This header file will act as
+the source for the QIDL compiler.
+
+Do not include any function declarations in this header file as QIDL does not
+understand function declarations.
+
+Determining What State Gets Saved
+---------------------------------
+
+By default, QIDL saves every field in a structure it sees.  This provides maximum
+correctness by default.  However, device structures generally contain state
+that reflects state that is in someway duplicated or not guest visible.  This
+more often that not reflects design implementation details.
+
+Since design implementation details change over time, saving this state makes
+compatibility hard to maintain since it would effectively lock down a device's
+implementation.
+
+QIDL allows a device author to suppress certain fields from being saved although
+there are very strict rules about when this is allowed and what needs to be done
+to ensure that this does not impact correctness.
+
+There are three cases where state can be suppressed: when it is **immutable**,
+**derived**, or **broken**.  In addition, QIDL can decide at run time whether to
+suppress a field by assigning it a **default** value.
+
+## Immutable Fields
+
+If a field is only set during device construction, based on parameters passed to
+the device's constructor, then there is no need to send save and restore this
+value.  We call these fields immutable and we tell QIDL about this fact by using
+a **immutable** marker.
+
+In our *SerialDevice* example, the *CharDriverState* pointer reflects the host
+backend that we use to send serial output to the user.  This is only assigned
+during device construction and never changes.  This means we can add an
+**immutable** marker to it:
+
+    typedef struct SerialDevice {
+        SysBusDevice parent;
+    
+        uint8_t thr;            // transmit holding register
+        uint8_t lsr;            // line status register
+        uint8_t ier;            // interrupt enable register
+    
+        int int_pending;        // whether we have a pending queued interrupt
+        CharDriverState *chr QIDL(immutable);
+    } SerialDevice;
+
+When reviewing patches that make use of the **immutable** marker, the following
+guidelines should be followed to determine if the marker is being used
+correctly.
+
+ 1. Check to see if the field is assigned anywhere other than the device
+    initialization function.
+
+ 2. Check to see if any function is being called that modifies the state of the
+    field outside of the initialization function.
+
+It can be subtle whether a field is truly immutable.  A good example is a
+*QEMUTimer*.  Timer's will usually have their timeout modified with a call to
+*qemu_mod_timer()* even though they are only assigned in the device
+initialization function.
+
+If the timer is always modified with a fixed value that is not dependent on
+guest state, then the timer is immutable since it's unaffected by the state of
+the guest.
+
+On the other hand, if the timer is modified based on guest state (such as a
+guest programmed time out), then the timer carries state.  It may be necessary
+to save/restore the timer or mark it as **derived** and work with it
+accordingly.
+
+### Derived Fields
+
+If a field is set based on some other field in the device's structure, then its
+value is derived.  Since this is effectively duplicate state, we can avoid
+sending it and then recompute it when we need to.  Derived state requires a bit
+more handling that immutable state.
+
+In our *SerialDevice* example, our *int_pending* flag is really derived from
+two pieces of state.  It is set based on whether interrupts are enabled in the
+*ier* register and whether there is *THRE* flag is not set in the *lsr*
+register.
+
+To mark a field as derived, use the **derived** marker.  To update our
+example, we would do:
+
+    typedef struct SerialDevice {
+        SysBusDevice parent;
+    
+        uint8_t thr;            // transmit holding register
+        uint8_t lsr;            // line status register
+        uint8_t ier;            // interrupt enable register
+    
+        int _derived int_pending; // whether we have a pending queued interrupt
+        CharDriverState *chr QIDL(immutable);
+    } SerialDevice;
+
+There is one other critical step needed when marking a field as derived.  A
+*post_load* function must be added that updates this field after loading the
+rest of the device state.  This function is implemented in the device's source
+file, not in the QIDL header.  Below is an example of what this function may do:
+
+    static void serial_post_load(SerialDevice *s)
+    {
+        s->int_pending = !(s->lsr & THRE) && (s->ier & INTE);
+    }
+
+When reviewing a patch that marks a field as *derived*, the following criteria
+should be used:
+
+ 1. Does the device have a post load function?
+
+ 2. Does the post load function assign a value to all of the derived fields?
+
+ 3. Are there any obvious places where a derived field is holding unique state?
+
+### Broken State
+
+QEMU does migration with a lot of devices today.  When applying this methodology
+to these devices, one will quickly discover that there are a lot of fields that
+are not being saved today that are not derived or immutable state.
+
+These are all bugs.  It just so happens that these bugs are usually not very
+serious.  In many cases, they cause small functionality glitches that so far
+have not created any problems.
+
+Consider our *SerialDevice* example.  In QEMU's real *SerialState* device, the
+*thr* register is not saved yet we have not marked it immutable or derived.
+
+The *thr* register is a temporary holding register that the next character to
+transmit is placed in while we wait for the next baud cycle.  In QEMU, we
+emulate a very fast baud rate regardless of what guest programs.  This means
+that the contents of the *thr* register only matter for a very small period of
+time (measured in microseconds).
+
+The likelihood of a migration converging in that very small period of time when
+the *thr* register has a meaningful value is very small.  Moreover, the worst
+thing that can happen by not saving this register is that we lose a byte in the
+data stream.  Even if this has happened in practice, the chances of someone
+noticing this as a bug is pretty small.
+
+Nonetheless, this is a bug and needs to be eventually fixed.  However, it would
+be very inconvenient to constantly break migration by fixing all of these bugs
+one-by-one.  Instead, QIDL has a **broken** marker.  This indicates that a field
+is not currently saved, but should be in the future.
+
+The idea behind the broken marker is that we can convert a large number of
+devices without breaking migration compatibility, and then institute a flag day
+where we go through and remove broken markers en-mass.
+
+Below is an update of our example to reflect our real life serial device:
+
+    typedef struct SerialDevice {
+        SysBusDevice parent;
+    
+        uint8_t thr QIDL(broken);    // transmit holding register
+        uint8_t lsr;            // line status register
+        uint8_t ier;            // interrupt enable register
+    
+        int _derived int_pending; // whether we have a pending queued interrupt
+        CharDriverState _immutable *chr;
+    } SerialDevice;
+
+When reviewing the use of the broken marker, the following things should be
+considered:
+
+ 1. What are the ramifications of not sending this data field?
+
+ 2. If the not sending this data field can cause data corruption or very poor
+    behavior within the guest, the broken marker is not appropriate to use.
+
+ 3. Assigning a default value to a field can also be used to fix a broken field
+    without significantly impacting live migration compatibility.
+
+### Default Values
+
+In many cases, a field that gets marked broken was not originally saved because
+in the vast majority of the time, the field does not contain a meaningful value.
+
+In the case of our *thr* example, the field usually does not have a meaningful
+value.
+
+Instead of always saving the field, QIDL has another mechanism that allows the
+field to be saved only when it has a meaningful value.  This is done using the
+**default** marker.  The default marker tells QIDL that if the field currently
+has a specific value, do not save the value as part of serialization.
+
+When loading a field, QIDL will assign the default value to the field before it
+tries to load the field.  If the field cannot be loaded, QIDL will ignore the
+error and rely on the default value.
+
+Using default values, we can fix broken fields while also minimizing the cases
+where we break live migration compatibility.  The **default** marker can be
+used in conjunction with the **broken** marker.  We can extend our example as
+follows:
+
+    typedef struct SerialDevice {
+        SysBusDevice parent;
+    
+        
+        uint8_t thr QIDL(default, 0); // transmit holding register
+        uint8_t lsr;             // line status register
+        uint8_t ier;             // interrupt enable register
+    
+        int _derived int_pending; // whether we have a pending queued interrupt
+        CharDriverState _immutable *chr;
+    } SerialDevice;
+
+The following guidelines should be followed when using a default marker:
+
+ 1. Is the field set to the default value both during device initialization and
+    whenever the field is no longer in use?
+
+ 2. If the non-default value is expected to occur often, then consider using the
+    **broken** marker along with the default marker and using a flag day to
+    remove the **broken** marker.
+
+ 3. In general, setting default values as the value during device initialization
+    is a good idea even if the field was never broken.  This gives us maximum
+    flexibility in the long term.
+
+ 4. Never change a default value without renaming a field.  The default value is
+    part of the device's ABI.
+
+The first guideline is particularly important.  In the case of QEMU's real
+*SerialDevice*, it would be necessary to add code to set the *thr* register to
+zero after the byte has been successfully transmitted.  Otherwise, it is
+unlikely that it would ever contain the default value.
+
+Arrays
+------
+
+QIDL has support for multiple types of arrays.  The following sections describe
+the different rules for arrays.
+
+Fixed Sized Arrays
+------------------
+
+A fixed sized array has a size that is known at build time.  A typical example
+would be:
+
+    struct SerialFIFO {
+        uint8_t data[UART_FIFO_LENGTH];
+        uint8_t count;
+        uint8_t itl;
+        uint8_t tail;
+        uint8_t head;
+    };
+
+In this example, *data* is a fixed sized array.  No special annotation is needed
+for QIDL to marshal this area correctly.  The following guidelines apply to
+fixed sized arrays:
+
+ 1. The size of the array is part of the device ABI.  It should not change
+    without renaming the field.
+
+Variable Sized, Fixed Capacity Arrays
+-------------------------------------
+
+Sometimes it's desirable to have a variable sized array.  QIDL currently supported
+variable sized arrays provided that the maximum capacity is fixed and part of
+the device structure memory.
+
+A typical example would be a slightly modified version of our above example:
+
+    struct SerialFIFO {
+        uint8_t count;
+        uint8_t data[UART_FIFO_LENGTH] QIDL(size_is, count);
+        uint8_t itl;
+        uint8_t tail;
+        uint8_t head;
+    };
+
+In this example, *data* is a variable sized array with a fixed capacity of
+*UART_FIFO_LENGTH*.  When we serialize, we want only want to serialize *count*
+members.
+
+The ABI implications of capacity are a bit more relaxed with variable sized
+arrays.  In general, you can increase or decrease the capacity without breaking
+the ABI although you may cause some instances of migration to fail between
+versions of QEMU with different capacities.
+
+When reviewing variable sized, fixed capacity arrays, keep the following things
+in mind:
+
+ 1. The variable size must occur before the array element in the state
+    structure.
+
+ 2. The capacity can change without breaking the ABI, but care should be used
+    when making these types of changes.
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 16/22] qidl: parser, initial import from qc.git
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (14 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 15/22] qidl: Add documentation Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 17/22] qidl: codegen, initial commit Michael Roth
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qidl_parser.py |  503 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 503 insertions(+)
 create mode 100644 scripts/qidl_parser.py

diff --git a/scripts/qidl_parser.py b/scripts/qidl_parser.py
new file mode 100644
index 0000000..4cd248b
--- /dev/null
+++ b/scripts/qidl_parser.py
@@ -0,0 +1,503 @@
+#
+# QEMU IDL Parser
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING file in the top-level directory.
+#
+# The lexer code is based off of:
+#   http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+import sys, json
+
+class Input(object):
+    def __init__(self, text):
+        self.fp = text
+        self.buf = text
+        self.eof = False
+
+    def pop(self):
+        if len(self.buf) == 0:
+            self.eof = True
+            return ''
+        ch = self.buf[0]
+        self.buf = self.buf[1:]
+        return ch
+
+def in_range(ch, start, end):
+    if ch >= start and ch <= end:
+        return True
+    return False
+
+# D			[0-9]
+# L			[a-zA-Z_]
+# H			[a-fA-F0-9]
+# E			[Ee][+-]?{D}+
+# FS			(f|F|l|L)
+# IS			(u|U|l|L)*
+
+def is_D(ch):
+    return in_range(ch, '0', '9')
+
+def is_L(ch):
+    return in_range(ch, 'a', 'z') or in_range(ch, 'A', 'Z') or ch == '_'
+
+def is_H(ch):
+    return in_range(ch, 'a', 'f') or in_range(ch, 'A', 'F') or is_D(ch)
+
+def is_FS(ch):
+    return ch in 'fFlL'
+
+def is_IS(ch):
+    return ch in 'uUlL'
+
+def lexer(fp):
+    ch = fp.pop()
+
+    while not fp.eof:
+        token = ''
+
+        if is_L(ch):
+            token += ch
+
+            ch = fp.pop()
+            while is_L(ch) or is_D(ch):
+                token += ch
+                ch = fp.pop()
+            if token in [ 'auto', 'break', 'case', 'const', 'continue',
+                           'default', 'do', 'else', 'enum', 'extern',
+                           'for', 'goto', 'if', 'register', 'return', 'signed',
+                           'sizeof',
+                           'static', 'struct', 'typedef', 'union', 'unsigned',
+                           'volatile', 'while' ]:
+                yield (token, token)
+            else:
+                yield ('symbol', token)
+        elif ch == "'":
+            token += ch
+
+            ch = fp.pop()
+            if ch == '\\':
+                token += ch
+                token += fp.pop()
+            else:
+                token += ch
+            token += fp.pop()
+            ch = fp.pop()
+            yield ('literal', token)
+        elif ch == '"':
+            token += ch
+
+            ch = fp.pop()
+            while ch not in ['', '"']:
+                token += ch
+                if ch == '\\':
+                    token += fp.pop()
+                ch = fp.pop()
+            token += ch
+            yield ('literal', token)
+            ch = fp.pop()
+        elif ch in '.><+-*/%&^|!;{},:=()[]~?':
+            token += ch
+            ch = fp.pop()
+            tmp_token = token + ch
+            if tmp_token in ['<:']:
+                yield ('operator', '[')
+                ch = fp.pop()
+            elif tmp_token in [':>']:
+                yield ('operator', ']')
+                ch = fp.pop()
+            elif tmp_token in ['<%']:
+                yield ('operator', '{')
+                ch = fp.pop()
+            elif tmp_token in ['%>']:
+                yield ('operator', '}')
+                ch = fp.pop()
+            elif tmp_token == '//':
+                token = tmp_token
+                ch = fp.pop()
+                while ch != '\n' and ch != '':
+                    token += ch
+                    ch = fp.pop()
+                yield ('comment', token)
+            elif tmp_token == '/*':
+                token = tmp_token
+
+                ch = fp.pop()
+                while True:
+                    while ch != '*':
+                        token += ch
+                        ch = fp.pop()
+                    token += ch
+                    ch = fp.pop()
+                    if ch == '/':
+                        token += ch
+                        break
+                yield ('comment', token)
+                ch = fp.pop()
+            elif tmp_token in [ '+=', '-=', '*=', '/=', '%=', '&=', '^=',
+                                '|=', '>>', '<<', '++', '--', '->', '&&',
+                                '||', '<=', '>=', '==', '!=' ]:
+                yield ('operator', tmp_token)
+                ch = fp.pop()
+            else:
+                yield ('operator', token)
+        elif ch == '0':
+            token += ch
+            ch = fp.pop()
+            if ch in 'xX':
+                token += ch
+                ch = fp.pop()
+                while is_H(ch):
+                    token += ch
+                    ch = fp.pop()
+                while is_IS(ch):
+                    token += ch
+                    ch = fp.pop()
+            elif is_D(ch):
+                token += ch
+                ch = fp.pop()
+                while is_D(ch):
+                    token += ch
+                    ch = fp.pop()
+            yield ('literal', token)
+        elif is_D(ch):
+            token += ch
+            ch = fp.pop()
+            while is_D(ch):
+                token += ch
+                ch = fp.pop()
+            yield ('literal', token)
+        elif ch in ' \t\v\n\f':
+            token += ch
+            ch = fp.pop()
+            while len(ch) and ch in ' \t\v\n\f':
+                token += ch
+                ch = fp.pop()
+            yield ('whitespace', token)
+        elif ch in '#':
+            token += ch
+            ch = fp.pop()
+            while len(ch) and ch != '\n':
+                token += ch
+                ch = fp.pop()
+            yield ('directive', token)
+        else:
+            yield ('unknown', ch)
+            ch = fp.pop()
+
+class LookAhead(object):
+    def __init__(self, container):
+        self.i = container.__iter__()
+        self.la = []
+        self.full = False
+
+    def at(self, i):
+        if i >= len(self.la):
+            if self.full:
+                raise StopIteration()
+            else:
+                try:
+                    self.la.append(self.i.next())
+                except StopIteration, e:
+                    self.full = True
+                    raise StopIteration()
+
+        return self.la[i]
+
+    def eof(self):
+        try:
+            self.at(len(self.la))
+        except StopIteration, e:
+            return True
+
+        return False
+
+def skip(c):
+    for token, value in c:
+        if token in ['whitespace', 'comment', 'directive']:
+            continue
+        yield (token, value)
+
+def expect(la, index, first, second=None):
+    if la.at(index)[0] != first:
+        raise Exception("expected '%s', got %s %s" % (first, la.at(index)[0], la.at(index)[1]))
+    if second != None:
+        if la.at(index)[1] != second:
+            raise Exception("expected '%s', got %s" % (second, la.at(index)[1]))
+    return index + 1, la.at(index)[1]
+
+def choice(la, index, first, second=None):
+    if la.at(index)[0] != first:
+        return False
+    if second != None:
+        if la.at(index)[1] != second:
+            return False
+    return True
+
+def process_marker(ret, params):
+    marker_type = params[0]
+    if marker_type == "derived":
+        ret['is_derived'] = True
+    elif marker_type == 'immutable':
+        ret['is_immutable'] = True
+    elif marker_type == 'broken':
+        ret['is_broken'] = True
+    elif marker_type == 'size_is':
+        ret['is_array'] = True
+        ret['array_size'] = params[1]
+    elif marker_type == 'optional':
+        ret['is_optional'] = True
+    elif marker_type == 'property':
+        ret['is_property'] = True
+        ret['property_fields'] = params[1:]
+
+    return ret
+
+def parse_markers(la, index, ret):
+    next = index
+
+    while choice(la, next, 'symbol', 'QIDL'):
+        params = []
+        next += 1
+
+        next, _ = expect(la, next, 'operator', '(')
+        open_parens = 1
+        param = ""
+        while open_parens:
+            if choice(la, next, 'operator', ','):
+                params.append(param)
+                param = ""
+                next += 1
+                continue
+
+            if choice(la, next, 'operator', '('):
+                open_parens += 1
+            elif choice(la, next, 'operator', ')'):
+                open_parens -= 1
+
+            if open_parens > 0:
+                param += la.at(next)[1]
+            next += 1
+        if param != "":
+            params.append(param)
+
+        ret = process_marker(ret, params)
+
+    return (next - index), ret
+
+def parse_type(la, index):
+    next = index
+    ret = {}
+
+    typename = ''
+    if choice(la, next, 'const', 'const'):
+        typename += 'const '
+        next += 1
+
+    if choice(la, next, 'struct', 'struct'):
+        typename += 'struct '
+        next += 1
+
+    if choice(la, next, 'unsigned', 'unsigned'):
+        typename += 'unsigned '
+        next += 1
+
+    if choice(la, next, 'union', 'union'):
+        typename += 'union '
+        next += 1
+
+    if choice(la, next, 'enum', 'enum'):
+        typename += 'enum '
+        next += 1
+
+    # we don't currently handle embedded struct declarations, skip them for now
+    if choice(la, next, 'operator', '{'):
+        open_braces = 1
+        while open_braces:
+            next += 1
+            if choice(la, next, 'operator', '{'):
+                open_braces += 1
+            elif choice(la, next, 'operator', '}'):
+                open_braces -= 1
+        next += 1
+        typename += "<anon>"
+        ret['is_nested_decl'] = True
+    else:
+        next, rest = expect(la, next, 'symbol')
+        typename += rest
+
+    ret['type'] = typename
+
+    off, ret = parse_markers(la, next, ret)
+    next += off
+
+    if choice(la, next, 'operator', '*'):
+        next += 1
+        ret['is_pointer'] = True
+
+    return (next - index), ret
+
+def parse_var_decl(la, index, repeating_type=None):
+    next = index
+
+    if repeating_type == None:
+        off, ret = parse_type(la, next)
+        next += off
+    else:
+        ret = { 'type': repeating_type }
+
+    if choice(la, next, 'operator', '('):
+        ret['is_function'] = True
+        next += 1
+        next, _ = expect(la, next, 'operator', '*')
+        next, variable = expect(la, next, 'symbol')
+        next, _ = expect(la, next, 'operator', ')')
+
+        # skip the param list since we don't use it currently
+        next, _ = expect(la, next, 'operator', '(')
+        open_parens = 1
+        while open_parens:
+            if choice(la, next, 'operator', '('):
+                open_parens += 1
+            elif choice(la, next, 'operator', ')'):
+                open_parens -= 1
+            next += 1
+    else:
+        next, variable = expect(la, next, 'symbol')
+    ret['variable'] = variable
+
+    if choice(la, next, 'operator', '['):
+        next += 1
+        expression = ""
+        while not choice(la, next, 'operator', ']'):
+            expression += la.at(next)[1]
+            next += 1
+        next, _ = expect(la, next, 'operator', ']')
+
+        if not ret.has_key('is_array'):
+            ret['is_array'] = True
+            ret['array_size'] = expression
+        else:
+            ret['array_capacity'] = expression
+
+    off, ret = parse_markers(la, next, ret)
+    next += off
+
+    return (next - index), ret
+
+def parse_struct(la, index):
+    next = index
+
+    next, _ = expect(la, next, 'struct', 'struct')
+
+    name = None
+    if choice(la, next, 'symbol'):
+        name = la.at(next)[1]
+        next += 1
+
+    next, _ = expect(la, next, 'operator', '{')
+
+    nodes = []
+
+    while not choice(la, next, 'operator', '}'):
+        offset, node = parse_var_decl(la, next)
+        next += offset
+        nodes.append(node)
+        while choice(la, next, 'operator', ','):
+            next += 1
+            offset, node = parse_var_decl(la, next, node['type'])
+            next += offset
+            nodes.append(node)
+
+        next, _ = expect(la, next, 'operator', ';')
+
+    next += 1
+
+    return (next - index), { 'struct': name, 'fields': nodes }
+
+def parse_typedef(la, index):
+    next = index
+
+    next, _ = expect(la, next, 'typedef', 'typedef')
+
+    offset, node = parse_struct(la, next)
+    next += offset
+
+    next, typename = expect(la, next, 'symbol')
+
+    return (next - index), { 'typedef': typename, 'type': node }
+
+def parse(la, index=0):
+    next = index
+
+    if choice(la, next, 'typedef'):
+        offset, node = parse_typedef(la, next)
+    elif choice(la, next, 'struct'):
+        offset, node = parse_struct(la, next)
+    else:
+        raise Exception("unsupported QIDL declaration")
+
+    next, _ = expect(la, next + offset, 'operator', ';')
+
+    return (next - index), node
+
+def process_declaration_params(params, declaration={}):
+    declaration['id'] = params[0]
+    declaration['do_state'] = False
+    declaration['do_properties'] = False
+    if "state" in params:
+        declaration['do_state'] = True
+    if "properties" in params:
+        declaration['do_properties'] = True
+    return declaration
+
+def get_declaration_params(line):
+    params = []
+    for param in line.split("(")[1][:-2].split(","):
+        params.append(param.strip())
+    return params
+
+def get_declarations(f):
+    in_declaration = False
+    declaration = {}
+    while True:
+        line = f.readline()
+        if line == '':
+            raise StopIteration()
+        elif line.startswith("QIDL_START("):
+            params = get_declaration_params(line)
+            declaration = process_declaration_params(params, declaration)
+            declaration['text'] = ""
+            in_declaration = True
+        elif line.startswith("QIDL_END("):
+            params = get_declaration_params(line)
+            if declaration['id'] != params[0]:
+                raise Exception("unterminated QIDL declaration: %s" % declaration['id'])
+            in_declaration = False
+            yield declaration
+        elif in_declaration:
+            declaration['text'] += line
+
+def parse_file(f):
+    nodes = []
+    for declaration in get_declarations(f):
+        la = LookAhead(skip(lexer(Input(declaration['text']))))
+        _, node = parse(la)
+        node['id'] = declaration['id']
+        node['do_state'] = declaration['do_state']
+        node['do_properties'] = declaration['do_properties']
+        nodes.append(node)
+    return nodes
+
+def main():
+    nodes = parse_file(sys.stdin)
+    print json.dumps(nodes, sort_keys=True, indent=2)
+
+if __name__ == '__main__':
+    main()
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 17/22] qidl: codegen, initial commit
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (15 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 16/22] qidl: parser, initial import from qc.git Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 18/22] qidl: qidl.h Michael Roth
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile        |    4 +-
 scripts/qidl.py |  256 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 258 insertions(+), 2 deletions(-)
 create mode 100644 scripts/qidl.py

diff --git a/Makefile b/Makefile
index ea9537e..82fc9f0 100644
--- a/Makefile
+++ b/Makefile
@@ -185,8 +185,8 @@ qapi-generated/qga-qapi-types.c qapi-generated/qga-qapi-types.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_types.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
 qapi-generated/qga-qapi-visit.c qapi-generated/qga-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_visit.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
 qapi-generated/qga-qmp-commands.h qapi-generated/qga-qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_commands.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_commands.py $(gen-out-type) -o qapi-generated -p "qga-" < $<, "  GEN   $@")
diff --git a/scripts/qidl.py b/scripts/qidl.py
new file mode 100644
index 0000000..c975377
--- /dev/null
+++ b/scripts/qidl.py
@@ -0,0 +1,256 @@
+#
+# QIDL Code Generator
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qidl_parser import parse_file
+from qapi import parse_schema, mcgen, camel_case, de_camel_case
+from qapi_visit import generate_visit_struct, push_indent, pop_indent
+import sys
+import json
+import getopt
+import os
+import errno
+
+def qapi_schema(node):
+    schema = OrderedDict()
+    data = OrderedDict()
+    fields = None
+    if node.has_key('typedef'):
+        schema['type'] = node['typedef']
+        fields = node['type']['fields']
+    elif node.has_key('struct'):
+        schema['type'] = node['struct']
+        fields = node['fields']
+    else:
+        raise Exception("top-level neither typedef nor struct")
+
+    for field in fields:
+        if filter(lambda x: field.has_key(x), \
+                ['is_derived', 'is_immutable', 'is_broken', 'is_function', 'is_nested_decl']):
+            continue
+
+        description = {}
+
+        if field['type'].endswith('_t'):
+            typename = field['type'][:-2]
+        elif field['type'].startswith('struct '):
+            typename = field['type'].split(" ")[1]
+        elif field['type'].startswith('enum '):
+            typename = 'int'
+        elif field['type'] == "_Bool":
+            typename = 'bool'
+        elif field['type'].endswith("char") and field.has_key('is_pointer'):
+            typename = 'str';
+        elif field['type'] == 'int':
+            typename = 'int32'
+        elif field['type'] == 'unsigned int':
+            typename = 'uint32'
+        else:
+            typename = field['type']
+
+        if field.has_key('is_array') and field['is_array']:
+            description['type'] = [typename]
+            description['<annotated>'] = 'true'
+            if field.has_key('array_size'):
+                description['array_size'] = field['array_size']
+            if field.has_key('array_capacity'):
+                description['array_capacity'] = field['array_capacity']
+        elif camel_case(de_camel_case(typename)) == typename and \
+            (not field.has_key('is_pointer') or not field['is_pointer']):
+            description['<annotated>'] = 'true'
+            description['<embedded struct>'] = 'true'
+            description['type'] = typename
+        else:
+            description = typename
+
+        if field.has_key('is_optional') and field['is_optional']:
+            data["*" + field['variable']] = description
+        else:
+            data[field['variable']] = description
+
+    schema['data'] = data
+    return schema
+
+
+def parse_schema_file(filename):
+    return parse_schema(open(filename, 'r'))
+
+def write_file(output, filename):
+    if filename:
+        output_file = open(filename, 'w')
+    else:
+        output_file = sys.stdout
+    output_file.write(output)
+    if filename:
+        output_file.close()
+
+def property_list(node):
+    prop_list = []
+    fields = None
+    if node.has_key('typedef'):
+        state = node['typedef']
+        fields = node['type']['fields']
+    elif node.has_key('struct'):
+        state = node['struct']
+        fields = node['fields']
+    else:
+        raise Exception("top-level neither typedef nor struct")
+
+    for field in fields:
+        if not field.has_key('is_property'):
+            continue
+
+        prop = {}
+
+        if field['type'].endswith('_t'):
+            typename = field['type'][:-2]
+        elif field['type'] == "_Bool":
+            typename = 'bool'
+        else:
+            typename = field['type']
+
+        prop['name'] = field['property_fields'][0]
+        prop['state'] = state
+        prop['field'] = field['variable']
+        prop['name'] = field['property_fields'][0]
+        prop['type'] = typename
+        if len(field['property_fields']) == 2:
+            prop['default'] = field['property_fields'][1]
+        if field.has_key('is_pointer'):
+            prop['is_pointer'] = True
+        prop_list.append(prop)
+
+    return prop_list
+
+def generate_include(include_path):
+    return mcgen('''
+#include "%(include)s"
+''',
+                       include=include_path)
+
+def generate_properties(type_name, prop_list=[]):
+    output = ""
+
+    for prop in prop_list:
+        if prop.has_key('is_pointer'):
+            if prop['type'] == "char" or prop['type'] == "const char":
+                prop['type'] = "string"
+            elif prop['type'] == "void":
+                prop['type'] = "ptr"
+
+        if prop.has_key("default"):
+            output += mcgen('''
+        DEFINE_PROP_%(type)s(%(name)s, %(state)s, %(field)s, %(default)s),
+''',
+                            type=prop['type'].upper(),  name=prop['name'],
+                            state=prop['state'], field=prop['field'],
+                            default=prop['default'])
+        else:
+            output += mcgen('''
+        DEFINE_PROP_%(type)s(%(name)s, %(state)s, %(field)s),
+''',
+                            type=prop['type'].upper(),  name=prop['name'],
+                            state=prop['state'], field=prop['field'])
+    output += mcgen('''
+        DEFINE_PROP_END_OF_LIST()
+''')
+
+    return output
+
+def generate_qidl_registration(type_name, schema, do_state, prop_list=[]):
+    schema_text = json.dumps("%s" % json.dumps(schema))
+    visitor = "NULL"
+    if do_state:
+        visitor = "visit_type_%s" % type_name
+
+    return mcgen('''
+static char *%(type_name)s_get_schema(Object *obj, Error **errp)
+{
+    return g_strdup(qidl_data_%(type_name)s.schema_json_text);
+}
+
+static void %(type_name)s_register_qidl(void)
+{
+    static Property properties[] = {
+%(properties)s
+    };
+    ObjectProperty *schema_link;
+
+    qidl_data_%(type_name)s.properties = properties;
+    qidl_data_%(type_name)s.visitor = %(visitor)s;
+    qidl_data_%(type_name)s.schema_json_text = %(schema_text)s;
+
+    schema_link = object_property_find(container_get(object_get_root(), "/qidl/schemas"),
+                                       "%(type_name)s", NULL);
+    qidl_data_%(type_name)s.schema_obj = container_get(object_get_root(), "/qidl/schemas/%(type_name)s");
+    if (!schema_link) {
+        object_property_add_str(qidl_data_%(type_name)s.schema_obj, "json_text",
+                                %(type_name)s_get_schema, NULL, NULL);
+    }
+}
+
+qidl_init(%(type_name)s_register_qidl)
+''',
+                 type_name=type_name, schema_text=schema_text, visitor=visitor,
+                 properties=generate_properties(type_name, prop_list))
+
+def main(argv=[]):
+    try:
+        opts, args = getopt.gnu_getopt(argv[1:], "o:cd:I:",
+                                       ["output-filepath=", "include="])
+    except getopt.GetoptError, err:
+        print >> sys.stderr, err
+        return 1
+
+    output_filepath = None
+    includes = []
+    for o, a in opts:
+        if o in ("-f", "--output-filepath"):
+            output_filepath = a
+        elif o in ("-I", "--include"):
+            includes.append(a)
+
+    nodes = parse_file(sys.stdin)
+    if not nodes:
+        return 2
+
+    if os.path.dirname(output_filepath) != "":
+        try:
+            os.makedirs(os.path.dirname(output_filepath))
+        except os.error, e:
+            if e.errno != errno.EEXIST:
+                raise
+    output = ""
+    for include in includes:
+        output += generate_include(include)
+    for node in nodes:
+        do_state = False
+        schema = qapi_schema(node)
+        prop_list = []
+        # qapi parser expects iteration to be line-by-line
+        schema_text = json.dumps(schema, indent=4).replace("\"", "'").split("\n")
+        expr = parse_schema(schema_text)[0]
+
+        if node.has_key('do_state') and node['do_state']:
+            do_state = True
+            output += generate_visit_struct(expr['type'], expr['data'], True)
+        if node.has_key('do_properties') and node['do_properties']:
+            prop_list = property_list(node)
+
+        output += generate_qidl_registration(expr['type'], schema, do_state, prop_list)
+
+    write_file(output, output_filepath)
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 18/22] qidl: qidl.h
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (16 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 17/22] qidl: codegen, initial commit Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 20:47   ` Blue Swirl
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 19/22] qidl: unit tests Michael Roth
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qidl.h |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 qidl.h

diff --git a/qidl.h b/qidl.h
new file mode 100644
index 0000000..75ae5af
--- /dev/null
+++ b/qidl.h
@@ -0,0 +1,58 @@
+/*
+ * QEMU IDL Macros/stubs
+ *
+ * See docs/qidl.txt for usage information.
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth    <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPLv2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QIDL_H
+#define QIDL_H
+
+#include "qapi/qapi-visit-core.h"
+#include "qemu/object.h"
+#include "hw/qdev-properties.h"
+
+#ifdef QIDL_GEN
+
+/* we pass the code through the preprocessor with QIDL_GEN defined to parse
+ * structures as they'd appear after preprocessing, and use the following
+ * definitions mostly to re-insert the initial macros/annotations so they
+ * stick around for the parser to process
+ */
+#define QIDL(...) QIDL(__VA_ARGS__)
+#define QIDL_START(...) QIDL_START(__VA_ARGS__)
+#define QIDL_END(...) QIDL_END(__VA_ARGS__)
+
+#define QIDL_VISIT_TYPE(...)
+#define QIDL_SCHEMA_ADD_LINK(...)
+#define QIDL_PROPERTIES(...)
+
+#else /* !QIDL_GEN */
+
+#define QIDL(...)
+#define QIDL_START(name, ...)
+#define QIDL_END(name) \
+    static struct { \
+        void (*visitor)(Visitor *, struct name **, const char *, Error **); \
+        const char *schema_json_text; \
+        Object *schema_obj; \
+        Property *properties; \
+    } qidl_data_##name;
+
+#define QIDL_VISIT_TYPE(name, v, s, f, e) qidl_data_##name.visitor(v, s, f, e)
+#define QIDL_SCHEMA_ADD_LINK(name, obj, path, errp) \
+    object_property_add_link(obj, path, "container", \
+                             &qidl_data_##name.schema_obj, errp);
+#define QIDL_PROPERTIES(name) qidl_data_##name.properties;
+
+#endif /* QIDL_GEN */
+
+#endif
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 19/22] qidl: unit tests
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (17 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 18/22] qidl: qidl.h Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 20/22] qemu-timer: add visit_type_QEMUTimer Michael Roth
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile                   |    2 +
 rules.mak                  |   15 +++-
 tests/Makefile             |    8 +-
 tests/test-qidl-included.h |   31 ++++++++
 tests/test-qidl-linked.c   |   91 +++++++++++++++++++++++
 tests/test-qidl-linked.h   |   18 +++++
 tests/test-qidl.c          |  177 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 339 insertions(+), 3 deletions(-)
 create mode 100644 tests/test-qidl-included.h
 create mode 100644 tests/test-qidl-linked.c
 create mode 100644 tests/test-qidl-linked.h
 create mode 100644 tests/test-qidl.c

diff --git a/Makefile b/Makefile
index 82fc9f0..0711f14 100644
--- a/Makefile
+++ b/Makefile
@@ -232,6 +232,7 @@ clean:
 	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
 	rm -f $$d/qemu-options.def; \
         done
+	find -depth -name qidl-generated -type d -exec rm -rf {} \;
 
 VERSION ?= $(shell cat VERSION)
 
@@ -402,6 +403,7 @@ qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
 # rebuilt before other object files
 Makefile: $(GENERATED_HEADERS)
 
+
 # Include automatically generated dependency files
 # All subdir dependencies come automatically from our recursive subdir rules
 -include $(wildcard *.d)
diff --git a/rules.mak b/rules.mak
index 60f3e96..3c46599 100644
--- a/rules.mak
+++ b/rules.mak
@@ -15,7 +15,20 @@ MAKEFLAGS += -rR
 QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
 
 %.o: %.c
-	$(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"  CC    $(TARGET_DIR)$@")
+
+%.qidl.c: %.c $(SRC_PATH)/qidl.h $(addprefix $(SRC_PATH)/scripts/,qidl.py qidl_parser.py qapi.py qapi_visit.py)
+	$(call rm -f $(*D)/qidl-generated/$(*F).qidl.c)
+	$(call quiet-command, $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(CFLAGS) -E -c -DQIDL_GEN $< | \
+	  $(PYTHON) $(SRC_PATH)/scripts/qidl.py --output-filepath=$(*D)/qidl-generated/$(*F).qidl.c || [ "$$?" -eq 2 ])
+
+%.o: %.c %.qidl.c
+	$(if $(strip $(shell test -f $(*D)/qidl-generated/$(*F).qidl.c && echo "true")), \
+	  $(call quiet-command, \
+	    $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c \
+	      -include $< -o $@ -c -x c - <$(*D)/qidl-generated/$(*F).qidl.c,"qidl CC $@"), \
+	  $(call quiet-command, \
+	    $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c \
+	      -o $@ $<,"  CC    $@"))
 
 ifeq ($(LIBTOOL),)
 %.lo: %.c
diff --git a/tests/Makefile b/tests/Makefile
index 7cfd3d8..7a82b53 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -15,6 +15,7 @@ check-unit-y += tests/test-string-output-visitor$(EXESUF)
 check-unit-y += tests/test-coroutine$(EXESUF)
 check-unit-y += tests/test-visitor-serialization$(EXESUF)
 check-unit-y += tests/test-iov$(EXESUF)
+check-unit-y += tests/test-qidl$(EXESUF)
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -34,11 +35,12 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
 	tests/test-coroutine.o tests/test-string-output-visitor.o \
 	tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
 	tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
-	tests/test-qmp-commands.o tests/test-visitor-serialization.o
+	tests/test-qmp-commands.o tests/test-visitor-serialization.o \
+	tests/test-qidl.o
 
 test-qapi-obj-y =  $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
 test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
-test-qapi-obj-y += module.o
+test-qapi-obj-y += module.o $(qom-obj-y)
 
 $(test-obj-y): QEMU_INCLUDES += -Itests
 
@@ -84,6 +86,8 @@ check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)
 qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
 $(check-qtest-y): $(qtest-obj-y)
 
+tests/test-qidl$(EXESUF): tests/test-qidl.o tests/test-qidl-linked.o $(test-qapi-obj-y) qapi/misc-qapi-visit.o
+
 .PHONY: check-help
 check-help:
 	@echo "Regression testing targets:"
diff --git a/tests/test-qidl-included.h b/tests/test-qidl-included.h
new file mode 100644
index 0000000..2aae51e
--- /dev/null
+++ b/tests/test-qidl-included.h
@@ -0,0 +1,31 @@
+/*
+ * Unit-tests for QIDL-generated visitors/code
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TEST_QIDL_INCLUDED_H
+#define TEST_QIDL_INCLUDED_H
+
+#include "qidl.h"
+
+QIDL_START(TestStructIncluded, state, properties)
+typedef struct TestStructIncluded {
+    int32_t a QIDL(immutable);
+    int32_t b;
+    uint32_t c QIDL(immutable);
+    uint32_t d;
+    uint64_t e QIDL(immutable);
+    uint64_t f QIDL(property, "f", 42);
+    char *g QIDL(property, "g");
+    char *h QIDL(immutable) QIDL(property, "h");
+} TestStructIncluded;
+QIDL_END(TestStructIncluded)
+
+#endif
diff --git a/tests/test-qidl-linked.c b/tests/test-qidl-linked.c
new file mode 100644
index 0000000..b0d9896
--- /dev/null
+++ b/tests/test-qidl-linked.c
@@ -0,0 +1,91 @@
+/*
+ * Unit-tests for QIDL-generated visitors/code
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qidl.h"
+#include "test-qidl-linked.h"
+#include "hw/qdev-properties.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+
+QIDL_START(TestStructLinked, state, properties)
+typedef struct TestStructLinked {
+    int32_t a QIDL(immutable);
+    int32_t b;
+    uint32_t c QIDL(immutable);
+    uint32_t d;
+    uint64_t e QIDL(immutable);
+    uint64_t f QIDL(property, "f", 42);
+    char *g QIDL(property, "g");
+    char *h QIDL(immutable) QIDL(property, "h");
+} TestStructLinked;
+QIDL_END(TestStructLinked)
+
+/* exercise generated code from annotations in objects we link against */
+void test_linked_object_annotations(gconstpointer opaque)
+{
+    TestStructLinked *s1, *s2 = NULL;
+    Property *props;
+    QmpInputVisitor *qiv;
+    QmpOutputVisitor *qov;
+    QObject *s1_obj;
+    Error *err = NULL;
+
+    s1 = g_malloc0(sizeof(TestStructLinked));
+    s1->a = 42;
+    s1->b = INT32_MAX;
+    s1->c = 43;
+    s1->d = UINT32_MAX;
+    s1->e = 44;
+    s1->f = UINT64_MAX;
+    s1->g = g_strdup("test string g");
+    s1->h = g_strdup("test string h");
+
+    qov = qmp_output_visitor_new();
+    QIDL_VISIT_TYPE(TestStructLinked, qmp_output_get_visitor(qov), &s1, NULL, &err);
+    g_assert(err == NULL);
+
+    s1_obj = qmp_output_get_qobject(qov);
+    qiv = qmp_input_visitor_new(s1_obj);
+
+    qobject_decref(s1_obj);
+    qmp_output_visitor_cleanup(qov);
+    g_free(s1->g);
+    g_free(s1->h);
+    g_free(s1);
+
+    s2 = g_malloc0(sizeof(TestStructLinked));
+    QIDL_VISIT_TYPE(TestStructLinked, qmp_input_get_visitor(qiv), &s2, NULL, &err);
+    g_assert(err == NULL);
+
+    g_assert_cmpint(s2->a, ==, 0);
+    g_assert_cmpint(s2->b, ==, INT32_MAX);
+    g_assert_cmpint(s2->c, ==, 0);
+    g_assert_cmpint(s2->d, ==, UINT32_MAX);
+    g_assert_cmpint(s2->e, ==, 0);
+    g_assert_cmpint(s2->f, ==, UINT64_MAX);
+    g_assert_cmpstr(s2->g, ==, "test string g");
+    g_assert(s2->h == NULL);
+
+    qmp_input_visitor_cleanup(qiv);
+    g_free(s2->g);
+    g_free(s2);
+
+    props = QIDL_PROPERTIES(TestStructLinked);
+    g_assert_cmpstr(props[0].name, ==, "f");
+    g_assert_cmpint(props[0].defval, ==, 42);
+    g_assert_cmpstr(props[1].name, ==, "g");
+    g_assert_cmpint(props[1].defval, ==, 0);
+    g_assert_cmpstr(props[2].name, ==, "h");
+    g_assert_cmpint(props[2].defval, ==, 0);
+    g_assert(props[3].name == NULL);
+}
diff --git a/tests/test-qidl-linked.h b/tests/test-qidl-linked.h
new file mode 100644
index 0000000..1b100a2
--- /dev/null
+++ b/tests/test-qidl-linked.h
@@ -0,0 +1,18 @@
+/*
+ * Unit-tests for QIDL-generated visitors/code
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TEST_QIDL_LINKED_H
+#define TEST_QIDL_LINKED_H
+
+void test_linked_object_annotations(gconstpointer opaque);
+
+#endif
diff --git a/tests/test-qidl.c b/tests/test-qidl.c
new file mode 100644
index 0000000..a1d27a2
--- /dev/null
+++ b/tests/test-qidl.c
@@ -0,0 +1,177 @@
+/*
+ * Unit-tests for QIDL-generated visitors/code
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "qidl.h"
+#include "test-qidl-included.h"
+#include "test-qidl-linked.h"
+#include "hw/qdev-properties.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qapi-dealloc-visitor.h"
+
+PropertyInfo qdev_prop_uint64;
+PropertyInfo qdev_prop_string;
+
+QIDL_START(TestStructMain, state, properties)
+typedef struct TestStructMain {
+    int32_t a QIDL(immutable);
+    int32_t b;
+    uint32_t c QIDL(immutable);
+    uint32_t d;
+    uint64_t e QIDL(immutable);
+    uint64_t f QIDL(property, "f", 42);
+    char *g QIDL(property, "g");
+    char *h QIDL(immutable) QIDL(property, "h");
+} TestStructMain;
+QIDL_END(TestStructMain)
+
+/* exercise generated code from annotations in main() object file */
+static void test_main_object_annotations(gconstpointer opaque)
+{
+    TestStructMain *s1, *s2 = NULL;
+    Property *props;
+    QmpInputVisitor *qiv;
+    QmpOutputVisitor *qov;
+    QObject *s1_obj;
+    Error *err = NULL;
+
+    s1 = g_malloc0(sizeof(TestStructMain));
+    s1->a = 42;
+    s1->b = INT32_MAX;
+    s1->c = 43;
+    s1->d = UINT32_MAX;
+    s1->e = 44;
+    s1->f = UINT64_MAX;
+    s1->g = g_strdup("test string g");
+    s1->h = g_strdup("test string h");
+
+    qov = qmp_output_visitor_new();
+    QIDL_VISIT_TYPE(TestStructMain, qmp_output_get_visitor(qov), &s1, NULL, &err);
+    g_assert(err == NULL);
+
+    s1_obj = qmp_output_get_qobject(qov);
+    qiv = qmp_input_visitor_new(s1_obj);
+
+    qobject_decref(s1_obj);
+    qmp_output_visitor_cleanup(qov);
+    g_free(s1->g);
+    g_free(s1->h);
+    g_free(s1);
+
+    s2 = g_malloc0(sizeof(TestStructMain));
+    QIDL_VISIT_TYPE(TestStructMain, qmp_input_get_visitor(qiv), &s2, NULL, &err);
+    g_assert(err == NULL);
+
+    g_assert_cmpint(s2->a, ==, 0);
+    g_assert_cmpint(s2->b, ==, INT32_MAX);
+    g_assert_cmpint(s2->c, ==, 0);
+    g_assert_cmpint(s2->d, ==, UINT32_MAX);
+    g_assert_cmpint(s2->e, ==, 0);
+    g_assert_cmpint(s2->f, ==, UINT64_MAX);
+    g_assert_cmpstr(s2->g, ==, "test string g");
+    g_assert(s2->h == NULL);
+
+    qmp_input_visitor_cleanup(qiv);
+    g_free(s2->g);
+    g_free(s2);
+
+    props = QIDL_PROPERTIES(TestStructMain);
+    g_assert_cmpstr(props[0].name, ==, "f");
+    g_assert_cmpint(props[0].defval, ==, 42);
+    g_assert_cmpstr(props[1].name, ==, "g");
+    g_assert_cmpint(props[1].defval, ==, 0);
+    g_assert_cmpstr(props[2].name, ==, "h");
+    g_assert_cmpint(props[2].defval, ==, 0);
+    g_assert(props[3].name == NULL);
+}
+
+/* exercise generated code from annotations in included header files */
+static void test_header_file_annotations(gconstpointer opaque)
+{
+    TestStructIncluded *s1, *s2 = NULL;
+    Property *props;
+    QmpInputVisitor *qiv;
+    QmpOutputVisitor *qov;
+    QObject *s1_obj;
+    Error *err = NULL;
+
+    s1 = g_malloc0(sizeof(TestStructIncluded));
+    s1->a = 42;
+    s1->b = INT32_MAX;
+    s1->c = 43;
+    s1->d = UINT32_MAX;
+    s1->e = 44;
+    s1->f = UINT64_MAX;
+    s1->g = g_strdup("test string g");
+    s1->h = g_strdup("test string h");
+
+    qov = qmp_output_visitor_new();
+    QIDL_VISIT_TYPE(TestStructIncluded, qmp_output_get_visitor(qov), &s1, NULL, &err);
+    g_assert(err == NULL);
+
+    s1_obj = qmp_output_get_qobject(qov);
+    qiv = qmp_input_visitor_new(s1_obj);
+
+    qobject_decref(s1_obj);
+    qmp_output_visitor_cleanup(qov);
+    g_free(s1->g);
+    g_free(s1->h);
+    g_free(s1);
+
+    s2 = g_malloc0(sizeof(TestStructIncluded));
+    QIDL_VISIT_TYPE(TestStructIncluded, qmp_input_get_visitor(qiv), &s2, NULL, &err);
+    g_assert(err == NULL);
+
+    g_assert_cmpint(s2->a, ==, 0);
+    g_assert_cmpint(s2->b, ==, INT32_MAX);
+    g_assert_cmpint(s2->c, ==, 0);
+    g_assert_cmpint(s2->d, ==, UINT32_MAX);
+    g_assert_cmpint(s2->e, ==, 0);
+    g_assert_cmpint(s2->f, ==, UINT64_MAX);
+    g_assert_cmpstr(s2->g, ==, "test string g");
+    g_assert(s2->h == NULL);
+
+    qmp_input_visitor_cleanup(qiv);
+    g_free(s2->g);
+    g_free(s2);
+
+    props = QIDL_PROPERTIES(TestStructIncluded);
+    g_assert_cmpstr(props[0].name, ==, "f");
+    g_assert_cmpint(props[0].defval, ==, 42);
+    g_assert_cmpstr(props[1].name, ==, "g");
+    g_assert_cmpint(props[1].defval, ==, 0);
+    g_assert_cmpstr(props[2].name, ==, "h");
+    g_assert_cmpint(props[2].defval, ==, 0);
+    g_assert(props[3].name == NULL);
+}
+
+int main(int argc, char **argv)
+{
+    module_call_init(MODULE_INIT_QOM);
+    module_call_init(MODULE_INIT_QIDL);
+
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_data_func("/qidl/build_test/main_object_annotations", NULL,
+                         test_main_object_annotations);
+    g_test_add_data_func("/qidl/build_test/linked_object_annotations", NULL,
+                         test_linked_object_annotations);
+    g_test_add_data_func("/qidl/build_test/header_file_annotations", NULL,
+                         test_header_file_annotations);
+
+    g_test_run();
+
+    return 0;
+}
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 20/22] qemu-timer: add visit_type_QEMUTimer
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (18 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 19/22] qidl: unit tests Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 21/22] rtc: add QIDL annotations Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 22/22] cirrus_vga: " Michael Roth
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile     |    3 ++-
 qemu-timer.c |   25 +++++++++++++++++++++++++
 qemu-timer.h |    4 ++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 0711f14..c545ebd 100644
--- a/Makefile
+++ b/Makefile
@@ -157,7 +157,8 @@ qemu-img.o: qemu-img-cmds.h
 
 tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
 	qemu-timer-common.o main-loop.o notify.o \
-	iohandler.o cutils.o iov.o async.o
+	iohandler.o cutils.o iov.o async.o \
+	$(qapi-obj-y) $(qobject-obj-y)
 tools-obj-$(CONFIG_POSIX) += compatfd.o
 
 qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
diff --git a/qemu-timer.c b/qemu-timer.c
index de98977..8a67620 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -30,6 +30,7 @@
 #include "hw/hw.h"
 
 #include "qemu-timer.h"
+#include "qapi/qapi-visit-core.h"
 
 #ifdef _WIN32
 #include <mmsystem.h>
@@ -61,6 +62,30 @@ struct QEMUTimer {
     int scale;
 };
 
+void visit_type_QEMUTimer(Visitor *v, QEMUTimer **obj, const char *name,
+                          Error **errp)
+{
+    int64_t expire_time, expire_time_cpy;
+    if (!obj || !*obj) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : NULL,
+                  "non-NULL QEMUTimer");
+        return;
+    }
+    expire_time = expire_time_cpy = qemu_timer_expire_time_ns(*obj);
+    visit_start_struct(v, NULL, "QEMUTimer", name, 0, errp);
+    visit_type_int64(v, &expire_time, "expire_time", errp);
+    visit_end_struct(v, errp);
+
+    /* if we're modifying a QEMUTimer, re-arm/delete accordingly */
+    if (expire_time != expire_time_cpy) {
+        if (expire_time != -1) {
+            qemu_mod_timer_ns(*obj, expire_time);
+        } else {
+            qemu_del_timer(*obj);
+        }
+    }
+}
+
 struct qemu_alarm_timer {
     char const *name;
     int (*start)(struct qemu_alarm_timer *t);
diff --git a/qemu-timer.h b/qemu-timer.h
index f8af595..1feabd7 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -4,6 +4,7 @@
 #include "qemu-common.h"
 #include "main-loop.h"
 #include "notify.h"
+#include "qapi/qapi-visit-core.h"
 
 #ifdef __FreeBSD__
 #include <sys/param.h>
@@ -67,6 +68,9 @@ int64_t cpu_get_ticks(void);
 void cpu_enable_ticks(void);
 void cpu_disable_ticks(void);
 
+void visit_type_QEMUTimer(Visitor *v, QEMUTimer **obj, const char *name,
+                          Error **errp);
+
 static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb,
                                            void *opaque)
 {
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 21/22] rtc: add QIDL annotations
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (19 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 20/22] qemu-timer: add visit_type_QEMUTimer Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 22/22] cirrus_vga: " Michael Roth
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber


Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hw/hw.h          |    1 +
 hw/mc146818rtc.c |   49 ++++++++++++++++++++++++++++++-------------------
 2 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/hw/hw.h b/hw/hw.h
index e5cb9bf..3c3d4f9 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -12,6 +12,7 @@
 #include "irq.h"
 #include "qemu-file.h"
 #include "vmstate.h"
+#include "qidl.h"
 
 #ifdef NEED_CPU_H
 #if TARGET_LONG_BITS == 64
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 3777f85..b200a74 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -25,6 +25,7 @@
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "mc146818rtc.h"
+#include "qidl.h"
 
 #ifdef TARGET_I386
 #include "apic.h"
@@ -47,31 +48,35 @@
 
 #define RTC_REINJECT_ON_ACK_COUNT 20
 
+QIDL_START(RTCState, state, properties)
 typedef struct RTCState {
-    ISADevice dev;
-    MemoryRegion io;
+    ISADevice dev QIDL(immutable);
+    MemoryRegion io QIDL(immutable);
     uint8_t cmos_data[128];
     uint8_t cmos_index;
     struct tm current_tm;
-    int32_t base_year;
-    qemu_irq irq;
-    qemu_irq sqw_irq;
-    int it_shift;
+    int32_t base_year QIDL(property, "base_year", 1980);
+    qemu_irq irq QIDL(immutable);
+    qemu_irq sqw_irq QIDL(immutable);
+    int it_shift QIDL(immutable);
     /* periodic timer */
     QEMUTimer *periodic_timer;
     int64_t next_periodic_time;
     /* second update */
     int64_t next_second_time;
-    uint16_t irq_reinject_on_ack_count;
+    uint16_t irq_reinject_on_ack_count QIDL(broken);
     uint32_t irq_coalesced;
     uint32_t period;
-    QEMUTimer *coalesced_timer;
+    bool has_coalesced_timer QIDL(immutable);
+    QEMUTimer *coalesced_timer QIDL(optional);
     QEMUTimer *second_timer;
     QEMUTimer *second_timer2;
-    Notifier clock_reset_notifier;
-    LostTickPolicy lost_tick_policy;
-    Notifier suspend_notifier;
+    Notifier clock_reset_notifier QIDL(broken);
+    LostTickPolicy lost_tick_policy QIDL(immutable) \
+        QIDL(property, "lost_tick_policy", LOST_TICK_DISCARD);
+    Notifier suspend_notifier QIDL(broken);
 } RTCState;
+QIDL_END(RTCState)
 
 static void rtc_set_time(RTCState *s);
 static void rtc_copy_date(RTCState *s);
@@ -615,6 +620,14 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
     visit_end_struct(v, errp);
 }
 
+static void rtc_get_state(Object *obj, Visitor *v, void *opaque,
+                          const char *name, Error **errp)
+{
+    ISADevice *isa = ISA_DEVICE(obj);
+    RTCState *s = DO_UPCAST(RTCState, dev, isa);
+    QIDL_VISIT_TYPE(RTCState, v, &s, name, errp);
+}
+
 static int rtc_initfn(ISADevice *dev)
 {
     RTCState *s = DO_UPCAST(RTCState, dev, dev);
@@ -627,9 +640,11 @@ static int rtc_initfn(ISADevice *dev)
 
     rtc_set_date_from_host(dev);
 
+
 #ifdef TARGET_I386
     switch (s->lost_tick_policy) {
     case LOST_TICK_SLEW:
+        s->has_coalesced_timer = true;
         s->coalesced_timer =
             qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
         break;
@@ -662,6 +677,9 @@ static int rtc_initfn(ISADevice *dev)
 
     object_property_add(OBJECT(s), "date", "struct tm",
                         rtc_get_date, NULL, NULL, s, NULL);
+    object_property_add(OBJECT(s), "state", "RTCState",
+                        rtc_get_state, NULL, NULL, s, NULL);
+    QIDL_SCHEMA_ADD_LINK(RTCState, OBJECT(s), "state_schema", NULL);
 
     return 0;
 }
@@ -683,13 +701,6 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
     return dev;
 }
 
-static Property mc146818rtc_properties[] = {
-    DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
-    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
-                               lost_tick_policy, LOST_TICK_DISCARD),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static void rtc_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -697,7 +708,7 @@ static void rtc_class_initfn(ObjectClass *klass, void *data)
     ic->init = rtc_initfn;
     dc->no_user = 1;
     dc->vmsd = &vmstate_rtc;
-    dc->props = mc146818rtc_properties;
+    dc->props = QIDL_PROPERTIES(RTCState);
 }
 
 static TypeInfo mc146818rtc_info = {
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH 22/22] cirrus_vga: add QIDL annotations
  2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
                   ` (20 preceding siblings ...)
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 21/22] rtc: add QIDL annotations Michael Roth
@ 2012-07-24 17:20 ` Michael Roth
  21 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 17:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: aliguori, quintela, owasserm, yamahata, pbonzini, akong, afaerber

We also add annotations for embedded VGACommonState/PCIDevice structs
to serialize inherited/guest-volatile data such as PCI config space and
msix tables.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 hw/cirrus_vga.c |   51 ++++++++++++++++++++++++++++++++++++++++-----------
 hw/msix.c       |    3 +++
 hw/pci.h        |   55 +++++++++++++++++++++++++++++++------------------------
 hw/vga_int.h    |   28 +++++++++++++++-------------
 4 files changed, 89 insertions(+), 48 deletions(-)

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 623dd68..2f707a4 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -197,17 +197,18 @@ typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
 typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
                               uint8_t *dst, int dst_pitch, int width, int height);
 
+QIDL_START(CirrusVGAState, state)
 typedef struct CirrusVGAState {
     VGACommonState vga;
 
-    MemoryRegion cirrus_linear_io;
-    MemoryRegion cirrus_linear_bitblt_io;
-    MemoryRegion cirrus_mmio_io;
-    MemoryRegion pci_bar;
+    MemoryRegion cirrus_linear_io QIDL(immutable);
+    MemoryRegion cirrus_linear_bitblt_io QIDL(immutable);
+    MemoryRegion cirrus_mmio_io QIDL(immutable);
+    MemoryRegion pci_bar QIDL(immutable);
     bool linear_vram;  /* vga.vram mapped over cirrus_linear_io */
-    MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
-    MemoryRegion low_mem;           /* always mapped, overridden by: */
-    MemoryRegion cirrus_bank[2];    /*   aliases at 0xa0000-0xb0000  */
+    MemoryRegion low_mem_container QIDL(immutable); /* container for 0xa0000-0xc0000 */
+    MemoryRegion low_mem QIDL(immutable);           /* always mapped, overridden by: */
+    MemoryRegion cirrus_bank[2] QIDL(immutable);    /*   aliases at 0xa0000-0xb0000  */
     uint32_t cirrus_addr_mask;
     uint32_t linear_mmio_mask;
     uint8_t cirrus_shadow_gr0;
@@ -230,11 +231,11 @@ typedef struct CirrusVGAState {
     uint32_t cirrus_blt_srcaddr;
     uint8_t cirrus_blt_mode;
     uint8_t cirrus_blt_modeext;
-    cirrus_bitblt_rop_t cirrus_rop;
+    cirrus_bitblt_rop_t cirrus_rop QIDL(immutable);
 #define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
     uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
-    uint8_t *cirrus_srcptr;
-    uint8_t *cirrus_srcptr_end;
+    uint8_t *cirrus_srcptr QIDL(derived);
+    uint8_t *cirrus_srcptr_end QIDL(derived);
     uint32_t cirrus_srccounter;
     /* hwcursor display state */
     int last_hw_cursor_size;
@@ -246,16 +247,21 @@ typedef struct CirrusVGAState {
     int device_id;
     int bustype;
 } CirrusVGAState;
+QIDL_END(CirrusVGAState)
 
+QIDL_START(PCICirrusVGAState, state)
 typedef struct PCICirrusVGAState {
     PCIDevice dev;
     CirrusVGAState cirrus_vga;
 } PCICirrusVGAState;
+QIDL_END(PCICirrusVGAState)
 
+QIDL_START(ISACirrusVGAState, state)
 typedef struct ISACirrusVGAState {
-    ISADevice dev;
+    ISADevice dev QIDL(immutable);
     CirrusVGAState cirrus_vga;
 } ISACirrusVGAState;
+QIDL_END(ISACirrusVGAState)
 
 static uint8_t rop_to_index[256];
 
@@ -2888,6 +2894,14 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
  *
  ***************************************/
 
+static void isa_cirrus_vga_get_state(Object *obj, Visitor *v, void *opaque,
+                                     const char *name, Error **errp)
+{
+    ISADevice *isa = ISA_DEVICE(obj);
+    ISACirrusVGAState *s = DO_UPCAST(ISACirrusVGAState, dev, isa);
+    QIDL_VISIT_TYPE(ISACirrusVGAState, v, &s, name, errp);
+}
+
 static int vga_initfn(ISADevice *dev)
 {
     ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
@@ -2903,6 +2917,9 @@ static int vga_initfn(ISADevice *dev)
     rom_add_vga(VGABIOS_CIRRUS_FILENAME);
     /* XXX ISA-LFB support */
     /* FIXME not qdev yet */
+    object_property_add(OBJECT(d), "state", "ISACirrusVGAState",
+                        isa_cirrus_vga_get_state, NULL, NULL, s, NULL);
+    QIDL_SCHEMA_ADD_LINK(ISACirrusVGAState, OBJECT(d), "state_schema", NULL);
     return 0;
 }
 
@@ -2928,6 +2945,14 @@ static TypeInfo isa_cirrus_vga_info = {
  *
  ***************************************/
 
+static void pci_cirrus_vga_get_state(Object *obj, Visitor *v, void *opaque,
+                                     const char *name, Error **errp)
+{
+    PCIDevice *pci = PCI_DEVICE(obj);
+    PCICirrusVGAState *s = DO_UPCAST(PCICirrusVGAState, dev, pci);
+    QIDL_VISIT_TYPE(PCICirrusVGAState, v, &s, name, errp);
+}
+
 static int pci_cirrus_vga_initfn(PCIDevice *dev)
 {
      PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
@@ -2960,6 +2985,10 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
      if (device_id == CIRRUS_ID_CLGD5446) {
          pci_register_bar(&d->dev, 1, 0, &s->cirrus_mmio_io);
      }
+
+    object_property_add(OBJECT(d), "state", "PCICirrusVGAState",
+                        pci_cirrus_vga_get_state, NULL, NULL, s, NULL);
+    QIDL_SCHEMA_ADD_LINK(PCICirrusVGAState, OBJECT(d), "state_schema", NULL);
      return 0;
 }
 
diff --git a/hw/msix.c b/hw/msix.c
index ded3c55..0c9b03d 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -281,6 +281,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
     dev->msix_entry_used = g_malloc0(MSIX_MAX_ENTRIES *
                                         sizeof *dev->msix_entry_used);
 
+    dev->msix_table_page_size = MSIX_PAGE_SIZE;
     dev->msix_table_page = g_malloc0(MSIX_PAGE_SIZE);
     msix_mask_all(dev, nentries);
 
@@ -301,6 +302,7 @@ err_config:
     memory_region_destroy(&dev->msix_mmio);
     g_free(dev->msix_table_page);
     dev->msix_table_page = NULL;
+    dev->msix_table_page_size = 0;
     g_free(dev->msix_entry_used);
     dev->msix_entry_used = NULL;
     return ret;
@@ -330,6 +332,7 @@ int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
     memory_region_destroy(&dev->msix_mmio);
     g_free(dev->msix_table_page);
     dev->msix_table_page = NULL;
+    dev->msix_table_page_size = 0;
     g_free(dev->msix_entry_used);
     dev->msix_entry_used = NULL;
     dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
diff --git a/hw/pci.h b/hw/pci.h
index 79d38fd..0caf834 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -177,38 +177,41 @@ typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector,
                                       MSIMessage msg);
 typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector);
 
+QIDL_START(PCIDevice, state)
 struct PCIDevice {
-    DeviceState qdev;
+    DeviceState qdev QIDL(immutable);
 
     /* PCI config space */
-    uint8_t *config;
+    uint8_t *config \
+        QIDL(size_is, (pci_is_express(*obj) ? \
+                       PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE));
 
     /* Used to enable config checks on load. Note that writable bits are
      * never checked even if set in cmask. */
-    uint8_t *cmask;
+    uint8_t *cmask QIDL(immutable);
 
     /* Used to implement R/W bytes */
-    uint8_t *wmask;
+    uint8_t *wmask QIDL(immutable);
 
     /* Used to implement RW1C(Write 1 to Clear) bytes */
-    uint8_t *w1cmask;
+    uint8_t *w1cmask QIDL(immutable);
 
     /* Used to allocate config space for capabilities. */
-    uint8_t *used;
+    uint8_t *used QIDL(immutable);
 
     /* the following fields are read only */
-    PCIBus *bus;
-    int32_t devfn;
-    char name[64];
-    PCIIORegion io_regions[PCI_NUM_REGIONS];
-    DMAContext *dma;
+    PCIBus *bus QIDL(immutable);
+    int32_t devfn QIDL(immutable);
+    char name[64] QIDL(immutable);
+    PCIIORegion io_regions[PCI_NUM_REGIONS] QIDL(immutable);
+    DMAContext *dma QIDL(immutable);
 
     /* do not access the following fields */
-    PCIConfigReadFunc *config_read;
-    PCIConfigWriteFunc *config_write;
+    PCIConfigReadFunc *config_read QIDL(immutable);
+    PCIConfigWriteFunc *config_write QIDL(immutable);
 
     /* IRQ objects for the INTA-INTD pins.  */
-    qemu_irq *irq;
+    qemu_irq *irq QIDL(immutable);
 
     /* Current IRQ levels.  Used internally by the generic PCI code.  */
     uint8_t irq_state;
@@ -220,14 +223,17 @@ struct PCIDevice {
     uint8_t msix_cap;
 
     /* MSI-X entries */
-    int msix_entries_nr;
+    int32_t msix_entries_nr;
+
+    /* MSI-X table page size */
+    int32_t msix_table_page_size QIDL(immutable);
 
     /* Space to store MSIX table */
-    uint8_t *msix_table_page;
+    uint8_t *msix_table_page QIDL(size_is, msix_table_page_size);
     /* MMIO index used to map MSIX table and pending bit entries. */
-    MemoryRegion msix_mmio;
+    MemoryRegion msix_mmio QIDL(immutable);
     /* Reference-count for entries actually in use by driver. */
-    unsigned *msix_entry_used;
+    unsigned int *msix_entry_used QIDL(broken);
     /* Region including the MSI-X table */
     uint32_t msix_bar_size;
     /* MSIX function mask set or MSIX disabled */
@@ -239,21 +245,22 @@ struct PCIDevice {
     uint8_t msi_cap;
 
     /* PCI Express */
-    PCIExpressDevice exp;
+    PCIExpressDevice exp QIDL(immutable);
 
     /* SHPC */
-    SHPCDevice *shpc;
+    SHPCDevice *shpc QIDL(immutable);
 
     /* Location of option rom */
-    char *romfile;
+    char *romfile QIDL(immutable);
     bool has_rom;
-    MemoryRegion rom;
+    MemoryRegion rom QIDL(immutable);
     uint32_t rom_bar;
 
     /* MSI-X notifiers */
-    MSIVectorUseNotifier msix_vector_use_notifier;
-    MSIVectorReleaseNotifier msix_vector_release_notifier;
+    MSIVectorUseNotifier msix_vector_use_notifier QIDL(immutable);
+    MSIVectorReleaseNotifier msix_vector_release_notifier QIDL(immutable);
 };
+QIDL_END(PCIDevice)
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
                       uint8_t attr, MemoryRegion *memory);
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 8938093..a77cc41 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -101,15 +101,16 @@ struct VGACommonState;
 typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
 typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
 
+QIDL_START(VGACommonState, state)
 typedef struct VGACommonState {
-    MemoryRegion *legacy_address_space;
-    uint8_t *vram_ptr;
-    MemoryRegion vram;
-    MemoryRegion vram_vbe;
+    MemoryRegion *legacy_address_space QIDL(immutable);
+    uint8_t *vram_ptr QIDL(immutable);
+    MemoryRegion vram QIDL(immutable);
+    MemoryRegion vram_vbe QIDL(immutable);
     uint32_t vram_size;
     uint32_t vram_size_mb; /* property */
     uint32_t latch;
-    MemoryRegion *chain4_alias;
+    MemoryRegion *chain4_alias QIDL(immutable);
     uint8_t sr_index;
     uint8_t sr[256];
     uint8_t gr_index;
@@ -141,7 +142,7 @@ typedef struct VGACommonState {
                         int *pheight);
     VGA_STATE_COMMON_BOCHS_VBE
     /* display refresh support */
-    DisplayState *ds;
+    DisplayState *ds QIDL(immutable);
     uint32_t font_offsets[2];
     int graphic_mode;
     uint8_t shift_control;
@@ -161,10 +162,10 @@ typedef struct VGACommonState {
     uint32_t cursor_offset;
     unsigned int (*rgb_to_pixel)(unsigned int r,
                                  unsigned int g, unsigned b);
-    vga_hw_update_ptr update;
-    vga_hw_invalidate_ptr invalidate;
-    vga_hw_screen_dump_ptr screen_dump;
-    vga_hw_text_update_ptr text_update;
+    vga_hw_update_ptr update QIDL(immutable);
+    vga_hw_invalidate_ptr invalidate QIDL(immutable);
+    vga_hw_screen_dump_ptr screen_dump QIDL(immutable);
+    vga_hw_text_update_ptr text_update QIDL(immutable);
     /* hardware mouse cursor support */
     uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
     void (*cursor_invalidate)(struct VGACommonState *s);
@@ -173,11 +174,12 @@ typedef struct VGACommonState {
     uint32_t last_palette[256];
     uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
     /* retrace */
-    vga_retrace_fn retrace;
-    vga_update_retrace_info_fn update_retrace_info;
-    union vga_retrace retrace_info;
+    vga_retrace_fn retrace QIDL(immutable);
+    vga_update_retrace_info_fn update_retrace_info QIDL(immutable);
+    union vga_retrace retrace_info QIDL(immutable);
     uint8_t is_vbe_vmstate;
 } VGACommonState;
+QIDL_END(VGACommonState)
 
 static inline int c6_to_8(int v)
 {
-- 
1.7.9.5

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

* Re: [Qemu-devel] [PATCH 18/22] qidl: qidl.h
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 18/22] qidl: qidl.h Michael Roth
@ 2012-07-24 20:47   ` Blue Swirl
  2012-07-25  0:30     ` Michael Roth
  0 siblings, 1 reply; 37+ messages in thread
From: Blue Swirl @ 2012-07-24 20:47 UTC (permalink / raw)
  To: Michael Roth
  Cc: aliguori, yamahata, quintela, qemu-devel, owasserm, pbonzini,
	akong, afaerber

On Tue, Jul 24, 2012 at 5:20 PM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  qidl.h |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
>  create mode 100644 qidl.h
>
> diff --git a/qidl.h b/qidl.h
> new file mode 100644
> index 0000000..75ae5af
> --- /dev/null
> +++ b/qidl.h
> @@ -0,0 +1,58 @@
> +/*
> + * QEMU IDL Macros/stubs
> + *
> + * See docs/qidl.txt for usage information.
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + *  Michael Roth    <mdroth@linux.vnet.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPLv2.

GPLv2 or later?

> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#ifndef QIDL_H
> +#define QIDL_H
> +
> +#include "qapi/qapi-visit-core.h"
> +#include "qemu/object.h"
> +#include "hw/qdev-properties.h"
> +
> +#ifdef QIDL_GEN
> +
> +/* we pass the code through the preprocessor with QIDL_GEN defined to parse
> + * structures as they'd appear after preprocessing, and use the following
> + * definitions mostly to re-insert the initial macros/annotations so they
> + * stick around for the parser to process

I guess this doesn't work if the file #includes itself, like some
flash files used to do (or I can't find the example just now).

> + */
> +#define QIDL(...) QIDL(__VA_ARGS__)
> +#define QIDL_START(...) QIDL_START(__VA_ARGS__)
> +#define QIDL_END(...) QIDL_END(__VA_ARGS__)
> +
> +#define QIDL_VISIT_TYPE(...)
> +#define QIDL_SCHEMA_ADD_LINK(...)
> +#define QIDL_PROPERTIES(...)

Maybe for this pass, the macros which do nothing like above could
still do more syntax checking by specifying the macro argument list
instead of ellipsis or even by introducing a dummy inline function.

> +
> +#else /* !QIDL_GEN */
> +
> +#define QIDL(...)
> +#define QIDL_START(name, ...)

Declare 'struct type of name' here (see below)?

> +#define QIDL_END(name) \
> +    static struct { \

'const', how about a name for the struct type too?

> +        void (*visitor)(Visitor *, struct name **, const char *, Error **); \

Here 'struct name **' could be const if the struct defined here is
const. Probably 'struct name' should be declared earlier.

> +        const char *schema_json_text; \
> +        Object *schema_obj; \
> +        Property *properties; \
> +    } qidl_data_##name;
> +
> +#define QIDL_VISIT_TYPE(name, v, s, f, e) qidl_data_##name.visitor(v, s, f, e)
> +#define QIDL_SCHEMA_ADD_LINK(name, obj, path, errp) \
> +    object_property_add_link(obj, path, "container", \
> +                             &qidl_data_##name.schema_obj, errp);

The semicolons here and below seem useless.

> +#define QIDL_PROPERTIES(name) qidl_data_##name.properties;
> +
> +#endif /* QIDL_GEN */
> +
> +#endif
> --
> 1.7.9.5
>
>

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

* Re: [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import Michael Roth
@ 2012-07-24 22:12   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:12 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori


> Python doesn't allow "-" in module names, so we need to rename the file
> so we can re-use bits of the codegen
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  Makefile              |    4 +-
>  scripts/qapi-visit.py |  352 -------------------------------------------------
>  scripts/qapi_visit.py |  352 +++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/Makefile        |    4 +-
>  4 files changed, 356 insertions(+), 356 deletions(-)
>  delete mode 100644 scripts/qapi-visit.py
>  create mode 100644 scripts/qapi_visit.py
>
> diff --git a/Makefile b/Makefile
> index ab82ef3..ea7174c 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -195,8 +195,8 @@ qapi-types.c qapi-types.h :\
>  $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
>  	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
>  qapi-visit.c qapi-visit.h :\
> -$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
> -	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
> +$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
>  qmp-commands.h qmp-marshal.c :\
>  $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
>  	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> deleted file mode 100644
> index 04ef7c4..0000000
> --- a/scripts/qapi-visit.py
> +++ /dev/null
> @@ -1,352 +0,0 @@
> -#
> -# QAPI visitor generator
> -#
> -# Copyright IBM, Corp. 2011
> -#
> -# Authors:
> -#  Anthony Liguori <aliguori@us.ibm.com>
> -#  Michael Roth    <mdroth@linux.vnet.ibm.com>
> -#
> -# This work is licensed under the terms of the GNU GPLv2.
> -# See the COPYING.LIB file in the top-level directory.
> -
> -from ordereddict import OrderedDict
> -from qapi import *
> -import sys
> -import os
> -import getopt
> -import errno
> -
> -def generate_visit_struct_body(field_prefix, name, members):
> -    ret = mcgen('''
> -if (!error_is_set(errp)) {
> -''')
> -    push_indent()
> -
> -    if len(field_prefix):
> -        field_prefix = field_prefix + "."
> -        ret += mcgen('''
> -Error **errp = &err; /* from outer scope */
> -Error *err = NULL;
> -visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
> -''',
> -                name=name)
> -    else:
> -        ret += mcgen('''
> -Error *err = NULL;
> -visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
> -''',
> -                name=name)
> -
> -    ret += mcgen('''
> -if (!err) {
> -    if (!obj || *obj) {
> -''')
> -
> -    push_indent()
> -    push_indent()
> -    for argname, argentry, optional, structured in parse_args(members):
> -        if optional:
> -            ret += mcgen('''
> -visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
> -if (obj && (*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 += generate_visit_struct_body(field_prefix + argname, argname, argentry)
> -        else:
> -            ret += mcgen('''
> -visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
> -''',
> -                         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, &err);
> -''')
> -
> -    pop_indent()
> -    ret += mcgen('''
> -
> -    error_propagate(errp, err);
> -    err = NULL;
> -}
> -''')
> -
> -    pop_indent()
> -    pop_indent()
> -    ret += mcgen('''
> -        /* Always call end_struct if start_struct succeeded.  */
> -        visit_end_struct(m, &err);
> -    }
> -    error_propagate(errp, err);
> -}
> -''')
> -    return ret
> -
> -def generate_visit_struct(name, members):
> -    ret = mcgen('''
> -
> -void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
> -{
> -''',
> -                name=name)
> -
> -    push_indent()
> -    ret += generate_visit_struct_body("", name, members)
> -    pop_indent()
> -
> -    ret += mcgen('''
> -}
> -''')
> -    return ret
> -
> -def generate_visit_list(name, members):
> -    return mcgen('''
> -
> -void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
> -{
> -    GenericList *i, **prev = (GenericList **)obj;
> -    Error *err = NULL;
> -
> -    if (!error_is_set(errp)) {
> -        visit_start_list(m, name, &err);
> -        if (!err) {
> -            for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
> -                %(name)sList *native_i = (%(name)sList *)i;
> -                visit_type_%(name)s(m, &native_i->value, NULL, &err);
> -            }
> -            error_propagate(errp, err);
> -            err = NULL;
> -
> -            /* Always call end_list if start_list succeeded.  */
> -            visit_end_list(m, &err);
> -        }
> -        error_propagate(errp, err);
> -    }
> -}
> -''',
> -                name=name)
> -
> -def generate_visit_enum(name, members):
> -    return mcgen('''
> -
> -void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
> -{
> -    visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
> -}
> -''',
> -                 name=name)
> -
> -def generate_visit_union(name, members):
> -    ret = generate_visit_enum('%sKind' % name, members.keys())
> -
> -    ret += mcgen('''
> -
> -void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
> -{
> -    Error *err = NULL;
> -
> -    if (!error_is_set(errp)) {
> -        visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
> -        if (!err) {
> -            if (!obj || *obj) {
> -                visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
> -                if (!err) {
> -                    switch ((*obj)->kind) {
> -''',
> -                 name=name)
> -
> -    push_indent()
> -    push_indent()
> -    for key in members:
> -        ret += mcgen('''
> -            case %(abbrev)s_KIND_%(enum)s:
> -                visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
> -                break;
> -''',
> -                abbrev = de_camel_case(name).upper(),
> -                enum = c_fun(de_camel_case(key)).upper(),
> -                c_type=members[key],
> -                c_name=c_fun(key))
> -
> -    ret += mcgen('''
> -            default:
> -                abort();
> -            }
> -        }
> -        error_propagate(errp, err);
> -        err = NULL;
> -    }
> -''')
> -    pop_indent()
> -    ret += mcgen('''
> -        /* Always call end_struct if start_struct succeeded.  */
> -        visit_end_struct(m, &err);
> -    }
> -    error_propagate(errp, err);
> -}
> -''')
> -
> -    pop_indent();
> -    ret += mcgen('''
> -}
> -''')
> -
> -    return ret
> -
> -def generate_declaration(name, members, genlist=True):
> -    ret = mcgen('''
> -
> -void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
> -''',
> -                name=name)
> -
> -    if genlist:
> -        ret += mcgen('''
> -void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
> -''',
> -                 name=name)
> -
> -    return ret
> -
> -def generate_decl_enum(name, members, genlist=True):
> -    return mcgen('''
> -
> -void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
> -''',
> -                name=name)
> -
> -try:
> -    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
> -                                   ["source", "header", "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'
> -
> -do_c = False
> -do_h = False
> -
> -for o, a in opts:
> -    if o in ("-p", "--prefix"):
> -        prefix = a
> -    elif o in ("-o", "--output-dir"):
> -        output_dir = a + "/"
> -    elif o in ("-c", "--source"):
> -        do_c = True
> -    elif o in ("-h", "--header"):
> -        do_h = True
> -
> -if not do_c and not do_h:
> -    do_c = True
> -    do_h = True
> -
> -c_file = output_dir + prefix + c_file
> -h_file = output_dir + prefix + h_file
> -
> -try:
> -    os.makedirs(output_dir)
> -except os.error, e:
> -    if e.errno != errno.EEXIST:
> -        raise
> -
> -def maybe_open(really, name, opt):
> -    if really:
> -        return open(name, opt)
> -    else:
> -        import StringIO
> -        return StringIO.StringIO()
> -
> -fdef = maybe_open(do_c, c_file, 'w')
> -fdecl = maybe_open(do_h, h_file, 'w')
> -
> -fdef.write(mcgen('''
> -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> -
> -/*
> - * schema-defined QAPI visitor functions
> - *
> - * Copyright IBM, Corp. 2011
> - *
> - * Authors:
> - *  Anthony Liguori   <aliguori@us.ibm.com>
> - *
> - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> - * See the COPYING.LIB file in the top-level directory.
> - *
> - */
> -
> -#include "%(header)s"
> -''',
> -                 header=basename(h_file)))
> -
> -fdecl.write(mcgen('''
> -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> -
> -/*
> - * schema-defined QAPI visitor function
> - *
> - * Copyright IBM, Corp. 2011
> - *
> - * Authors:
> - *  Anthony Liguori   <aliguori@us.ibm.com>
> - *
> - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> - * See the COPYING.LIB file in the top-level directory.
> - *
> - */
> -
> -#ifndef %(guard)s
> -#define %(guard)s
> -
> -#include "qapi/qapi-visit-core.h"
> -#include "%(prefix)sqapi-types.h"
> -''',
> -                  prefix=prefix, guard=guardname(h_file)))
> -
> -exprs = parse_schema(sys.stdin)
> -
> -for expr in exprs:
> -    if expr.has_key('type'):
> -        ret = generate_visit_struct(expr['type'], expr['data'])
> -        ret += generate_visit_list(expr['type'], expr['data'])
> -        fdef.write(ret)
> -
> -        ret = generate_declaration(expr['type'], expr['data'])
> -        fdecl.write(ret)
> -    elif expr.has_key('union'):
> -        ret = generate_visit_union(expr['union'], expr['data'])
> -        ret += generate_visit_list(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)
> -
> -fdecl.write('''
> -#endif
> -''')
> -
> -fdecl.flush()
> -fdecl.close()
> -
> -fdef.flush()
> -fdef.close()
> diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
> new file mode 100644
> index 0000000..04ef7c4
> --- /dev/null
> +++ b/scripts/qapi_visit.py
> @@ -0,0 +1,352 @@
> +#
> +# QAPI visitor generator
> +#
> +# Copyright IBM, Corp. 2011
> +#
> +# Authors:
> +#  Anthony Liguori <aliguori@us.ibm.com>
> +#  Michael Roth    <mdroth@linux.vnet.ibm.com>
> +#
> +# This work is licensed under the terms of the GNU GPLv2.
> +# See the COPYING.LIB file in the top-level directory.
> +
> +from ordereddict import OrderedDict
> +from qapi import *
> +import sys
> +import os
> +import getopt
> +import errno
> +
> +def generate_visit_struct_body(field_prefix, name, members):
> +    ret = mcgen('''
> +if (!error_is_set(errp)) {
> +''')
> +    push_indent()
> +
> +    if len(field_prefix):
> +        field_prefix = field_prefix + "."
> +        ret += mcgen('''
> +Error **errp = &err; /* from outer scope */
> +Error *err = NULL;
> +visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
> +''',
> +                name=name)
> +    else:
> +        ret += mcgen('''
> +Error *err = NULL;
> +visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
> +''',
> +                name=name)
> +
> +    ret += mcgen('''
> +if (!err) {
> +    if (!obj || *obj) {
> +''')
> +
> +    push_indent()
> +    push_indent()
> +    for argname, argentry, optional, structured in parse_args(members):
> +        if optional:
> +            ret += mcgen('''
> +visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
> +if (obj && (*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 += generate_visit_struct_body(field_prefix + argname, argname, argentry)
> +        else:
> +            ret += mcgen('''
> +visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
> +''',
> +                         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, &err);
> +''')
> +
> +    pop_indent()
> +    ret += mcgen('''
> +
> +    error_propagate(errp, err);
> +    err = NULL;
> +}
> +''')
> +
> +    pop_indent()
> +    pop_indent()
> +    ret += mcgen('''
> +        /* Always call end_struct if start_struct succeeded.  */
> +        visit_end_struct(m, &err);
> +    }
> +    error_propagate(errp, err);
> +}
> +''')
> +    return ret
> +
> +def generate_visit_struct(name, members):
> +    ret = mcgen('''
> +
> +void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
> +{
> +''',
> +                name=name)
> +
> +    push_indent()
> +    ret += generate_visit_struct_body("", name, members)
> +    pop_indent()
> +
> +    ret += mcgen('''
> +}
> +''')
> +    return ret
> +
> +def generate_visit_list(name, members):
> +    return mcgen('''
> +
> +void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
> +{
> +    GenericList *i, **prev = (GenericList **)obj;
> +    Error *err = NULL;
> +
> +    if (!error_is_set(errp)) {
> +        visit_start_list(m, name, &err);
> +        if (!err) {
> +            for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
> +                %(name)sList *native_i = (%(name)sList *)i;
> +                visit_type_%(name)s(m, &native_i->value, NULL, &err);
> +            }
> +            error_propagate(errp, err);
> +            err = NULL;
> +
> +            /* Always call end_list if start_list succeeded.  */
> +            visit_end_list(m, &err);
> +        }
> +        error_propagate(errp, err);
> +    }
> +}
> +''',
> +                name=name)
> +
> +def generate_visit_enum(name, members):
> +    return mcgen('''
> +
> +void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
> +{
> +    visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
> +}
> +''',
> +                 name=name)
> +
> +def generate_visit_union(name, members):
> +    ret = generate_visit_enum('%sKind' % name, members.keys())
> +
> +    ret += mcgen('''
> +
> +void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
> +{
> +    Error *err = NULL;
> +
> +    if (!error_is_set(errp)) {
> +        visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
> +        if (!err) {
> +            if (!obj || *obj) {
> +                visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
> +                if (!err) {
> +                    switch ((*obj)->kind) {
> +''',
> +                 name=name)
> +
> +    push_indent()
> +    push_indent()
> +    for key in members:
> +        ret += mcgen('''
> +            case %(abbrev)s_KIND_%(enum)s:
> +                visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
> +                break;
> +''',
> +                abbrev = de_camel_case(name).upper(),
> +                enum = c_fun(de_camel_case(key)).upper(),
> +                c_type=members[key],
> +                c_name=c_fun(key))
> +
> +    ret += mcgen('''
> +            default:
> +                abort();
> +            }
> +        }
> +        error_propagate(errp, err);
> +        err = NULL;
> +    }
> +''')
> +    pop_indent()
> +    ret += mcgen('''
> +        /* Always call end_struct if start_struct succeeded.  */
> +        visit_end_struct(m, &err);
> +    }
> +    error_propagate(errp, err);
> +}
> +''')
> +
> +    pop_indent();
> +    ret += mcgen('''
> +}
> +''')
> +
> +    return ret
> +
> +def generate_declaration(name, members, genlist=True):
> +    ret = mcgen('''
> +
> +void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
> +''',
> +                name=name)
> +
> +    if genlist:
> +        ret += mcgen('''
> +void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
> +''',
> +                 name=name)
> +
> +    return ret
> +
> +def generate_decl_enum(name, members, genlist=True):
> +    return mcgen('''
> +
> +void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
> +''',
> +                name=name)
> +
> +try:
> +    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
> +                                   ["source", "header", "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'
> +
> +do_c = False
> +do_h = False
> +
> +for o, a in opts:
> +    if o in ("-p", "--prefix"):
> +        prefix = a
> +    elif o in ("-o", "--output-dir"):
> +        output_dir = a + "/"
> +    elif o in ("-c", "--source"):
> +        do_c = True
> +    elif o in ("-h", "--header"):
> +        do_h = True
> +
> +if not do_c and not do_h:
> +    do_c = True
> +    do_h = True
> +
> +c_file = output_dir + prefix + c_file
> +h_file = output_dir + prefix + h_file
> +
> +try:
> +    os.makedirs(output_dir)
> +except os.error, e:
> +    if e.errno != errno.EEXIST:
> +        raise
> +
> +def maybe_open(really, name, opt):
> +    if really:
> +        return open(name, opt)
> +    else:
> +        import StringIO
> +        return StringIO.StringIO()
> +
> +fdef = maybe_open(do_c, c_file, 'w')
> +fdecl = maybe_open(do_h, h_file, 'w')
> +
> +fdef.write(mcgen('''
> +/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +
> +/*
> + * schema-defined QAPI visitor functions
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "%(header)s"
> +''',
> +                 header=basename(h_file)))
> +
> +fdecl.write(mcgen('''
> +/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +
> +/*
> + * schema-defined QAPI visitor function
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef %(guard)s
> +#define %(guard)s
> +
> +#include "qapi/qapi-visit-core.h"
> +#include "%(prefix)sqapi-types.h"
> +''',
> +                  prefix=prefix, guard=guardname(h_file)))
> +
> +exprs = parse_schema(sys.stdin)
> +
> +for expr in exprs:
> +    if expr.has_key('type'):
> +        ret = generate_visit_struct(expr['type'], expr['data'])
> +        ret += generate_visit_list(expr['type'], expr['data'])
> +        fdef.write(ret)
> +
> +        ret = generate_declaration(expr['type'], expr['data'])
> +        fdecl.write(ret)
> +    elif expr.has_key('union'):
> +        ret = generate_visit_union(expr['union'], expr['data'])
> +        ret += generate_visit_list(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)
> +
> +fdecl.write('''
> +#endif
> +''')
> +
> +fdecl.flush()
> +fdecl.close()
> +
> +fdef.flush()
> +fdef.close()
> diff --git a/tests/Makefile b/tests/Makefile
> index 9675ba7..8bbac75 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -55,8 +55,8 @@ tests/test-qapi-types.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
>  tests/test-qapi-visit.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
> +$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_visit.py
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
>  tests/test-qmp-commands.h tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module Michael Roth
@ 2012-07-24 22:13   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:13 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori


> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  scripts/qapi_visit.py |  143 +++++++++++++++++++++++++------------------------
>  1 file changed, 74 insertions(+), 69 deletions(-)
>
> diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
> index 04ef7c4..25707f5 100644
> --- a/scripts/qapi_visit.py
> +++ b/scripts/qapi_visit.py
> @@ -224,55 +224,57 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e
>  ''',
>                  name=name)
>  
> -try:
> -    opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
> -                                   ["source", "header", "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'
> -
> -do_c = False
> -do_h = False
> -
> -for o, a in opts:
> -    if o in ("-p", "--prefix"):
> -        prefix = a
> -    elif o in ("-o", "--output-dir"):
> -        output_dir = a + "/"
> -    elif o in ("-c", "--source"):
> +def main(argv=[]):
> +    try:
> +        opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
> +                                       ["source", "header", "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'
> +
> +    do_c = False
> +    do_h = False
> +
> +    for o, a in opts:
> +        if o in ("-p", "--prefix"):
> +            prefix = a
> +        elif o in ("-o", "--output-dir"):
> +            output_dir = a + "/"
> +        elif o in ("-c", "--source"):
> +            do_c = True
> +        elif o in ("-h", "--header"):
> +            do_h = True
> +
> +    if not do_c and not do_h:
>          do_c = True
> -    elif o in ("-h", "--header"):
>          do_h = True
>  
> -if not do_c and not do_h:
> -    do_c = True
> -    do_h = True
> +    c_file = output_dir + prefix + c_file
> +    h_file = output_dir + prefix + h_file
>  
> -c_file = output_dir + prefix + c_file
> -h_file = output_dir + prefix + h_file
> +    try:
> +        os.makedirs(output_dir)
> +    except os.error, e:
> +        if e.errno != errno.EEXIST:
> +            raise
>  
> -try:
> -    os.makedirs(output_dir)
> -except os.error, e:
> -    if e.errno != errno.EEXIST:
> -        raise
> -
> -def maybe_open(really, name, opt):
> -    if really:
> -        return open(name, opt)
> -    else:
> -        import StringIO
> -        return StringIO.StringIO()
> +    def maybe_open(really, name, opt):
> +        if really:
> +            return open(name, opt)
> +        else:
> +            import StringIO
> +            return StringIO.StringIO()
>  
> -fdef = maybe_open(do_c, c_file, 'w')
> -fdecl = maybe_open(do_h, h_file, 'w')
> +    fdef = maybe_open(do_c, c_file, 'w')
> +    fdecl = maybe_open(do_h, h_file, 'w')
>  
> -fdef.write(mcgen('''
> +    fdef.write(mcgen('''
>  /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
>  
>  /*
> @@ -292,7 +294,7 @@ fdef.write(mcgen('''
>  ''',
>                   header=basename(h_file)))
>  
> -fdecl.write(mcgen('''
> +    fdecl.write(mcgen('''
>  /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
>  
>  /*
> @@ -316,37 +318,40 @@ fdecl.write(mcgen('''
>  ''',
>                    prefix=prefix, guard=guardname(h_file)))
>  
> -exprs = parse_schema(sys.stdin)
> +    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)
> +    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'])
> -        ret += generate_visit_list(expr['union'], 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'])
> +            ret += generate_visit_list(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('%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)
> +            ret = generate_decl_enum(expr['enum'], expr['data'])
> +            fdecl.write(ret)
>  
> -fdecl.write('''
> +    fdecl.write('''
>  #endif
> -''')
> +    ''')
> +
> +    fdecl.flush()
> +    fdecl.close()
>  
> -fdecl.flush()
> -fdecl.close()
> +    fdef.flush()
> +    fdef.close()
>  
> -fdef.flush()
> -fdef.close()
> +if __name__ == '__main__':
> +    sys.exit(main(sys.argv))
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions Michael Roth
@ 2012-07-24 22:16   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:16 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

> Add support for arrays in the code generators.
>
> Complex field descriptions can now be used to provide additional
> information to the visitor generators, such as the max size of an array,
> or the field within a struct to use to determine how many elements are
> present in the array to avoid serializing uninitialized elements.
>
> Add handling for these in the code generators as well.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  scripts/qapi.py          |   10 ++++++++--
>  scripts/qapi_commands.py |    8 ++++----
>  scripts/qapi_types.py    |    2 +-
>  scripts/qapi_visit.py    |   34 +++++++++++++++++++++++++++-------
>  4 files changed, 40 insertions(+), 14 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 8082af3..39bb74e 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -99,12 +99,16 @@ def parse_args(typeinfo):
>          argentry = typeinfo[member]
>          optional = False
>          structured = False
> +        annotated = False
>          if member.startswith('*'):
>              argname = member[1:]
>              optional = True
>          if isinstance(argentry, OrderedDict):
> -            structured = True
> -        yield (argname, argentry, optional, structured)
> +            if argentry.has_key('<annotated>'):
> +                annotated = True
> +            else:
> +                structured = True
> +        yield (argname, argentry, optional, structured, annotated)
>  
>  def de_camel_case(name):
>      new_name = ''
> @@ -177,6 +181,8 @@ def c_type(name):
>          return 'void'
>      elif name == name.upper():
>          return '%sEvent *' % camel_case(name)
> +    elif name.replace("u", "").replace("int", "") in ["8", "16", "32", "64"]:
> +        return name + "_t"
>      else:
>          return '%s *' % name
>  
> diff --git a/scripts/qapi_commands.py b/scripts/qapi_commands.py
> index 9eed40e..52221d6 100644
> --- a/scripts/qapi_commands.py
> +++ b/scripts/qapi_commands.py
> @@ -32,7 +32,7 @@ void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
>  
>  def generate_command_decl(name, args, ret_type):
>      arglist=""
> -    for argname, argtype, optional, structured in parse_args(args):
> +    for argname, argtype, optional, structured, annotated in parse_args(args):
>          argtype = c_type(argtype)
>          if argtype == "char *":
>              argtype = "const char *"
> @@ -50,7 +50,7 @@ def gen_sync_call(name, args, ret_type, indent=0):
>      retval=""
>      if ret_type:
>          retval = "retval = "
> -    for argname, argtype, optional, structured in parse_args(args):
> +    for argname, argtype, optional, structured, annotated in parse_args(args):
>          if optional:
>              arglist += "has_%s, " % c_var(argname)
>          arglist += "%s, " % (c_var(argname))
> @@ -106,7 +106,7 @@ Visitor *v;
>  def gen_visitor_input_vars_decl(args):
>      ret = ""
>      push_indent()
> -    for argname, argtype, optional, structured in parse_args(args):
> +    for argname, argtype, optional, structured, annotated in parse_args(args):
>          if optional:
>              ret += mcgen('''
>  bool has_%(argname)s = false;
> @@ -145,7 +145,7 @@ v = qmp_input_get_visitor(mi);
>  ''',
>                       obj=obj)
>  
> -    for argname, argtype, optional, structured in parse_args(args):
> +    for argname, argtype, optional, structured, annotated in parse_args(args):
>          if optional:
>              ret += mcgen('''
>  visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
> diff --git a/scripts/qapi_types.py b/scripts/qapi_types.py
> index 4a734f5..fb2b9ea 100644
> --- a/scripts/qapi_types.py
> +++ b/scripts/qapi_types.py
> @@ -35,7 +35,7 @@ struct %(name)s
>  ''',
>            name=structname)
>  
> -    for argname, argentry, optional, structured in parse_args(members):
> +    for argname, argentry, optional, structured, annotated in parse_args(members):
>          if optional:
>              ret += mcgen('''
>      bool has_%(c_name)s;
> diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
> index 25707f5..9839e3c 100644
> --- a/scripts/qapi_visit.py
> +++ b/scripts/qapi_visit.py
> @@ -16,6 +16,22 @@ import sys
>  import os
>  import getopt
>  import errno
> +import types
> +
> +def generate_visit_array_body(name, info):
> +    ret = mcgen('''
> +visit_start_array(m, (void **)obj, "%(name)s", %(count)s, sizeof(%(type)s), errp);
> +int %(name)s_i;
> +for (%(name)s_i = 0; %(name)s_i < %(count)s; %(name)s_i++) {
> +    visit_type_%(type_short)s(m, &(*obj)->%(name)s[%(name)s_i], NULL, errp);
> +    visit_next_array(m, errp);
> +}
> +visit_end_array(m, errp);
> +''',
> +                name=name, type=c_type(info['type'][0]),
> +                type_short=info['type'][0],
> +                count=info['array_size'])
> +    return ret
>  
>  def generate_visit_struct_body(field_prefix, name, members):
>      ret = mcgen('''
> @@ -45,10 +61,10 @@ if (!err) {
>  
>      push_indent()
>      push_indent()
> -    for argname, argentry, optional, structured in parse_args(members):
> +    for argname, argentry, optional, structured, annotated in parse_args(members):
>          if optional:
>              ret += mcgen('''
> -visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
> +visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", errp);
>  if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
>  ''',
>                           c_prefix=c_var(field_prefix), prefix=field_prefix,
> @@ -58,12 +74,16 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
>          if structured:
>              ret += generate_visit_struct_body(field_prefix + argname, argname, argentry)
>          else:
> -            ret += mcgen('''
> -visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
> +            if annotated:
> +                if isinstance(argentry['type'], types.ListType):
> +                    ret += generate_visit_array_body(argname, argentry)
> +            else:
> +                ret += mcgen('''
> +visit_type_%(type)s(m, 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)
> +                             c_prefix=c_var(field_prefix), prefix=field_prefix,
> +                             type=type_name(argentry), c_name=c_var(argname),
> +                             name=argname)
>  
>          if optional:
>              pop_indent()
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 06/22] qapi: add visitor interfaces for arrays
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 06/22] qapi: add visitor interfaces for arrays Michael Roth
@ 2012-07-24 22:18   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:18 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  qapi/qapi-visit-core.c |   25 +++++++++++++++++++++++++
>  qapi/qapi-visit-core.h |    8 ++++++++
>  scripts/qapi_visit.py  |   28 ++++++++++++++++++++++++++++
>  3 files changed, 61 insertions(+)
>
> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
> index 7a82b63..631387d 100644
> --- a/qapi/qapi-visit-core.c
> +++ b/qapi/qapi-visit-core.c
> @@ -311,3 +311,28 @@ void input_type_enum(Visitor *v, int *obj, const char *strings[],
>      g_free(enum_str);
>      *obj = value;
>  }
> +
> +void visit_start_array(Visitor *v, void **obj, const char *name,
> +                       size_t elem_count, size_t elem_size, Error
> **errp)

So this is a C style single dimension array?  Can we at least call this
c_array then or something like that.

Regards,

Anthony Liguori

> +{
> +    g_assert(v->start_array);
> +    if (!error_is_set(errp)) {
> +        v->start_array(v, obj, name, elem_count, elem_size, errp);
> +    }
> +}
> +
> +void visit_next_array(Visitor *v, Error **errp)
> +{
> +    g_assert(v->next_array);
> +    if (!error_is_set(errp)) {
> +        v->next_array(v, errp);
> +    }
> +}
> +
> +void visit_end_array(Visitor *v, Error **errp)
> +{
> +    g_assert(v->end_array);
> +    if (!error_is_set(errp)) {
> +        v->end_array(v, errp);
> +    }
> +}
> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
> index 60aceda..4a7bdb6 100644
> --- a/qapi/qapi-visit-core.h
> +++ b/qapi/qapi-visit-core.h
> @@ -43,6 +43,10 @@ struct Visitor
>      void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
>      void (*type_number)(Visitor *v, double *obj, const char *name,
>                          Error **errp);
> +    void (*start_array)(Visitor *v, void **obj, const char *name,
> +                        size_t elem_count, size_t elem_size, Error **errp);
> +    void (*next_array)(Visitor *v, Error **errp);
> +    void (*end_array)(Visitor *v, Error **errp);
>  
>      /* May be NULL */
>      void (*start_optional)(Visitor *v, bool *present, const char *name,
> @@ -91,5 +95,9 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
>  void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
>  void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
>  void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
> +void visit_start_array(Visitor *v, void **obj, const char *name,
> +                       size_t elem_count, size_t elem_size, Error **errp);
> +void visit_next_array(Visitor *v, Error **errp);
> +void visit_end_array(Visitor *v, Error **errp);
>  
>  #endif
> diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
> index 9839e3c..bf93bfe 100644
> --- a/scripts/qapi_visit.py
> +++ b/scripts/qapi_visit.py
> @@ -33,6 +33,34 @@ visit_end_array(m, errp);
>                  count=info['array_size'])
>      return ret
>  
> +def generate_visit_array_body(name, info):
> +    if info['array_size'][0].isdigit():
> +        array_size = info['array_size']
> +    elif info['array_size'][0] == '(' and info['array_size'][-1] == ')':
> +        array_size = info['array_size']
> +    else:
> +        array_size = "(*obj)->%s" % info['array_size']
> +
> +    if info.has_key('array_capacity'):
> +        array_capacity = info['array_capacity']
> +    else:
> +        array_capacity = array_size
> +
> +    ret = mcgen('''
> +visit_start_array(m, (void **)obj, "%(name)s", %(array_capacity)s, sizeof(%(type)s), errp);
> +int %(name)s_i;
> +for (%(name)s_i = 0; %(name)s_i < %(array_size)s; %(name)s_i++) {
> +    visit_type_%(type_short)s(m, &(*obj)->%(name)s[%(name)s_i], NULL, errp);
> +    visit_next_array(m, errp);
> +}
> +visit_end_array(m, errp);
> +''',
> +                name=name, type=c_type(info['type'][0]),
> +                type_short=info['type'][0],
> +                array_size=array_size,
> +                array_capacity=array_capacity)
> +    return ret
> +
>  def generate_visit_struct_body(field_prefix, name, members):
>      ret = mcgen('''
>  if (!error_is_set(errp)) {
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support generating static functions
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support generating static functions Michael Roth
@ 2012-07-24 22:19   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:19 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

> qidl embeds visitor code into object files rather than linking against
> seperate files, so allow for static declarations when we're using
> qapi_visit.py as a library as we do with qidl.py
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  scripts/qapi_visit.py |   51 ++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 33 insertions(+), 18 deletions(-)
>
> diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
> index bf93bfe..864acb2 100644
> --- a/scripts/qapi_visit.py
> +++ b/scripts/qapi_visit.py
> @@ -139,13 +139,16 @@ visit_end_optional(m, &err);
>  ''')
>      return ret
>  
> -def generate_visit_struct(name, members):
> +def generate_visit_struct(name, members, static=False):
> +    ret_type = "void"
> +    if static:
> +        ret_type = "static " + ret_type
>      ret = mcgen('''
>  
> -void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
> +%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
>  {
>  ''',
> -                name=name)
> +                name=name, ret_type=ret_type)
>  
>      push_indent()
>      ret += generate_visit_struct_body("", name, members)
> @@ -156,10 +159,13 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
>  ''')
>      return ret
>  
> -def generate_visit_list(name, members):
> +def generate_visit_list(name, members, static=False):
> +    ret_type = "void"
> +    if static:
> +        ret_type = "static " + ret_type
>      return mcgen('''
>  
> -void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
> +%(ret_type)s visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
>  {
>      GenericList *i, **prev = (GenericList **)obj;
>      Error *err = NULL;
> @@ -181,19 +187,22 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name,
>      }
>  }
>  ''',
> -                name=name)
> +                name=name, ret_type=ret_type)
>  
> -def generate_visit_enum(name, members):
> +def generate_visit_enum(name, members, static=False):
> +    ret_type = "void"
> +    if static:
> +        ret_type = "static " + ret_type
>      return mcgen('''
>  
> -void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
> +%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
>  {
>      visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
>  }
>  ''',
> -                 name=name)
> +                 name=name, ret_type=ret_type)
>  
> -def generate_visit_union(name, members):
> +def generate_visit_union(name, members, static=False):
>      ret = generate_visit_enum('%sKind' % name, members.keys())
>  
>      ret += mcgen('''
> @@ -250,27 +259,33 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
>  
>      return ret
>  
> -def generate_declaration(name, members, genlist=True):
> +def generate_declaration(name, members, genlist=True, static=False):
> +    ret_type = "void"
> +    if static:
> +        ret_type = "static " + ret_type
>      ret = mcgen('''
>  
> -void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
> +%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
>  ''',
> -                name=name)
> +                name=name, ret_type=ret_type)
>  
>      if genlist:
>          ret += mcgen('''
> -void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
> +%(ret_type)s visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
>  ''',
> -                 name=name)
> +                 name=name, ret_type=ret_type)
>  
>      return ret
>  
> -def generate_decl_enum(name, members, genlist=True):
> +def generate_decl_enum(name, members, genlist=True, static=False):
> +    ret_type = "void"
> +    if static:
> +        ret_type = "static " + ret_type
>      return mcgen('''
>  
> -void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
> +%(ret_type)s visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
>  ''',
> -                name=name)
> +                name=name, ret_type=ret_type)
>  
>  def main(argv=[]):
>      try:
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 08/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 08/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs Michael Roth
@ 2012-07-24 22:21   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:21 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  scripts/qapi_visit.py |    9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/scripts/qapi_visit.py b/scripts/qapi_visit.py
> index 864acb2..8f8cdca 100644
> --- a/scripts/qapi_visit.py
> +++ b/scripts/qapi_visit.py
> @@ -105,6 +105,15 @@ if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
>              if annotated:
>                  if isinstance(argentry['type'], types.ListType):
>                      ret += generate_visit_array_body(argname, argentry)
> +                elif argentry.has_key('<embedded struct>'):
> +                    tmp_ptr_name = "%s_%s_ptr" % (c_var(field_prefix).replace(".", ""), c_var(argname))
> +                    ret += mcgen('''
> +%(type)s *%(tmp_ptr)s = &(*obj)->%(c_prefix)s%(c_name)s;
> +visit_type_%(type)s(m, (obj && *obj) ? &%(tmp_ptr)s : NULL, "%(name)s", errp);
> +''',
> +                                 c_prefix=c_var(field_prefix), prefix=field_prefix,
> +                                 type=type_name(argentry['type']), c_name=c_var(argname),
> +                                 name=argname, tmp_ptr=tmp_ptr_name)
>              else:
>                  ret += mcgen('''
>  visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", errp);
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust Michael Roth
@ 2012-07-24 22:23   ` Anthony Liguori
  2012-07-24 22:59     ` Michael Roth
  0 siblings, 1 reply; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:23 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

> Currently the QAPI JSON parser expects a very particular style of code
> indentation, the major one being that terminating curly/square brackets are
> not on placed on a seperate line. This is incompatible with most
> pretty-print formats, so make it a little more robust by supporting
> these cases.

The code was supposed to just expect that all subsequent lines are
indented.  This was to simplify the parser.  Can you provide an
problematic example?

Regards,

Anthony Liguori
[...]

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

* Re: [Qemu-devel] [PATCH 11/22] qapi: add open-coded visitor for struct tm types
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 11/22] qapi: add open-coded visitor for struct tm types Michael Roth
@ 2012-07-24 22:24   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:24 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  qapi/Makefile.objs     |    1 +
>  qapi/misc-qapi-visit.c |   14 ++++++++++++++
>  qapi/qapi-visit-core.h |    3 +++
>  3 files changed, 18 insertions(+)
>  create mode 100644 qapi/misc-qapi-visit.c
>
> diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
> index 5f5846e..7604b52 100644
> --- a/qapi/Makefile.objs
> +++ b/qapi/Makefile.objs
> @@ -1,3 +1,4 @@
>  qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
>  qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
>  qapi-obj-y += string-input-visitor.o string-output-visitor.o opts-visitor.o
> +qapi-obj-y += misc-qapi-visit.o
> diff --git a/qapi/misc-qapi-visit.c b/qapi/misc-qapi-visit.c
> new file mode 100644
> index 0000000..a44773d
> --- /dev/null
> +++ b/qapi/misc-qapi-visit.c
> @@ -0,0 +1,14 @@
> +#include <time.h>
> +#include "qidl.h"
> +
> +void visit_type_tm(Visitor *v, struct tm *obj, const char *name, Error **errp)
> +{
> +    visit_start_struct(v, NULL, "struct tm", name, 0, errp);
> +    visit_type_int32(v, &obj->tm_year, "tm_year", errp);
> +    visit_type_int32(v, &obj->tm_mon, "tm_mon", errp);
> +    visit_type_int32(v, &obj->tm_mday, "tm_mday", errp);
> +    visit_type_int32(v, &obj->tm_hour, "tm_hour", errp);
> +    visit_type_int32(v, &obj->tm_min, "tm_min", errp);
> +    visit_type_int32(v, &obj->tm_sec, "tm_sec", errp);
> +    visit_end_struct(v, errp);
> +}
> diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h
> index 4a7bdb6..6af9f5e 100644
> --- a/qapi/qapi-visit-core.h
> +++ b/qapi/qapi-visit-core.h
> @@ -100,4 +100,7 @@ void visit_start_array(Visitor *v, void **obj, const char *name,
>  void visit_next_array(Visitor *v, Error **errp);
>  void visit_end_array(Visitor *v, Error **errp);
>  
> +/* misc. visitors */
> +void visit_type_tm(Visitor *m, struct tm *obj, const char *name, Error **errp);
> +
>  #endif
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 12/22] qom-fuse: workaround for truncated properties > 4096
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 12/22] qom-fuse: workaround for truncated properties > 4096 Michael Roth
@ 2012-07-24 22:26   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:26 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

I don't think this is the most correct solution but I think it's good
enough in practice so

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Regards,

Anthony Liguori

> We currently hard-code property size at 4096 for the purposes of
> getattr()/stat()/etc. For 'state' properties we can exceed this easily,
> leading to truncated responses.
>
> Instead, for a particular property, make it
> max(4096, most_recent_property_size * 2). This allows some
> head-room for properties that change size periodically (numbers,
> strings, state properties containing arrays, etc)
>
> Also, implement a simple property cache to avoid spinning on qom-get
> if an application reads beyond the actual size. This also allows us
> to use a snapshot of a single qom-get that persists across read()'s.
> Old Cache entries are evicted as soon as we attempt to read() from
> offset 0 again.
>
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  QMP/qom-fuse |   24 +++++++++++++++++-------
>  1 file changed, 17 insertions(+), 7 deletions(-)
>
> diff --git a/QMP/qom-fuse b/QMP/qom-fuse
> index 5c6754a..bd43f29 100755
> --- a/QMP/qom-fuse
> +++ b/QMP/qom-fuse
> @@ -26,6 +26,7 @@ class QOMFS(Fuse):
>          self.qmp.connect()
>          self.ino_map = {}
>          self.ino_count = 1
> +        self.prop_cache = {}
>  
>      def get_ino(self, path):
>          if self.ino_map.has_key(path):
> @@ -67,12 +68,16 @@ class QOMFS(Fuse):
>          if not self.is_property(path):
>              return -ENOENT
>  
> -        path, prop = path.rsplit('/', 1)
> -        try:
> -            data = str(self.qmp.command('qom-get', path=path, property=prop))
> -            data += '\n' # make values shell friendly
> -        except:
> -            return -EPERM
> +        # avoid extra calls to qom-get by using cached value when offset > 0
> +        if offset == 0 or not self.prop_cache.has_key(path):
> +            directory, prop = path.rsplit('/', 1)
> +            try:
> +                resp = str(self.qmp.command('qom-get', path=directory, property=prop))
> +                self.prop_cache[path] = resp + '\n' # make values shell friendly
> +            except:
> +                return -EPERM
> +
> +        data = self.prop_cache[path]
>  
>          if offset > len(data):
>              return ''
> @@ -111,13 +116,18 @@ class QOMFS(Fuse):
>                                         0,
>                                         0))
>          elif self.is_property(path):
> +            directory, prop = path.rsplit('/', 1)
> +            try:
> +                resp = str(self.qmp.command('qom-get', path=directory, property=prop))
> +            except:
> +                return -ENOENT
>              value = posix.stat_result((0644 | stat.S_IFREG,
>                                         self.get_ino(path),
>                                         0,
>                                         1,
>                                         1000,
>                                         1000,
> -                                       4096,
> +                                       max(len(resp) * 2, 4096),
>                                         0,
>                                         0,
>                                         0))
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 14/22] qdev: move Property-related declarations to qdev-properties.h
  2012-07-24 17:20 ` [Qemu-devel] [PATCH 14/22] qdev: move Property-related declarations to qdev-properties.h Michael Roth
@ 2012-07-24 22:28   ` Anthony Liguori
  0 siblings, 0 replies; 37+ messages in thread
From: Anthony Liguori @ 2012-07-24 22:28 UTC (permalink / raw)
  To: Michael Roth, qemu-devel
  Cc: quintela, owasserm, yamahata, pbonzini, akong, afaerber

Michael Roth <mdroth@linux.vnet.ibm.com> writes:

License please.

Regards,

Anthony Liguori

> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  hw/qdev-properties.h |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/qdev.h            |  126 +-----------------------------------------------
>  2 files changed, 131 insertions(+), 125 deletions(-)
>  create mode 100644 hw/qdev-properties.h
>
> diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
> new file mode 100644
> index 0000000..329ef70
> --- /dev/null
> +++ b/hw/qdev-properties.h
> @@ -0,0 +1,130 @@
> +#ifndef QDEV_PROPERTIES_H
> +#define QDEV_PROPERTIES_H
> +
> +#include "qemu/object.h"
> +#include "qemu-queue.h"
> +
> +typedef struct Property Property;
> +
> +typedef struct PropertyInfo PropertyInfo;
> +
> +struct Property {
> +    const char   *name;
> +    PropertyInfo *info;
> +    int          offset;
> +    uint8_t      bitnr;
> +    uint8_t      qtype;
> +    int64_t      defval;
> +};
> +
> +struct PropertyInfo {
> +    const char *name;
> +    const char *legacy_name;
> +    const char **enum_table;
> +    int (*parse)(DeviceState *dev, Property *prop, const char *str);
> +    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
> +    ObjectPropertyAccessor *get;
> +    ObjectPropertyAccessor *set;
> +    ObjectPropertyRelease *release;
> +};
> +
> +typedef struct GlobalProperty {
> +    const char *driver;
> +    const char *property;
> +    const char *value;
> +    QTAILQ_ENTRY(GlobalProperty) next;
> +} GlobalProperty;
> +
> +extern PropertyInfo qdev_prop_bit;
> +extern PropertyInfo qdev_prop_uint8;
> +extern PropertyInfo qdev_prop_uint16;
> +extern PropertyInfo qdev_prop_uint32;
> +extern PropertyInfo qdev_prop_int32;
> +extern PropertyInfo qdev_prop_uint64;
> +extern PropertyInfo qdev_prop_hex8;
> +extern PropertyInfo qdev_prop_hex32;
> +extern PropertyInfo qdev_prop_hex64;
> +extern PropertyInfo qdev_prop_string;
> +extern PropertyInfo qdev_prop_chr;
> +extern PropertyInfo qdev_prop_ptr;
> +extern PropertyInfo qdev_prop_macaddr;
> +extern PropertyInfo qdev_prop_losttickpolicy;
> +extern PropertyInfo qdev_prop_bios_chs_trans;
> +extern PropertyInfo qdev_prop_drive;
> +extern PropertyInfo qdev_prop_netdev;
> +extern PropertyInfo qdev_prop_vlan;
> +extern PropertyInfo qdev_prop_pci_devfn;
> +extern PropertyInfo qdev_prop_blocksize;
> +extern PropertyInfo qdev_prop_pci_host_devaddr;
> +
> +#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
> +        .name      = (_name),                                    \
> +        .info      = &(_prop),                                   \
> +        .offset    = offsetof(_state, _field)                    \
> +            + type_check(_type,typeof_field(_state, _field)),    \
> +        }
> +#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
> +        .name      = (_name),                                           \
> +        .info      = &(_prop),                                          \
> +        .offset    = offsetof(_state, _field)                           \
> +            + type_check(_type,typeof_field(_state, _field)),           \
> +        .qtype     = QTYPE_QINT,                                        \
> +        .defval    = (_type)_defval,                                    \
> +        }
> +#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
> +        .name      = (_name),                                    \
> +        .info      = &(qdev_prop_bit),                           \
> +        .bitnr    = (_bit),                                      \
> +        .offset    = offsetof(_state, _field)                    \
> +            + type_check(uint32_t,typeof_field(_state, _field)), \
> +        .qtype     = QTYPE_QBOOL,                                \
> +        .defval    = (bool)_defval,                              \
> +        }
> +
> +#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
> +#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
> +#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
> +#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
> +#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
> +#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
> +#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
> +#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
> +#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
> +
> +#define DEFINE_PROP_PTR(_n, _s, _f)             \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
> +#define DEFINE_PROP_CHR(_n, _s, _f)             \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
> +#define DEFINE_PROP_STRING(_n, _s, _f)             \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
> +#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
> +#define DEFINE_PROP_VLAN(_n, _s, _f)             \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
> +#define DEFINE_PROP_DRIVE(_n, _s, _f) \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
> +#define DEFINE_PROP_MACADDR(_n, _s, _f)         \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
> +#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
> +                        LostTickPolicy)
> +#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
> +#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
> +    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
> +#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
> +    DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
> +
> +#define DEFINE_PROP_END_OF_LIST()               \
> +    {}
> +
> +#endif
> diff --git a/hw/qdev.h b/hw/qdev.h
> index a2cbd9d..c9b5453 100644
> --- a/hw/qdev.h
> +++ b/hw/qdev.h
> @@ -8,10 +8,7 @@
>  #include "qapi/qapi-visit-core.h"
>  #include "qemu/object.h"
>  #include "error.h"
> -
> -typedef struct Property Property;
> -
> -typedef struct PropertyInfo PropertyInfo;
> +#include "qdev-properties.h"
>  
>  typedef struct CompatProperty CompatProperty;
>  
> @@ -122,33 +119,6 @@ struct BusState {
>      QLIST_ENTRY(BusState) sibling;
>  };
>  
> -struct Property {
> -    const char   *name;
> -    PropertyInfo *info;
> -    int          offset;
> -    uint8_t      bitnr;
> -    uint8_t      qtype;
> -    int64_t      defval;
> -};
> -
> -struct PropertyInfo {
> -    const char *name;
> -    const char *legacy_name;
> -    const char **enum_table;
> -    int (*parse)(DeviceState *dev, Property *prop, const char *str);
> -    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
> -    ObjectPropertyAccessor *get;
> -    ObjectPropertyAccessor *set;
> -    ObjectPropertyRelease *release;
> -};
> -
> -typedef struct GlobalProperty {
> -    const char *driver;
> -    const char *property;
> -    const char *value;
> -    QTAILQ_ENTRY(GlobalProperty) next;
> -} GlobalProperty;
> -
>  /*** Board API.  This should go away once we have a machine config file.  ***/
>  
>  DeviceState *qdev_create(BusState *bus, const char *name);
> @@ -215,100 +185,6 @@ void do_info_qdm(Monitor *mon);
>  int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
>  int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
>  
> -/*** qdev-properties.c ***/
> -
> -extern PropertyInfo qdev_prop_bit;
> -extern PropertyInfo qdev_prop_uint8;
> -extern PropertyInfo qdev_prop_uint16;
> -extern PropertyInfo qdev_prop_uint32;
> -extern PropertyInfo qdev_prop_int32;
> -extern PropertyInfo qdev_prop_uint64;
> -extern PropertyInfo qdev_prop_hex8;
> -extern PropertyInfo qdev_prop_hex32;
> -extern PropertyInfo qdev_prop_hex64;
> -extern PropertyInfo qdev_prop_string;
> -extern PropertyInfo qdev_prop_chr;
> -extern PropertyInfo qdev_prop_ptr;
> -extern PropertyInfo qdev_prop_macaddr;
> -extern PropertyInfo qdev_prop_losttickpolicy;
> -extern PropertyInfo qdev_prop_bios_chs_trans;
> -extern PropertyInfo qdev_prop_drive;
> -extern PropertyInfo qdev_prop_netdev;
> -extern PropertyInfo qdev_prop_vlan;
> -extern PropertyInfo qdev_prop_pci_devfn;
> -extern PropertyInfo qdev_prop_blocksize;
> -extern PropertyInfo qdev_prop_pci_host_devaddr;
> -
> -#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
> -        .name      = (_name),                                    \
> -        .info      = &(_prop),                                   \
> -        .offset    = offsetof(_state, _field)                    \
> -            + type_check(_type,typeof_field(_state, _field)),    \
> -        }
> -#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
> -        .name      = (_name),                                           \
> -        .info      = &(_prop),                                          \
> -        .offset    = offsetof(_state, _field)                           \
> -            + type_check(_type,typeof_field(_state, _field)),           \
> -        .qtype     = QTYPE_QINT,                                        \
> -        .defval    = (_type)_defval,                                    \
> -        }
> -#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
> -        .name      = (_name),                                    \
> -        .info      = &(qdev_prop_bit),                           \
> -        .bitnr    = (_bit),                                      \
> -        .offset    = offsetof(_state, _field)                    \
> -            + type_check(uint32_t,typeof_field(_state, _field)), \
> -        .qtype     = QTYPE_QBOOL,                                \
> -        .defval    = (bool)_defval,                              \
> -        }
> -
> -#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
> -#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
> -#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
> -#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
> -#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
> -#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
> -#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
> -#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
> -#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
> -
> -#define DEFINE_PROP_PTR(_n, _s, _f)             \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
> -#define DEFINE_PROP_CHR(_n, _s, _f)             \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
> -#define DEFINE_PROP_STRING(_n, _s, _f)             \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
> -#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
> -#define DEFINE_PROP_VLAN(_n, _s, _f)             \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
> -#define DEFINE_PROP_DRIVE(_n, _s, _f) \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
> -#define DEFINE_PROP_MACADDR(_n, _s, _f)         \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
> -#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
> -                        LostTickPolicy)
> -#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
> -#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
> -    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
> -#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
> -    DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
> -
> -#define DEFINE_PROP_END_OF_LIST()               \
> -    {}
> -
>  /* Set properties between creation and init.  */
>  void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
>  int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
> -- 
> 1.7.9.5

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

* Re: [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust
  2012-07-24 22:23   ` Anthony Liguori
@ 2012-07-24 22:59     ` Michael Roth
  0 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-24 22:59 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: quintela, owasserm, qemu-devel, yamahata, pbonzini, akong,
	afaerber

On Tue, Jul 24, 2012 at 05:23:33PM -0500, Anthony Liguori wrote:
> Michael Roth <mdroth@linux.vnet.ibm.com> writes:
> 
> > Currently the QAPI JSON parser expects a very particular style of code
> > indentation, the major one being that terminating curly/square brackets are
> > not on placed on a seperate line. This is incompatible with most
> > pretty-print formats, so make it a little more robust by supporting
> > these cases.
> 
> The code was supposed to just expect that all subsequent lines are
> indented.  This was to simplify the parser.  Can you provide an
> problematic example?

The main one was cases like this:

    mdroth@loki:~/w/qemu3.git$ cat example.json 
    {
        'a': 'test'
    }
    mdroth@loki:~/w/qemu3.git$ python scripts/qapi-types.py -o /tmp <example.json 
    Traceback (most recent call last):
      File "scripts/qapi-types.py", line 260, in <module>
        exprs = parse_schema(sys.stdin)
      File "/home/mdroth/dev/kvm/qemu3.git/scripts/qapi.py", line 76, in parse_schema
        expr_eval = evaluate(expr)
      File "/home/mdroth/dev/kvm/qemu3.git/scripts/qapi.py", line 62, in evaluate
        return parse(map(lambda x: x, tokenize(string)))[0]
      File "/home/mdroth/dev/kvm/qemu3.git/scripts/qapi.py", line 42, in parse
        if tokens[0] == ',':
    IndexError: list index out of range

I had it in my queue because it was what was preventing me from pretty-printing
the QIDL-generated schemas in V1, since python's pretty print stuff generally
puts the opening/closing braces at the same indent level. But now we store them
in the binary, and don't pretty-print those, so I don't think this is an issue
WRT this series anymore. Might still make sense to add it for future use-cases
though.

> 
> Regards,
> 
> Anthony Liguori
> [...]
> 

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

* Re: [Qemu-devel] [PATCH 18/22] qidl: qidl.h
  2012-07-24 20:47   ` Blue Swirl
@ 2012-07-25  0:30     ` Michael Roth
  0 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-07-25  0:30 UTC (permalink / raw)
  To: Blue Swirl
  Cc: aliguori, yamahata, quintela, qemu-devel, owasserm, pbonzini,
	akong, afaerber

On Tue, Jul 24, 2012 at 08:47:44PM +0000, Blue Swirl wrote:
> On Tue, Jul 24, 2012 at 5:20 PM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> >
> > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> > ---
> >  qidl.h |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 58 insertions(+)
> >  create mode 100644 qidl.h
> >
> > diff --git a/qidl.h b/qidl.h
> > new file mode 100644
> > index 0000000..75ae5af
> > --- /dev/null
> > +++ b/qidl.h
> > @@ -0,0 +1,58 @@
> > +/*
> > + * QEMU IDL Macros/stubs
> > + *
> > + * See docs/qidl.txt for usage information.
> > + *
> > + * Copyright IBM, Corp. 2012
> > + *
> > + * Authors:
> > + *  Michael Roth    <mdroth@linux.vnet.ibm.com>
> > + *
> > + * This work is licensed under the terms of the GNU GPLv2.
> 
> GPLv2 or later?
> 

Yes, will fix.

> > + * See the COPYING file in the top-level directory.
> > + *
> > + */
> > +
> > +#ifndef QIDL_H
> > +#define QIDL_H
> > +
> > +#include "qapi/qapi-visit-core.h"
> > +#include "qemu/object.h"
> > +#include "hw/qdev-properties.h"
> > +
> > +#ifdef QIDL_GEN
> > +
> > +/* we pass the code through the preprocessor with QIDL_GEN defined to parse
> > + * structures as they'd appear after preprocessing, and use the following
> > + * definitions mostly to re-insert the initial macros/annotations so they
> > + * stick around for the parser to process
> 
> I guess this doesn't work if the file #includes itself, like some
> flash files used to do (or I can't find the example just now).
> 

Yikes... I haven't encountered such a beast yet, but I don't see why it
wouldn't work? This series uses it for cases where annotations are pulled
in via #includes, so a file #include'ing itself should be any different,
as far as I can imagine.

> > + */
> > +#define QIDL(...) QIDL(__VA_ARGS__)
> > +#define QIDL_START(...) QIDL_START(__VA_ARGS__)
> > +#define QIDL_END(...) QIDL_END(__VA_ARGS__)
> > +
> > +#define QIDL_VISIT_TYPE(...)
> > +#define QIDL_SCHEMA_ADD_LINK(...)
> > +#define QIDL_PROPERTIES(...)
> 
> Maybe for this pass, the macros which do nothing like above could
> still do more syntax checking by specifying the macro argument list
> instead of ellipsis or even by introducing a dummy inline function.
> 
> > +
> > +#else /* !QIDL_GEN */
> > +
> > +#define QIDL(...)
> > +#define QIDL_START(name, ...)
> 
> Declare 'struct type of name' here (see below)?
> 

I'd like to keep it more general so we can do things like annotate
unions/enums/etc if need be, and also to be able to easily define
away all the QIDL annotations via configure to identity build
issues potentially caused by QIDL.

Not sure, but I think it may also cause some annoyances for cscope/ctags
users, or even just grepping for a type definition.

> > +#define QIDL_END(name) \
> > +    static struct { \
> 
> 'const', how about a name for the struct type too?
> 
> > +        void (*visitor)(Visitor *, struct name **, const char *, Error **); \
> 
> Here 'struct name **' could be const if the struct defined here is
> const. Probably 'struct name' should be declared earlier.
> 

Taking a 'const struct name **' and passing it in as a 'struct name**'?

If so, I think this comes down to enforcing non-const structs by having QIDL
generate the declaration, or just letting the build generate a warning. The
former is safer, but for the reasons above I'd prefer the latter since it
allows us to use plain C for type declarations.

> > +        const char *schema_json_text; \
> > +        Object *schema_obj; \
> > +        Property *properties; \
> > +    } qidl_data_##name;
> > +
> > +#define QIDL_VISIT_TYPE(name, v, s, f, e) qidl_data_##name.visitor(v, s, f, e)
> > +#define QIDL_SCHEMA_ADD_LINK(name, obj, path, errp) \
> > +    object_property_add_link(obj, path, "container", \
> > +                             &qidl_data_##name.schema_obj, errp);
> 
> The semicolons here and below seem useless.
> 
> > +#define QIDL_PROPERTIES(name) qidl_data_##name.properties;
> > +
> > +#endif /* QIDL_GEN */
> > +
> > +#endif
> > --
> > 1.7.9.5
> >
> >
> 

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

* [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py
  2012-09-21 14:07 [Qemu-devel] [PATCH v2] Add infrastructure for QIDL-based device serialization Michael Roth
@ 2012-09-21 14:07 ` Michael Roth
  0 siblings, 0 replies; 37+ messages in thread
From: Michael Roth @ 2012-09-21 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, peter.maydell, aliguori, eblake

Python doesn't allow "-" in module names, so we need to rename the file
so we can re-use bits of the codegen

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile                                 |    8 ++++----
 scripts/{qapi-types.py => qapi_types.py} |    0
 tests/Makefile                           |    4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)
 rename scripts/{qapi-types.py => qapi_types.py} (100%)

diff --git a/Makefile b/Makefile
index b82f4a8..c1ccb47 100644
--- a/Makefile
+++ b/Makefile
@@ -185,8 +185,8 @@ endif
 qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
 
 qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_types.py $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
@@ -195,8 +195,8 @@ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-p
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 
 qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_types.py $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
 qapi-visit.c qapi-visit.h :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi_visit.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
diff --git a/scripts/qapi-types.py b/scripts/qapi_types.py
similarity index 100%
rename from scripts/qapi-types.py
rename to scripts/qapi_types.py
diff --git a/tests/Makefile b/tests/Makefile
index 58d5b3f..23a71f5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -52,8 +52,8 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools
 tests/test-iov$(EXESUF): tests/test-iov.o iov.o
 
 tests/test-qapi-types.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
+$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi_types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi_types.py $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 tests/test-qapi-visit.c tests/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 $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
-- 
1.7.9.5

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

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

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-24 17:20 [Qemu-devel] [RFC v2] Use QEMU IDL for device serialization/introspection Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import Michael Roth
2012-07-24 22:12   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 03/22] qapi: qapi-commands.py -> qapi_commands.py Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module Michael Roth
2012-07-24 22:13   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions Michael Roth
2012-07-24 22:16   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 06/22] qapi: add visitor interfaces for arrays Michael Roth
2012-07-24 22:18   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support generating static functions Michael Roth
2012-07-24 22:19   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 08/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs Michael Roth
2012-07-24 22:21   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 09/22] qapi: QmpOutputVisitor, implement array handling Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 10/22] qapi: qapi.py, make json parser more robust Michael Roth
2012-07-24 22:23   ` Anthony Liguori
2012-07-24 22:59     ` Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 11/22] qapi: add open-coded visitor for struct tm types Michael Roth
2012-07-24 22:24   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 12/22] qom-fuse: workaround for truncated properties > 4096 Michael Roth
2012-07-24 22:26   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 13/22] module additions for schema registration Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 14/22] qdev: move Property-related declarations to qdev-properties.h Michael Roth
2012-07-24 22:28   ` Anthony Liguori
2012-07-24 17:20 ` [Qemu-devel] [PATCH 15/22] qidl: Add documentation Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 16/22] qidl: parser, initial import from qc.git Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 17/22] qidl: codegen, initial commit Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 18/22] qidl: qidl.h Michael Roth
2012-07-24 20:47   ` Blue Swirl
2012-07-25  0:30     ` Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 19/22] qidl: unit tests Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 20/22] qemu-timer: add visit_type_QEMUTimer Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 21/22] rtc: add QIDL annotations Michael Roth
2012-07-24 17:20 ` [Qemu-devel] [PATCH 22/22] cirrus_vga: " Michael Roth
  -- strict thread matches above, loose matches on Subject: below --
2012-09-21 14:07 [Qemu-devel] [PATCH v2] Add infrastructure for QIDL-based device serialization Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py Michael Roth

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