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 <ebl...@redhat.com> --- 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