From patchwork Sun Jul 3 02:58:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 643676 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rhw9g69KVz9s5M for ; Sun, 3 Jul 2016 13:09:43 +1000 (AEST) Received: from localhost ([::1]:40969 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bJXmv-0007sv-Lu for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2016 23:09:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54994) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bJXcf-0003fU-Ll for qemu-devel@nongnu.org; Sat, 02 Jul 2016 22:59:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bJXcc-0002ef-KY for qemu-devel@nongnu.org; Sat, 02 Jul 2016 22:59:04 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58279) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bJXcc-0002eS-Bh for qemu-devel@nongnu.org; Sat, 02 Jul 2016 22:59:02 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D187FC0467E4; Sun, 3 Jul 2016 02:59:01 +0000 (UTC) Received: from red.redhat.com (ovpn-116-56.phx2.redhat.com [10.3.116.56]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u632wpel006603; Sat, 2 Jul 2016 22:59:01 -0400 From: Eric Blake To: qemu-devel@nongnu.org Date: Sat, 2 Jul 2016 20:58:40 -0600 Message-Id: <1467514729-29366-8-git-send-email-eblake@redhat.com> In-Reply-To: <1467514729-29366-1-git-send-email-eblake@redhat.com> References: <1467514729-29366-1-git-send-email-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Sun, 03 Jul 2016 02:59:01 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v8 07/16] qapi: Plumb in 'box' to qapi generator lower levels X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: armbru@redhat.com, Michael Roth Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" The next 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. Even without a union, being able to use a C struct rather than a list of parameters can make it much easier to handle coding with QAPI. This patch adds the internal plumbing of a 'box' flag associated with each command and event. In several cases, this means adding indentation, with one new dead branch and the remaining branch being the original code more deeply nested; this was done so that the new implementation in the next patch is easier to review without also being mixed with indentation changes. For this patch, no behavior or generated output changes, other than the testsuite outputting the value of the new flag (always False for now). Signed-off-by: Eric Blake --- v8: improve commit message, defer some implementation, rebase without gen_err_check() v7: rebase to master v6: rebase to earlier changes --- scripts/qapi.py | 43 +++++++++++++++++++++------------ scripts/qapi-commands.py | 20 ++++++++------- scripts/qapi-event.py | 18 +++++++------- scripts/qapi-introspect.py | 4 +-- 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 | 19 +++++++++------ tests/qapi-schema/test-qapi.py | 8 +++--- 9 files changed, 70 insertions(+), 49 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 86bd780..f5e7697 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -826,10 +826,10 @@ class QAPISchemaVisitor(object): 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 @@ -1164,7 +1164,8 @@ class QAPISchemaAlternateType(QAPISchemaType): 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) @@ -1174,12 +1175,14 @@ 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 + assert not self.box # not implemented if self._ret_type_name: self.ret_type = schema.lookup_type(self._ret_type_name) assert isinstance(self.ret_type, QAPISchemaType) @@ -1187,24 +1190,26 @@ class QAPISchemaCommand(QAPISchemaEntity): 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 + assert not self.box # not implemented 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): @@ -1380,6 +1385,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, info, 'arg', self._make_members(data, info)) @@ -1387,15 +1393,16 @@ class QAPISchema(object): assert len(rets) == 1 rets = self._make_array_type(rets[0], info) 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, info, 'arg', self._make_members(data, info)) - 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: @@ -1638,18 +1645,22 @@ extern const char *const %(c_name)s_lookup[]; 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_param_type(), 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_param_type(), + c_name(memb.name)) if extra: ret += sep + extra return ret diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 333a46f..598c4c7 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -16,20 +16,22 @@ 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_call(name, arg_type, ret_type): +def gen_call(name, arg_type, box, ret_type): ret = '' argstr = '' - if arg_type: + if box: + assert False # not implemented + elif arg_type: assert not arg_type.variants for memb in arg_type.members: if memb.optional: @@ -94,7 +96,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 @@ -136,7 +138,7 @@ def gen_marshal(name, arg_type, ret_type): (void)args; ''') - ret += gen_call(name, arg_type, ret_type) + ret += gen_call(name, arg_type, box, ret_type) # 'goto out' produced above for arg_type, and by gen_call() for ret_type if (arg_type and not arg_type.is_empty()) or ret_type: @@ -212,16 +214,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor): 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 ef4a320..024be4d 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -14,18 +14,18 @@ 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)) # Declare and initialize an object 'qapi' using parameters from gen_params() @@ -57,7 +57,7 @@ def gen_param_var(typ): return ret -def gen_event_send(name, arg_type): +def gen_event_send(name, arg_type, box): # FIXME: Our declaration of local variables (and of 'errp' in the # parameter list) can collide with exploded members of the event's # data type passed in as parameters. If this collision ever hits in @@ -72,7 +72,7 @@ def gen_event_send(name, arg_type): Error *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 not arg_type.is_empty(): ret += mcgen(''' @@ -160,9 +160,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor): 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) diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py index e0f926b..60e9877 100644 --- a/scripts/qapi-introspect.py +++ b/scripts/qapi-introspect.py @@ -154,14 +154,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/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out index b6b4134..5ca8fd2 100644 --- a/tests/qapi-schema/event-case.out +++ b/tests/qapi-schema/event-case.out @@ -1,4 +1,5 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] prefix QTYPE event oops None + box=False object q_empty diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out index 382ce2f..27d45f3 100644 --- a/tests/qapi-schema/ident-with-escape.out +++ b/tests/qapi-schema/ident-with-escape.out @@ -1,7 +1,7 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] prefix QTYPE command fooA q_obj_fooA-arg -> None - gen=True success_response=True + gen=True success_response=True box=False object q_empty object q_obj_fooA-arg member bar1: str optional=False diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out index ae3293a..a7cd10f 100644 --- a/tests/qapi-schema/indented-expr.out +++ b/tests/qapi-schema/indented-expr.out @@ -1,7 +1,7 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] prefix QTYPE command eins None -> None - gen=True success_response=True + gen=True success_response=True box=False object q_empty 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 f34ecc7..754a926 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -23,9 +23,13 @@ alternate AltStrNum case s: str case n: number event EVENT_A None + box=False event EVENT_B None + box=False event EVENT_C q_obj_EVENT_C-arg + box=False event EVENT_D q_obj_EVENT_D-arg + box=False object Empty1 object Empty2 base Empty1 @@ -124,6 +128,7 @@ object UserDefZero object WrapAlternate member alt: UserDefAlternate optional=False event __ORG.QEMU_X-EVENT __org.qemu_x-Struct + box=False alternate __org.qemu_x-Alt tag type case __org.qemu_x-branch: str @@ -147,11 +152,11 @@ object __org.qemu_x-Union2 tag __org.qemu_x-member1 case __org.qemu_x-value: __org.qemu_x-Struct2 command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1 - gen=True success_response=True + gen=True success_response=True box=False command guest-get-time q_obj_guest-get-time-arg -> int - gen=True success_response=True + gen=True success_response=True box=False command guest-sync q_obj_guest-sync-arg -> any - gen=True success_response=True + gen=True success_response=True box=False object q_empty object q_obj_EVENT_C-arg member a: int optional=True @@ -212,10 +217,10 @@ object q_obj_user_def_cmd2-arg member ud1a: UserDefOne optional=False member ud1b: UserDefOne optional=True command user_def_cmd None -> None - gen=True success_response=True + gen=True success_response=True box=False command user_def_cmd0 Empty2 -> Empty2 - gen=True success_response=True + gen=True success_response=True box=False command user_def_cmd1 q_obj_user_def_cmd1-arg -> None - gen=True success_response=True + gen=True success_response=True box=False command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo - 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 bedd145..d82af59 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -36,13 +36,15 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): 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) + print ' gen=%s success_response=%s box=%s' % (gen, success_response, + box) - def visit_event(self, name, info, arg_type): + 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):