From patchwork Wed Mar 16 14:45:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Armbruster X-Patchwork-Id: 8601251 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 419039F44D for ; Wed, 16 Mar 2016 14:45:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 539F0202F2 for ; Wed, 16 Mar 2016 14:45:27 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 36E85202F0 for ; Wed, 16 Mar 2016 14:45:25 +0000 (UTC) Received: from localhost ([::1]:56785 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1agChQ-0007ME-K0 for patchwork-qemu-devel@patchwork.kernel.org; Wed, 16 Mar 2016 10:45:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48914) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1agChH-0007Ku-TQ for qemu-devel@nongnu.org; Wed, 16 Mar 2016 10:45:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1agChE-0005GI-7d for qemu-devel@nongnu.org; Wed, 16 Mar 2016 10:45:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34498) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1agChD-0005GB-VR for qemu-devel@nongnu.org; Wed, 16 Mar 2016 10:45:12 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 5B8BF64D0E; Wed, 16 Mar 2016 14:45:11 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-49.ams2.redhat.com [10.36.116.49]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u2GEj9m4029755 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Wed, 16 Mar 2016 10:45:10 -0400 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id A560F303F90D; Wed, 16 Mar 2016 15:45:08 +0100 (CET) From: Markus Armbruster To: Eric Blake References: <1457571335-10938-1-git-send-email-eblake@redhat.com> <1457571335-10938-8-git-send-email-eblake@redhat.com> Date: Wed, 16 Mar 2016 15:45:08 +0100 In-Reply-To: <1457571335-10938-8-git-send-email-eblake@redhat.com> (Eric Blake's message of "Wed, 9 Mar 2016 17:55:28 -0700") Message-ID: <87wpp2qy6j.fsf@blackfin.pond.sub.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Wed, 16 Mar 2016 14:45:11 +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 Cc: qemu-devel@nongnu.org, Michael Roth Subject: Re: [Qemu-devel] [PATCH v5 07/14] qapi: Utilize implicit struct visits X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Here's how I'd rebase this on the simplified PATCH 06 I just posted as a reply to yours: From e35449172828351f0acd85f236add45d3eb575a7 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 9 Mar 2016 17:55:28 -0700 Subject: [PATCH 07/14] qapi: Utilize implicit struct visits Rather than generate inline per-member visits, take advantage of the 'visit_type_FOO_members()' function for both event and command marshalling. This is possible now that implicit structs can be visited like any other. Generated code shrinks accordingly; events initialize a struct based on parameters, through a new gen_param_var() helper, like: |@@ -338,6 +250,9 @@ void qapi_event_send_block_job_error(con | QMPEventFuncEmit emit = qmp_event_get_func_emit(); | QmpOutputVisitor *qov; | Visitor *v; |+ q_obj_BLOCK_JOB_ERROR_arg param = { |+ (char *)device, operation, action |+ }; | | if (!emit) { | return; @@ -351,19 +266,7 @@ void qapi_event_send_block_job_error(con | if (err) { | goto out; | } |- visit_type_str(v, "device", (char **)&device, &err); |- if (err) { |- goto out_obj; |- } |- visit_type_IoOperationType(v, "operation", &operation, &err); |- if (err) { |- goto out_obj; |- } |- visit_type_BlockErrorAction(v, "action", &action, &err); |- if (err) { |- goto out_obj; |- } |-out_obj: |+ visit_type_q_obj_BLOCK_JOB_ERROR_arg_members(v, ¶m, &err); | visit_end_struct(v, err ? NULL : &err); Notice that the initialization of 'param' has to cast away const (just as the old gen_visit_members() had to do): we can't change the signature of the user function (which uses 'const char *'), but have to assign it to a non-const QAPI object (which requires 'char *'). Likewise, command marshalling generates call arguments from a stack-allocated struct, rather than a list of local variables: |@@ -57,26 +57,15 @@ void qmp_marshal_add_fd(QDict *args, QOb | QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args)); | QapiDeallocVisitor *qdv; | Visitor *v; |- bool has_fdset_id = false; |- int64_t fdset_id = 0; |- bool has_opaque = false; |- char *opaque = NULL; |- |- v = qmp_input_get_visitor(qiv); |- if (visit_optional(v, "fdset-id", &has_fdset_id)) { |- visit_type_int(v, "fdset-id", &fdset_id, &err); |- if (err) { |- goto out; |- } |- } |- if (visit_optional(v, "opaque", &has_opaque)) { |- visit_type_str(v, "opaque", &opaque, &err); |- if (err) { |- goto out; |- } |+ q_obj_add_fd_arg qapi = {0}; |+ |+ v = qmp_input_get_visitor(qiv); |+ visit_type_q_obj_add_fd_arg_members(v, &qapi, &err); |+ if (err) { |+ goto out; | } | |- retval = qmp_add_fd(has_fdset_id, fdset_id, has_opaque, opaque, &err); |+ retval = qmp_add_fd(qapi.has_fdset_id, qapi.fdset_id, qapi.has_opaque, qapi.opaque, &err); | if (err) { | goto out; | } |@@ -88,12 +77,7 @@ out: | qmp_input_visitor_cleanup(qiv); | qdv = qapi_dealloc_visitor_new(); | v = qapi_dealloc_get_visitor(qdv); |- if (visit_optional(v, "fdset-id", &has_fdset_id)) { |- visit_type_int(v, "fdset-id", &fdset_id, NULL); |- } |- if (visit_optional(v, "opaque", &has_opaque)) { |- visit_type_str(v, "opaque", &opaque, NULL); |- } |+ visit_type_q_obj_add_fd_arg_members(v, &qapi, NULL); | qapi_dealloc_visitor_cleanup(qdv); | } For the marshaller, it has the nice side effect of eliminating a chance of collision between argument QMP names and local variables. A similar collision still exists in the qapi_event_send_FOO(). Document it with a FIXME comment. This patch also paves the way for some followup simplifications in the generator, in subsequent patches. Signed-off-by: Eric Blake Message-Id: <1457571335-10938-8-git-send-email-eblake@redhat.com> --- scripts/qapi-commands.py | 28 ++++++++++++---------------- scripts/qapi-event.py | 48 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 3784f33..5ffc381 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -33,8 +33,8 @@ def gen_call(name, arg_type, ret_type): assert not arg_type.variants for memb in arg_type.members: if memb.optional: - argstr += 'has_%s, ' % c_name(memb.name) - argstr += '%s, ' % c_name(memb.name) + argstr += 'qapi.has_%s, ' % c_name(memb.name) + argstr += 'qapi.%s, ' % c_name(memb.name) lhs = '' if ret_type: @@ -71,21 +71,10 @@ def gen_marshal_vars(arg_type, ret_type): QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args)); QapiDeallocVisitor *qdv; Visitor *v; -''') + %(c_name)s qapi = {0}; - 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_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()) - ret += '\n' + c_name=arg_type.c_name()) else: ret += mcgen(''' @@ -107,17 +96,24 @@ def gen_marshal_input_visit(arg_type, dealloc=False): qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); ''') + errp = 'NULL' else: ret += mcgen(''' v = qmp_input_get_visitor(qiv); ''') + errp = '&err' - ret += gen_visit_members(arg_type.members, skiperr=dealloc) + ret += mcgen(''' + visit_type_%(c_name)s_members(v, &qapi, %(errp)s); +''', + c_name=arg_type.c_name(), errp=errp) if dealloc: ret += mcgen(''' qapi_dealloc_visitor_cleanup(qdv); ''') + else: + ret += gen_err_check() return ret diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 27af206..9b5c5b5 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -28,7 +28,37 @@ def gen_event_send_decl(name, arg_type): proto=gen_event_send_proto(name, arg_type)) +# Declare and initialize an object 'qapi' using parameters from gen_params() +def gen_param_var(typ): + assert not typ.variants + ret = mcgen(''' + %(c_name)s param = { +''', + c_name=typ.c_name()) + sep = ' ' + for memb in typ.members: + ret += sep + sep = ', ' + if memb.optional: + ret += 'has_' + c_name(memb.name) + sep + if memb.type.name == 'str': + # Cast away const added in gen_params() + ret += '(char *)' + ret += c_name(memb.name) + ret += mcgen(''' + + }; +''') + return ret + + def gen_event_send(name, arg_type): + # 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 + # practice, we can rename our local variables with a leading _ prefix, + # or split the code into a wrapper function that creates a boxed + # 'param' object then calls another to do the real work. ret = mcgen(''' %(proto)s @@ -43,10 +73,11 @@ def gen_event_send(name, arg_type): ret += mcgen(''' QmpOutputVisitor *qov; Visitor *v; - ''') + ret += gen_param_var(arg_type) ret += mcgen(''' + emit = qmp_event_get_func_emit(); if (!emit) { return; @@ -58,26 +89,23 @@ def gen_event_send(name, arg_type): name=name) if arg_type and arg_type.members: - assert not arg_type.variants ret += mcgen(''' qov = qmp_output_visitor_new(); v = qmp_output_get_visitor(qov); visit_start_struct(v, "%(name)s", NULL, 0, &err); -''', - name=name) - ret += gen_err_check() - ret += gen_visit_members(arg_type.members, need_cast=True, - label='out_obj') - ret += mcgen(''' -out_obj: + if (err) { + goto out; + } + visit_type_%(c_name)s_members(v, ¶m, &err); visit_end_struct(v, err ? NULL : &err); if (err) { goto out; } qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov)); -''') +''', + name=name, c_name=arg_type.c_name()) ret += mcgen(''' emit(%(c_enum)s, qmp, &err);