From patchwork Fri Oct 12 21:10:47 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Roth X-Patchwork-Id: 191230 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A21232C0089 for ; Sat, 13 Oct 2012 08:59:51 +1100 (EST) Received: from localhost ([::1]:37146 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TMmWm-0006ym-Ky for incoming@patchwork.ozlabs.org; Fri, 12 Oct 2012 17:12:16 -0400 Received: from eggs.gnu.org ([208.118.235.92]:42222) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TMmW2-0005Ga-Nk for qemu-devel@nongnu.org; Fri, 12 Oct 2012 17:11:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TMmW0-0005tZ-Tb for qemu-devel@nongnu.org; Fri, 12 Oct 2012 17:11:30 -0400 Received: from mail-ie0-f173.google.com ([209.85.223.173]:36593) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TMmW0-0005iK-3y for qemu-devel@nongnu.org; Fri, 12 Oct 2012 17:11:28 -0400 Received: by mail-ie0-f173.google.com with SMTP id 17so5335456iea.4 for ; Fri, 12 Oct 2012 14:11:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=W9nWl4ELmNq6k7kHjFh1D4p/p3rjL/f/3W8D9K/wEZk=; b=m91lzG1ap13v5Yr+ZtHOWtiSDaSY3gwwhkEVdYRuIJyYJZ5IxuQfficFFpwocBOOnR GIOrRvXXQcH5k9NtkvCQn5w9QUkLqwxmdF8GpStDaRYugjUIQmG+BlRq4l4875VRZExx P6Af/lFUk8vfMnJ9EbcPspuGIB2w4bCHaLHnGbIow8xYRNit3aO0fBNJUlTifAuK0xv5 5+YwBhMKbWJjXmEu/VZmXylVG77r8WayJKGjErQuBSSdhKtP92lC/R+x0ZE3pdGqe+rc iA0hcWeZnih86TfRus6msedrElpwPm/oqJZD3gPMwL1IwOYynSZytro6OSboO2wUpvhJ N4ww== Received: by 10.50.152.132 with SMTP id uy4mr3411927igb.3.1350076287852; Fri, 12 Oct 2012 14:11:27 -0700 (PDT) Received: from loki.morrigu.org (cpe-72-179-62-111.austin.res.rr.com. [72.179.62.111]) by mx.google.com with ESMTPS id uj11sm2454777igb.15.2012.10.12.14.11.26 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 12 Oct 2012 14:11:27 -0700 (PDT) From: Michael Roth To: qemu-devel@nongnu.org Date: Fri, 12 Oct 2012 16:10:47 -0500 Message-Id: <1350076268-18461-6-git-send-email-mdroth@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1350076268-18461-1-git-send-email-mdroth@linux.vnet.ibm.com> References: <1350076268-18461-1-git-send-email-mdroth@linux.vnet.ibm.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.223.173 Cc: kwolf@redhat.com, peter.maydell@linaro.org, aliguori@us.ibm.com, blauwirbel@gmail.com, pbonzini@redhat.com Subject: [Qemu-devel] [PATCH v4 05/26] qapi: qapi_visit.py, support arrays and complex qapi definitions 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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. Reviewed-by: Anthony Liguori Signed-off-by: Michael Roth --- scripts/qapi.py | 8 +++- scripts/qapi_commands.py | 8 ++-- scripts/qapi_types.py | 2 +- scripts/qapi_visit.py | 102 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 14 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index afc5f32..555d823 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -110,12 +110,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 = True + else: + structured = True + yield (argname, argentry, optional, structured, annotated) def de_camel_case(name): new_name = '' diff --git a/scripts/qapi_commands.py b/scripts/qapi_commands.py index 3c4678d..a2e0c23 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 1b84834..87d0218 100644 --- a/scripts/qapi_types.py +++ b/scripts/qapi_types.py @@ -45,7 +45,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 f98abf2..d80d3d8 100644 --- a/scripts/qapi_visit.py +++ b/scripts/qapi_visit.py @@ -16,6 +16,90 @@ import sys import os import getopt import errno +import types + +def generate_visit_carray_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 + + # Visitors for "objects" (qidl-generated visitors for structs or + # qapi-defined types) expect a ** argument so that, in some + # cases, memory can be allocated for the object and a pointer to that + # memory can be assigned to the location/pointer passed to the visitor + # call. + # + # For other cases, "primitive" types, we don't do allocations and thus + # expect a *. + # + # So we use special handling for the former case, below, to get the + # arguments right. We identify these cases by checking if the type + # uses camel-case, which is reserved for typedef'd structs/objects as + # per QEMU coding standards and QAPI convention. + if camel_case(de_camel_case(info['type'][0])) == info['type'][0]: + ret = mcgen(''' + +if (!error_is_set(errp)) { + Error *%(local_err)s = NULL; + visit_start_carray(m, (void **)obj, "%(name)s", %(array_capacity)s, sizeof(%(type)s), &%(local_err)s); + if (!%(local_err)s) { + int %(name)s_i; + for (%(name)s_i = 0; %(name)s_i < %(array_size)s; %(name)s_i++) { + %(type)s %(name)s_ptr = &(*obj)->%(name)s[%(name)s_i]; + visit_next_carray(m, &%(local_err)s); + visit_type_%(type_short)s(m, &%(name)s_ptr, NULL, &%(local_err)s); + } + + error_propagate(errp, %(local_err)s); + %(local_err)s = NULL; + + /* Always call end_carry if start_carray succeeded. */ + visit_end_carray(m, &%(local_err)s); + } + error_propagate(errp, %(local_err)s); +} +''', + name=name, type=c_type(info['type'][0]), + type_short=info['type'][0], + array_size=str(array_size), + array_capacity=str(array_capacity), + local_err=name + "_err") + else: + ret = mcgen(''' +if (!error_is_set(errp)) { + Error *%(local_err)s = NULL; + visit_start_carray(m, (void **)obj, "%(name)s", %(array_capacity)s, sizeof(%(type)s), &%(local_err)s); + if (!%(local_err)s) { + int %(name)s_i; + for (%(name)s_i = 0; %(name)s_i < %(array_size)s; %(name)s_i++) { + %(type)s *%(name)s_ptr = (%(type)s *)&(*obj)->%(name)s[%(name)s_i]; + visit_next_carray(m, &%(local_err)s); + visit_type_%(type_short)s(m, %(name)s_ptr, NULL, &%(local_err)s); + } + + error_propagate(errp, %(local_err)s); + %(local_err)s = NULL; + + /* Always call end_carry if start_carray succeeded. */ + visit_end_carray(m, &%(local_err)s); + } + error_propagate(errp, %(local_err)s); +} +''', + name=name, type=c_type(info['type'][0]), + type_short=info['type'][0], + array_size=str(array_size), + array_capacity=str(array_capacity), + local_err=name + "_err") + return ret def generate_visit_struct_body(field_prefix, name, members): ret = mcgen(''' @@ -45,10 +129,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 +142,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_carray_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()