From patchwork Tue Jan 19 16:10:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Blake X-Patchwork-Id: 8064021 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E2BDABEEE5 for ; Tue, 19 Jan 2016 16:28:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DE5EF2045E for ; Tue, 19 Jan 2016 16:28:47 +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 AB4B520456 for ; Tue, 19 Jan 2016 16:28:46 +0000 (UTC) Received: from localhost ([::1]:37942 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aLZ9B-0003Id-MV for patchwork-qemu-devel@patchwork.kernel.org; Tue, 19 Jan 2016 11:28:45 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42726) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aLYsJ-0005D5-8B for qemu-devel@nongnu.org; Tue, 19 Jan 2016 11:11:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aLYsC-0002G9-KG for qemu-devel@nongnu.org; Tue, 19 Jan 2016 11:11:19 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53874) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aLYsC-0002Fk-9p for qemu-devel@nongnu.org; Tue, 19 Jan 2016 11:11:12 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 08B12A37DC; Tue, 19 Jan 2016 16:11:12 +0000 (UTC) Received: from red.redhat.com (ovpn-113-211.phx2.redhat.com [10.3.113.211]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0JGAlYp008625; Tue, 19 Jan 2016 11:11:11 -0500 From: Eric Blake To: qemu-devel@nongnu.org Date: Tue, 19 Jan 2016 09:10:45 -0700 Message-Id: <1453219845-30939-38-git-send-email-eblake@redhat.com> In-Reply-To: <1453219845-30939-1-git-send-email-eblake@redhat.com> References: <1453219845-30939-1-git-send-email-eblake@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: marcandre.lureau@redhat.com, armbru@redhat.com, Michael Roth Subject: [Qemu-devel] [PATCH v9 37/37] qapi: Update docs to match recent generator changes 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 Several commits have been changing the generator, but not updating the docs to match: - The implicit tag member is named "type", not "kind". Screwed up in commit 39a1815. - Commit 9f08c8ec made list types lazy, and thereby dropped UserDefOneList if nothing explicitly uses the list type. - The parameter order has switched 'name' to occur earlier. - The generated code now checks for partial allocations. - etc. Rework the examples to show slightly more output (we don't want to show too much; that's what the testsuite is for), and regenerate the output to match all recent changes. Reported-by: Marc-André Lureau Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- v9: new patch --- docs/qapi-code-gen.txt | 130 +++++++++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 52 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 128f074..ae7b1a5 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -1,7 +1,7 @@ = How to use the QAPI code generator = Copyright IBM Corp. 2011 -Copyright (C) 2012-2015 Red Hat, Inc. +Copyright (C) 2012-2016 Red Hat, Inc. This work is licensed under the terms of the GNU GPL, version 2 or later. See the COPYING file in the top-level directory. @@ -655,7 +655,7 @@ Union types { "name": "BlockdevOptions", "meta-type": "object", "members": [ - { "name": "kind", "type": "BlockdevOptionsKind" } ], + { "name": "type", "type": "BlockdevOptionsKind" } ], "tag": "type", "variants": [ { "case": "file", "type": ":obj-FileOptions-wrapper" }, @@ -721,29 +721,34 @@ the names of built-in types. Clients should examine member == Code generation == -Schemas are fed into four scripts to generate all the code/files that, +Schemas are fed into five scripts to generate all the code/files that, paired with the core QAPI libraries, comprise everything required to take JSON commands read in by a Client JSON Protocol server, unmarshal the arguments into the underlying C types, call into the corresponding -C function, and map the response back to a Client JSON Protocol -response to be returned to the user. +C function, map the response back to a Client JSON Protocol response +to be returned to the user, and introspect the commands. -As an example, we'll use the following schema, which describes a single -complex user-defined type (which will produce a C struct, along with a list -node structure that can be used to chain together a list of such types in -case we want to accept/return a list of this type with a command), and a -command which takes that type as a parameter and returns the same type: +As an example, we'll use the following schema, which describes a +single complex user-defined type, along with command which takes a +list of that type as a parameter. The user is responsible for writing +the implementation of qmp_my_command(); everything else is produced by +the generator. $ cat example-schema.json { 'struct': 'UserDefOne', - 'data': { 'integer': 'int', 'string': 'str' } } + 'data': { 'integer': 'int', '*string': 'str' } } { 'command': 'my-command', - 'data': {'arg1': 'UserDefOne'}, + 'data': { 'arg1': ['UserDefOne'] }, 'returns': 'UserDefOne' } { 'event': 'MY_EVENT' } +For a more thorough look at generated code, the testsuite includes +tests/qapi-schema/qapi-schema-tests.json that covers more examples of +what the generator will accept, and compiles the resulting C code as +part of 'make check-unit'. + === scripts/qapi-types.py === Used to generate the C types defined by a schema. The following files are @@ -776,7 +781,7 @@ Example: qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOne(v, &obj, NULL, NULL); + visit_type_UserDefOne(v, NULL, &obj, NULL); qapi_dealloc_visitor_cleanup(qdv); } @@ -791,7 +796,7 @@ Example: qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOneList(v, &obj, NULL, NULL); + visit_type_UserDefOneList(v, NULL, &obj, NULL); qapi_dealloc_visitor_cleanup(qdv); } $ cat qapi-generated/example-qapi-types.h @@ -808,17 +813,15 @@ Example: struct UserDefOne { int64_t integer; + bool has_string; char *string; }; void qapi_free_UserDefOne(UserDefOne *obj); struct UserDefOneList { - union { - UserDefOne *value; - uint64_t padding; - }; UserDefOneList *next; + UserDefOne *value; }; void qapi_free_UserDefOneList(UserDefOneList *obj); @@ -854,54 +857,76 @@ Example: { Error *err = NULL; - visit_type_int(v, &(*obj)->integer, "integer", &err); + visit_type_int(v, "integer", &(*obj)->integer, &err); if (err) { goto out; } - visit_type_str(v, &(*obj)->string, "string", &err); - if (err) { - goto out; + if (visit_optional(v, "string", &(*obj)->has_string)) { + visit_type_str(v, "string", &(*obj)->string, &err); + if (err) { + goto out; + } } out: error_propagate(errp, err); } - void visit_type_UserDefOne(Visitor *v, UserDefOne **obj, const char *name, Error **errp) + void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp) { Error *err = NULL; + bool allocated; - visit_start_struct(v, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err); - if (!err) { - if (*obj) { - visit_type_UserDefOne_fields(v, obj, errp); - } - visit_end_struct(v, &err); + allocated = visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), + &err); + if (err) { + goto out; + } + if (!*obj) { + goto out_obj; + } + visit_type_UserDefOne_fields(v, obj, &err); + if (err) { + goto out_obj; } + visit_check_struct(v, &err); + out_obj: + visit_end_struct(v); + if (allocated && err) { + qapi_free_UserDefOne(*obj); + *obj = NULL; + } + out: error_propagate(errp, err); } - void visit_type_UserDefOneList(Visitor *v, UserDefOneList **obj, const char *name, Error **errp) + void visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp) { Error *err = NULL; - GenericList *i, **prev; + UserDefOneList *eld; + bool allocated; - visit_start_list(v, name, &err); + allocated = visit_start_list(v, name, (GenericList **)obj, sizeof(UserDefOneList), &err); if (err) { goto out; } - - for (prev = (GenericList **)obj; - !err && (i = visit_next_list(v, prev, &err)) != NULL; - prev = &i) { - UserDefOneList *native_i = (UserDefOneList *)i; - visit_type_UserDefOne(v, &native_i->value, NULL, &err); + elt = *obj; + while (elt) { + visit_type_UserDefOne(v, NULL, &elt->value, &err); + if (err) { + break; + } + elt = (UserDefOneList *)visit_next_list(v, (GenericList *)elt, sizeof(UserDefOneList), &err); + if (err) { + break; + } } - - error_propagate(errp, err); - err = NULL; - visit_end_list(v, &err); + visit_end_list(v); out: + if (allocated && err) { + qapi_free_UserDefOneList(*obj); + *obj = NULL; + } error_propagate(errp, err); } $ cat qapi-generated/example-qapi-visit.h @@ -912,8 +937,8 @@ Example: [Visitors for built-in types omitted...] - void visit_type_UserDefOne(Visitor *v, UserDefOne **obj, const char *name, Error **errp); - void visit_type_UserDefOneList(Visitor *v, UserDefOneList **obj, const char *name, Error **errp); + void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp); + void visit_type_UserDefOneList(Visitor *v, const char *name, UserDefOneList **obj, Error **errp); #endif @@ -949,7 +974,7 @@ Example: Visitor *v; v = qmp_output_get_visitor(qov); - visit_type_UserDefOne(v, &ret_in, "unused", &err); + visit_type_UserDefOne(v, "unused", &ret_in, &err); if (err) { goto out; } @@ -960,7 +985,7 @@ Example: qmp_output_visitor_cleanup(qov); qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOne(v, &ret_in, "unused", NULL); + visit_type_UserDefOne(v, "unused", &ret_in, NULL); qapi_dealloc_visitor_cleanup(qdv); } @@ -971,10 +996,10 @@ Example: QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args)); QapiDeallocVisitor *qdv; Visitor *v; - UserDefOne *arg1 = NULL; + UserDefOneList *arg1 = NULL; v = qmp_input_get_visitor(qiv); - visit_type_UserDefOne(v, &arg1, "arg1", &err); + visit_type_UserDefOne(v, "arg1", &arg1, &err); if (err) { goto out; } @@ -991,7 +1016,7 @@ Example: qmp_input_visitor_cleanup(qiv); qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOne(v, &arg1, "arg1", NULL); + visit_type_UserDefOne(v, "arg1", &arg1, NULL); qapi_dealloc_visitor_cleanup(qdv); } @@ -1011,7 +1036,7 @@ Example: #include "qapi/qmp/qdict.h" #include "qapi/error.h" - UserDefOne *qmp_my_command(UserDefOne *arg1, Error **errp); + UserDefOne *qmp_my_command(UserDefOneList *arg1, Error **errp); #endif @@ -1095,8 +1120,9 @@ Example: "{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, " "{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, " "{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, " - "{\"members\": [{\"name\": \"arg1\", \"type\": \"2\"}], \"meta-type\": \"object\", \"name\": \"1\"}, " - "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, " + "{\"members\": [{\"name\": \"arg1\", \"type\": \"[2]\"}], \"meta-type\": \"object\", \"name\": \"1\"}, " + "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"default\": null, \"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, " + "{\"element-type\": \"2\", \"meta-type\": \"array\", \"name\": \"[2]\"}, " "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, " "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]"; $ cat qapi-generated/example-qmp-introspect.h