qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH RFC v3 18/20] qapi: Plumb in 'box' to qapi generator


From: Eric Blake
Subject: [Qemu-devel] [PATCH RFC v3 18/20] qapi: Plumb in 'box' to qapi generator lower levels
Date: Tue, 18 Aug 2015 09:05:16 -0700

A future patch will add support for passing a qapi union
type as the 'data' of a command.  But to do that, the user
function for implementing the command, as called by the
generated marshal command, must take the corresponding C
struct as a single boxed pointer, rather than a breakdown
into one parameter per member.  This patch adds the
internal plubming of a 'box' flag associated with each
command and event.  For this patch, no behavior changes,
other than the testsuite outputting the value of the new
flag (always False for now).

Signed-off-by: Eric Blake <address@hidden>
---
 scripts/qapi-commands.py                | 93 ++++++++++++++++++---------------
 scripts/qapi-event.py                   | 65 ++++++++++++-----------
 scripts/qapi-introspect.py              |  4 +-
 scripts/qapi.py                         | 47 ++++++++++-------
 tests/qapi-schema/args-member-array.out |  2 +-
 tests/qapi-schema/event-case.out        |  1 +
 tests/qapi-schema/ident-with-escape.out |  2 +-
 tests/qapi-schema/indented-expr.out     |  4 +-
 tests/qapi-schema/qapi-schema-test.out  | 17 +++---
 tests/qapi-schema/returns-int.out       |  2 +-
 tests/qapi-schema/test-qapi.py          |  8 +--
 11 files changed, 139 insertions(+), 106 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 7ff7c31..e2b8f7a 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -15,13 +15,13 @@
 from qapi import *
 import re

-def gen_command_decl(name, arg_type, ret_type):
+def gen_command_decl(name, arg_type, box, ret_type):
     return mcgen('''
 %(c_type)s qmp_%(c_name)s(%(params)s);
 ''',
                  c_type=(ret_type and ret_type.c_type()) or 'void',
                  c_name=c_name(name),
-                 params=gen_params(arg_type, 'Error **errp'))
+                 params=gen_params(arg_type, box, 'Error **errp'))

 def gen_err_check(err):
     if not err:
@@ -33,15 +33,18 @@ if (%(err)s) {
 ''',
                  err=err)

-def gen_call(name, arg_type, ret_type):
+def gen_call(name, arg_type, box, ret_type):
     ret = ''

     argstr = ''
-    if arg_type:
-        for memb in arg_type.members:
-            if memb.optional:
-                argstr += 'has_%s, ' % c_name(memb.name)
-            argstr += '%s, ' % c_name(memb.name)
+    if box:
+        assert False # not implemented
+    else:
+        if arg_type:
+            for memb in arg_type.members:
+                if memb.optional:
+                    argstr += 'has_%s, ' % c_name(memb.name)
+                argstr += '%s, ' % c_name(memb.name)

     lhs = ''
     if ret_type:
@@ -63,7 +66,7 @@ qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
     pop_indent()
     return ret

-def gen_marshal_vars(arg_type, ret_type):
+def gen_marshal_vars(arg_type, box, ret_type):
     ret = mcgen('''
     Error *local_err = NULL;
 ''')
@@ -83,18 +86,21 @@ QapiDeallocVisitor *md;
 Visitor *v;
 ''')

-        for memb in arg_type.members:
-            if memb.optional:
-                ret += mcgen('''
+        if box:
+            assert False # not implemented
+        else:
+            for memb in arg_type.members:
+                if memb.optional:
+                    ret += mcgen('''
 bool has_%(c_name)s = false;
 ''',
-                             c_name=c_name(memb.name))
-            ret += mcgen('''
+                                 c_name=c_name(memb.name))
+                ret += mcgen('''
 %(c_type)s %(c_name)s = %(c_null)s;
 ''',
-                         c_name=c_name(memb.name),
-                         c_type=memb.type.c_type(),
-                         c_null=memb.type.c_null())
+                             c_name=c_name(memb.name),
+                             c_type=memb.type.c_type(),
+                             c_null=memb.type.c_null())
         ret += '\n'
     else:
         ret += mcgen('''
@@ -105,7 +111,7 @@ bool has_%(c_name)s = false;
     pop_indent()
     return ret

-def gen_marshal_input_visit(arg_type, dealloc=False):
+def gen_marshal_input_visit(arg_type, box, dealloc=False):
     ret = ''

     if not arg_type:
@@ -128,28 +134,31 @@ v = qapi_dealloc_get_visitor(md);
 v = qmp_input_get_visitor(mi);
 ''')

-    for memb in arg_type.members:
-        if memb.optional:
-            ret += mcgen('''
+    if box:
+        assert False # not implemented
+    else:
+        for memb in arg_type.members:
+            if memb.optional:
+                ret += mcgen('''
 visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
 ''',
-                         c_name=c_name(memb.name), name=memb.name,
-                         errp=errparg)
-            ret += gen_err_check(errarg)
-            ret += mcgen('''
+                             c_name=c_name(memb.name), name=memb.name,
+                             errp=errparg)
+                ret += gen_err_check(errarg)
+                ret += mcgen('''
 if (has_%(c_name)s) {
 ''',
-                         c_name=c_name(memb.name))
-            push_indent()
-        ret += mcgen('''
+                             c_name=c_name(memb.name))
+                push_indent()
+            ret += mcgen('''
 visit_type_%(c_type)s(v, &%(c_name)s, "%(name)s", %(errp)s);
 ''',
-                     c_name=c_name(memb.name), name=memb.name,
-                     c_type=memb.type.c_name(), errp=errparg)
-        ret += gen_err_check(errarg)
-        if memb.optional:
-            pop_indent()
-            ret += mcgen('''
+                         c_name=c_name(memb.name), name=memb.name,
+                         c_type=memb.type.c_name(), errp=errparg)
+            ret += gen_err_check(errarg)
+            if memb.optional:
+                pop_indent()
+                ret += mcgen('''
 }
 ''')

@@ -200,7 +209,7 @@ def gen_marshal_decl(name):
 ''',
                  proto=gen_marshal_proto(name))

-def gen_marshal(name, arg_type, ret_type):
+def gen_marshal(name, arg_type, box, ret_type):
     ret = mcgen('''

 %(proto)s
@@ -208,9 +217,9 @@ def gen_marshal(name, arg_type, ret_type):
 ''',
                 proto=gen_marshal_proto(name))

-    ret += gen_marshal_vars(arg_type, ret_type)
-    ret += gen_marshal_input_visit(arg_type)
-    ret += gen_call(name, arg_type, ret_type)
+    ret += gen_marshal_vars(arg_type, box, ret_type)
+    ret += gen_marshal_input_visit(arg_type, box)
+    ret += gen_call(name, arg_type, box, ret_type)

     if re.search('^ *goto out;', ret, re.MULTILINE):
         ret += mcgen('''
@@ -220,7 +229,7 @@ out:
     ret += mcgen('''
     error_propagate(errp, local_err);
 ''')
-    ret += gen_marshal_input_visit(arg_type, dealloc=True)
+    ret += gen_marshal_input_visit(arg_type, box, dealloc=True)
     ret += mcgen('''
 }
 ''')
@@ -271,16 +280,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self.regy = None
         self.visited_ret_types = None
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         if not gen:
             return
-        self.decl += gen_command_decl(name, arg_type, ret_type)
+        self.decl += gen_command_decl(name, arg_type, box, ret_type)
         if ret_type and ret_type not in self.visited_ret_types:
             self.visited_ret_types.add(ret_type)
             self.defn += gen_marshal_output(ret_type)
         if middle_mode:
             self.decl += gen_marshal_decl(name)
-        self.defn += gen_marshal(name, arg_type, ret_type)
+        self.defn += gen_marshal(name, arg_type, box, ret_type)
         if not middle_mode:
             self.regy += gen_register_command(name, success_response)

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index d100099..278cd7f 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -13,19 +13,19 @@

 from qapi import *

-def gen_event_send_proto(name, arg_type):
+def gen_event_send_proto(name, arg_type, box):
     return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
         'c_name': c_name(name.lower()),
-        'param': gen_params(arg_type, 'Error **errp')}
+        'param': gen_params(arg_type, box, 'Error **errp')}

-def gen_event_send_decl(name, arg_type):
+def gen_event_send_decl(name, arg_type, box):
     return mcgen('''

 %(proto)s;
 ''',
-                 proto=gen_event_send_proto(name, arg_type))
+                 proto=gen_event_send_proto(name, arg_type, box))

-def gen_event_send(name, arg_type):
+def gen_event_send(name, arg_type, box):
     ret = mcgen('''

 %(proto)s
@@ -34,7 +34,7 @@ def gen_event_send(name, arg_type):
     Error *local_err = NULL;
     QMPEventFuncEmit emit;
 ''',
-                proto=gen_event_send_proto(name, arg_type))
+                proto=gen_event_send_proto(name, arg_type, box))

     if arg_type and arg_type.members:
         ret += mcgen('''
@@ -63,47 +63,52 @@ def gen_event_send(name, arg_type):
     v = qmp_output_get_visitor(qov);
     g_assert(v);

+''')
+
+        if box:
+            assert False # not implemented
+        else:
+            ret += mcgen('''
     /* Fake visit, as if all members are under a structure */
     visit_start_struct(v, NULL, "", "%(name)s", 0, &local_err);
     if (local_err) {
         goto clean;
     }
-
 ''',
-                     name=name)
+                         name=name)

-        for memb in arg_type.members:
-            if memb.optional:
-                ret += mcgen('''
+            for memb in arg_type.members:
+                if memb.optional:
+                    ret += mcgen('''
     if (has_%(c_name)s) {
 ''',
-                             c_name=c_name(memb.name))
-                push_indent()
+                                 c_name=c_name(memb.name))
+                    push_indent()

-            # Ugly: need to cast away the const
-            if memb.type.name == "str":
-                cast = '(char **)'
-            else:
-                cast = ''
+                # Ugly: need to cast away the const
+                if memb.type.name == "str":
+                    cast = '(char **)'
+                else:
+                    cast = ''

-            ret += mcgen('''
+                ret += mcgen('''
     visit_type_%(c_type)s(v, %(cast)s&%(c_name)s, "%(name)s", &local_err);
     if (local_err) {
         goto clean;
     }
 ''',
-                         cast=cast,
-                         c_name=c_name(memb.name),
-                         c_type=memb.type.c_name(),
-                         name=memb.name)
+                             cast=cast,
+                             c_name=c_name(memb.name),
+                             c_type=memb.type.c_name(),
+                             name=memb.name)

-            if memb.optional:
-                pop_indent()
-                ret += mcgen('''
+                if memb.optional:
+                    pop_indent()
+                    ret += mcgen('''
     }
 ''')

-        ret += mcgen('''
+            ret += mcgen('''

     visit_end_struct(v, &local_err);
     if (local_err) {
@@ -147,9 +152,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
         self.decl += gen_enum(event_enum_name, self.event_names)
         self.defn += gen_enum_lookup(event_enum_name, self.event_names)
         self.event_names = None
-    def visit_event(self, name, info, arg_type):
-        self.decl += gen_event_send_decl(name, arg_type)
-        self.defn += gen_event_send(name, arg_type)
+    def visit_event(self, name, info, arg_type, box):
+        self.decl += gen_event_send_decl(name, arg_type, box)
+        self.defn += gen_event_send(name, arg_type, box)
         self.event_names.append(name)

 (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index d723ef1..935ffc3 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -145,14 +145,14 @@ const char %(c_name)s[] = %(c_string)s;
                                       for m in variants.variants] })

     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         arg_type = arg_type or self.schema.the_empty_object_type
         ret_type = ret_type or self.schema.the_empty_object_type
         self._gen_json(name, 'command',
                        { 'arg-type': self._use_type(arg_type),
                          'ret-type': self._use_type(ret_type) })

-    def visit_event(self, name, info, arg_type):
+    def visit_event(self, name, info, arg_type, box):
         arg_type = arg_type or self.schema.the_empty_object_type
         self._gen_json(name, 'event', { 'arg-type': self._use_type(arg_type) })

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 61e4c00..313eaef 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -792,9 +792,9 @@ class QAPISchemaVisitor(object):
     def visit_alternate_type(self, name, info, variants):
         pass
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         pass
-    def visit_event(self, name, info, arg_type):
+    def visit_event(self, name, info, arg_type, box):
         pass

 class QAPISchemaType(QAPISchemaEntity):
@@ -986,7 +986,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
         visitor.visit_alternate_type(self.name, self.info, self.variants)

 class QAPISchemaCommand(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type, ret_type, gen, success_response):
+    def __init__(self, name, info, arg_type, ret_type, gen, success_response,
+                 box):
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -996,32 +997,36 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.ret_type = None
         self.gen = gen
         self.success_response = success_response
+        self.box = box
     def check(self, schema):
         if self.arg_type_name:
             self.arg_type = schema.lookup_type(self.arg_type_name)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
-            assert not self.arg_type.variants # not implemented
+            if not self.box:
+                assert not self.arg_type.variants
         if self.ret_type_name:
             self.ret_type = schema.lookup_type(self.ret_type_name)
             assert isinstance(self.ret_type, QAPISchemaType)
     def visit(self, visitor):
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
-                              self.gen, self.success_response)
+                              self.gen, self.success_response, self.box)

 class QAPISchemaEvent(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type):
+    def __init__(self, name, info, arg_type, box):
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         self.arg_type_name = arg_type
         self.arg_type = None
+        self.box = box
     def check(self, schema):
         if self.arg_type_name:
             self.arg_type = schema.lookup_type(self.arg_type_name)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
-            assert not self.arg_type.variants # not implemented
+            if not self.box:
+                assert not self.arg_type.variants
     def visit(self, visitor):
-        visitor.visit_event(self.name, self.info, self.arg_type)
+        visitor.visit_event(self.name, self.info, self.arg_type, self.box)

 class QAPISchema(object):
     def __init__(self, fname):
@@ -1172,6 +1177,7 @@ class QAPISchema(object):
         rets = expr.get('returns')
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
+        box = expr.get('box', False)
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(name, 'arg',
                                                    self._make_members(data))
@@ -1182,15 +1188,16 @@ class QAPISchema(object):
             rets = self._make_implicit_object_type(name, 'ret',
                                                    self._make_members(rets))
         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
-                                           success_response))
+                                           success_response, box))

     def _def_event(self, expr, info):
         name = expr['event']
         data = expr.get('data')
+        box = expr.get('box', False)
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(name, 'arg',
                                                    self._make_members(data))
-        self._def_entity(QAPISchemaEvent(name, info, data))
+        self._def_entity(QAPISchemaEvent(name, info, data, box))

     def _def_exprs(self):
         for expr_elem in self.exprs:
@@ -1413,18 +1420,22 @@ extern const char *const %(c_name)s_lookup[];
                  c_name=c_name(name))
     return ret

-def gen_params(arg_type, extra):
+def gen_params(arg_type, box, extra):
     if not arg_type:
         return extra
-    assert not arg_type.variants
     ret = ''
     sep = ''
-    for memb in arg_type.members:
-        ret += sep
-        sep = ', '
-        if memb.optional:
-            ret += 'bool has_%s, ' % c_name(memb.name)
-        ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
+    if box:
+        assert False # not implemented
+    else:
+        assert not arg_type.variants
+        for memb in arg_type.members:
+            ret += sep
+            sep = ', '
+            if memb.optional:
+                ret += 'bool has_%s, ' % c_name(memb.name)
+            ret += '%s %s' % (memb.type.c_type(is_param=True),
+                              c_name(memb.name))
     if extra:
         ret += sep + extra
     return ret
diff --git a/tests/qapi-schema/args-member-array.out 
b/tests/qapi-schema/args-member-array.out
index b3b92df..f5dc409 100644
--- a/tests/qapi-schema/args-member-array.out
+++ b/tests/qapi-schema/args-member-array.out
@@ -6,4 +6,4 @@ enum abc ['a', 'b', 'c']
 object def
     member array: abcList optional=False
 command okay :obj-okay-arg -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index cdfd264..97a682a 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,2 +1,3 @@
 object :empty
 event oops None
+   box=False
diff --git a/tests/qapi-schema/ident-with-escape.out 
b/tests/qapi-schema/ident-with-escape.out
index f4542b1..2381c33 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -2,4 +2,4 @@ object :empty
 object :obj-fooA-arg
     member bar1: str optional=False
 command fooA :obj-fooA-arg -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/indented-expr.out 
b/tests/qapi-schema/indented-expr.out
index 226d300..f5d2695 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,5 +1,5 @@
 object :empty
 command eins None -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command zwei None -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/qapi-schema-test.out 
b/tests/qapi-schema/qapi-schema-test.out
index ce01fa7..1a66627 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -70,9 +70,13 @@ alternate AltTwo
     case s: str
     case n: number
 event EVENT_A None
+   box=False
 event EVENT_B None
+   box=False
 event EVENT_C :obj-EVENT_C-arg
+   box=False
 event EVENT_D :obj-EVENT_D-arg
+   box=False
 enum EnumOne ['value1', 'value2', 'value3']
 object EventStructOne
     member struct1: UserDefOne optional=False
@@ -148,6 +152,7 @@ object UserDefUnionBase
 object UserDefZero
     member integer: int optional=False
 event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
+   box=False
 alternate __org.qemu_x-Alt
     case __org.qemu_x-branch: str
     case b: __org.qemu_x-Base
@@ -167,14 +172,14 @@ object __org.qemu_x-Union2
     tag __org.qemu_x-member1
     case __org.qemu_x-value: __org.qemu_x-Struct2
 command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> 
__org.qemu_x-Union1
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command guest-sync :obj-guest-sync-arg -> any
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd None -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd1 :obj-user_def_cmd1-arg -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd3 :obj-user_def_cmd3-arg -> int
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/returns-int.out 
b/tests/qapi-schema/returns-int.out
index a2da259..911212d 100644
--- a/tests/qapi-schema/returns-int.out
+++ b/tests/qapi-schema/returns-int.out
@@ -1,3 +1,3 @@
 object :empty
 command guest-get-time None -> int
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 471f8e1..273cdc3 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -30,12 +30,14 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         print 'alternate %s' % name
         self._print_variants(variants)
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         print 'command %s %s -> %s' % \
             (name, arg_type and arg_type.name, ret_type and ret_type.name)
-        print '   gen=%s success_response=%s' % (gen, success_response)
-    def visit_event(self, name, info, arg_type):
+        print '   gen=%s success_response=%s box=%s' % (gen, success_response,
+                                                        box)
+    def visit_event(self, name, info, arg_type, box):
         print 'event %s %s' % (name, arg_type and arg_type.name)
+        print '   box=%s' % box

     @staticmethod
     def _print_variants(variants):
-- 
2.4.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]