From e55250c6cb4cf836f9188095a21c85f663aac06b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 23 Feb 2016 10:51:46 +0000 Subject: [PATCH 01/12] qmp-shell: fix pretty printing of JSON responses Pretty printing of JSON responses is important to be able to understand large responses from query commands in particular. Unfortunately this was broken during the addition of the verbose flag in commit 1ceca07e48ead0dd2e41576c81d40e6a91cafefd Author: John Snow Date: Wed Apr 29 15:14:04 2015 -0400 scripts: qmp-shell: Add verbose flag This is because that change turned the python data structure into a formatted JSON string before the pretty print was given it. So we're just pretty printing a string, which is a no-op. The original pretty printer would output python objects. (QEMU) query-chardev { u'return': [ { u'filename': u'vc', u'frontend-open': False, u'label': u'parallel0'}, { u'filename': u'vc', u'frontend-open': True, u'label': u'serial0'}, { u'filename': u'unix:/tmp/qemp,server', u'frontend-open': True, u'label': u'compat_monitor0'}]} This fixes the problem by switching to outputting pretty formatted JSON text instead. This has the added benefit that the pretty printed output is now valid JSON text. Due to the way the verbose flag was handled, the pretty printing now applies to the command sent, as well as its response: (QEMU) query-chardev { "execute": "query-chardev", "arguments": {} } { "return": [ { "frontend-open": false, "label": "parallel0", "filename": "vc" }, { "frontend-open": true, "label": "serial0", "filename": "vc" }, { "frontend-open": true, "label": "compat_monitor0", "filename": "unix:/tmp/qmp,server" } ] } Signed-off-by: Daniel P. Berrange Message-Id: <1456224706-1591-1-git-send-email-berrange@redhat.com> Tested-by: Kashyap Chamarthy Reviewed-by: John Snow [Bonus fix: multiple -p now work] Signed-off-by: Markus Armbruster --- scripts/qmp/qmp-shell | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 7a402edf2a..0373b24b20 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -70,7 +70,6 @@ import json import ast import readline import sys -import pprint class QMPCompleter(list): def complete(self, text, state): @@ -103,11 +102,11 @@ class FuzzyJSON(ast.NodeTransformer): # TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and # _execute_cmd()). Let's design a better one. class QMPShell(qmp.QEMUMonitorProtocol): - def __init__(self, address, pp=None): + def __init__(self, address, pretty=False): qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address)) self._greeting = None self._completer = None - self._pp = pp + self._pretty = pretty self._transmode = False self._actions = list() @@ -231,11 +230,11 @@ class QMPShell(qmp.QEMUMonitorProtocol): return qmpcmd def _print(self, qmp): - jsobj = json.dumps(qmp) - if self._pp is not None: - self._pp.pprint(jsobj) - else: - print str(jsobj) + indent = None + if self._pretty: + indent = 4 + jsobj = json.dumps(qmp, indent=indent) + print str(jsobj) def _execute_cmd(self, cmdline): try: @@ -377,7 +376,7 @@ def main(): addr = '' qemu = None hmp = False - pp = None + pretty = False verbose = False try: @@ -387,9 +386,7 @@ def main(): fail_cmdline(arg) hmp = True elif arg == "-p": - if pp is not None: - fail_cmdline(arg) - pp = pprint.PrettyPrinter(indent=4) + pretty = True elif arg == "-v": verbose = True else: @@ -398,7 +395,7 @@ def main(): if hmp: qemu = HMPShell(arg) else: - qemu = QMPShell(arg, pp) + qemu = QMPShell(arg, pretty) addr = arg if qemu is None: From 96a1616c85ae62fc13aff85a34effb4b2477b7ce Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 23 Feb 2016 14:14:33 -0700 Subject: [PATCH 02/12] qapi-dealloc: Reduce use outside of generated code No need to roll our own use of the dealloc visitors when we can just directly use the qapi_free_FOO() functions that do what we want in one line. In net.c, inline net_visit() into its remaining lone caller. After this patch, test-visitor-serialization.c is the only non-generated file that needs to use a dealloc visitor, because it is testing low level aspects of the visitor interface. Signed-off-by: Eric Blake Message-Id: <1456262075-3311-2-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- hw/acpi/core.c | 11 +---------- net/net.c | 31 ++++++++++--------------------- numa.c | 9 +-------- tests/test-opts-visitor.c | 10 +--------- 4 files changed, 13 insertions(+), 48 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 3a14e90cd0..3d9e5c4a02 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -26,7 +26,6 @@ #include "hw/nvram/fw_cfg.h" #include "qemu/config-file.h" #include "qapi/opts-visitor.h" -#include "qapi/dealloc-visitor.h" #include "qapi-visit.h" #include "qapi-event.h" @@ -297,15 +296,7 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) out: g_free(blob); g_strfreev(pathnames); - - if (hdrs != NULL) { - QapiDeallocVisitor *dv; - - dv = qapi_dealloc_visitor_new(); - visit_type_AcpiTableOptions(qapi_dealloc_get_visitor(dv), NULL, &hdrs, - NULL); - qapi_dealloc_visitor_cleanup(dv); - } + qapi_free_AcpiTableOptions(hdrs); error_propagate(errp, err); } diff --git a/net/net.c b/net/net.c index aebf7531a8..b0c832e1f0 100644 --- a/net/net.c +++ b/net/net.c @@ -42,7 +42,6 @@ #include "qemu/main-loop.h" #include "qapi-visit.h" #include "qapi/opts-visitor.h" -#include "qapi/dealloc-visitor.h" #include "sysemu/sysemu.h" #include "net/filter.h" #include "qapi/string-output-visitor.h" @@ -1043,38 +1042,28 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp) } -static void net_visit(Visitor *v, int is_netdev, void **object, Error **errp) -{ - if (is_netdev) { - visit_type_Netdev(v, NULL, (Netdev **)object, errp); - } else { - visit_type_NetLegacy(v, NULL, (NetLegacy **)object, errp); - } -} - - int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) { void *object = NULL; Error *err = NULL; int ret = -1; + OptsVisitor *ov = opts_visitor_new(opts); + Visitor *v = opts_get_visitor(ov); - { - OptsVisitor *ov = opts_visitor_new(opts); - - net_visit(opts_get_visitor(ov), is_netdev, &object, &err); - opts_visitor_cleanup(ov); + if (is_netdev) { + visit_type_Netdev(v, NULL, (Netdev **)&object, &err); + } else { + visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err); } if (!err) { ret = net_client_init1(object, is_netdev, &err); } - if (object) { - QapiDeallocVisitor *dv = qapi_dealloc_visitor_new(); - - net_visit(qapi_dealloc_get_visitor(dv), is_netdev, &object, NULL); - qapi_dealloc_visitor_cleanup(dv); + if (is_netdev) { + qapi_free_Netdev(object); + } else { + qapi_free_NetLegacy(object); } error_propagate(errp, err); diff --git a/numa.c b/numa.c index 4c4f7f572e..da27bf8d4f 100644 --- a/numa.c +++ b/numa.c @@ -31,7 +31,6 @@ #include "include/exec/cpu-common.h" /* for RAM_ADDR_FMT */ #include "qapi-visit.h" #include "qapi/opts-visitor.h" -#include "qapi/dealloc-visitor.h" #include "hw/boards.h" #include "sysemu/hostmem.h" #include "qmp-commands.h" @@ -243,13 +242,7 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp) error: error_report_err(err); - - if (object) { - QapiDeallocVisitor *dv = qapi_dealloc_visitor_new(); - visit_type_NumaOptions(qapi_dealloc_get_visitor(dv), NULL, &object, - NULL); - qapi_dealloc_visitor_cleanup(dv); - } + qapi_free_NumaOptions(object); return -1; } diff --git a/tests/test-opts-visitor.c b/tests/test-opts-visitor.c index b7acf7d294..297a02d6a2 100644 --- a/tests/test-opts-visitor.c +++ b/tests/test-opts-visitor.c @@ -17,7 +17,6 @@ #include "qemu/option.h" /* qemu_opts_parse() */ #include "qapi/opts-visitor.h" /* opts_visitor_new() */ #include "test-qapi-visit.h" /* visit_type_UserDefOptions() */ -#include "qapi/dealloc-visitor.h" /* qapi_dealloc_visitor_new() */ static QemuOptsList userdef_opts = { .name = "userdef", @@ -55,14 +54,7 @@ setup_fixture(OptsVisitorFixture *f, gconstpointer test_data) static void teardown_fixture(OptsVisitorFixture *f, gconstpointer test_data) { - if (f->userdef != NULL) { - QapiDeallocVisitor *dv; - - dv = qapi_dealloc_visitor_new(); - visit_type_UserDefOptions(qapi_dealloc_get_visitor(dv), NULL, - &f->userdef, NULL); - qapi_dealloc_visitor_cleanup(dv); - } + qapi_free_UserDefOptions(f->userdef); error_free(f->err); } From 14f00c6c492488381a513c3816b15794446231a0 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:43 -0700 Subject: [PATCH 03/12] qapi: Rename 'fields' to 'members' in generator C types and JSON objects don't have fields, but members. We shouldn't gratuitously invent terminology. This patch is a strict renaming of generator code internals (including testsuite comments), before later patches rename C interfaces. No change to generated code with this patch. Suggested-by: Markus Armbruster Signed-off-by: Eric Blake Message-Id: <1457021813-10704-2-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi-commands.py | 4 ++-- scripts/qapi-event.py | 4 ++-- scripts/qapi-types.py | 8 +++---- scripts/qapi-visit.py | 28 ++++++++++++------------- scripts/qapi.py | 20 +++++++++--------- tests/qapi-schema/qapi-schema-test.json | 2 +- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index f831621843..f44e01f004 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -111,7 +111,7 @@ def gen_marshal_input_visit(arg_type, dealloc=False): v = qmp_input_get_visitor(qiv); ''') - ret += gen_visit_fields(arg_type.members, skiperr=dealloc) + ret += gen_visit_members(arg_type.members, skiperr=dealloc) if dealloc: ret += mcgen(''' @@ -175,7 +175,7 @@ def gen_marshal(name, arg_type, ret_type): ret += gen_marshal_input_visit(arg_type) ret += gen_call(name, arg_type, ret_type) - # 'goto out' produced by gen_marshal_input_visit->gen_visit_fields() + # 'goto out' produced by gen_marshal_input_visit->gen_visit_members() # for each arg_type member, and by gen_call() for ret_type if (arg_type and arg_type.members) or ret_type: ret += mcgen(''' diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 544ae1218d..fb579dd098 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -67,8 +67,8 @@ def gen_event_send(name, arg_type): ''', name=name) ret += gen_err_check() - ret += gen_visit_fields(arg_type.members, need_cast=True, - label='out_obj') + ret += gen_visit_members(arg_type.members, need_cast=True, + label='out_obj') ret += mcgen(''' out_obj: visit_end_struct(v, err ? NULL : &err); diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index eac90d2fe9..8858d290ab 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -38,7 +38,7 @@ struct %(c_name)s { c_name=c_name(name), c_type=element_type.c_type()) -def gen_struct_fields(members): +def gen_struct_members(members): ret = '' for memb in members: if memb.optional: @@ -77,16 +77,16 @@ struct %(c_name)s { /* Members inherited from %(c_name)s: */ ''', c_name=base.c_name()) - ret += gen_struct_fields(base.members) + ret += gen_struct_members(base.members) ret += mcgen(''' /* Own members: */ ''') - ret += gen_struct_fields(members) + ret += gen_struct_members(members) if variants: ret += gen_variants(variants) - # Make sure that all structs have at least one field; this avoids + # Make sure that all structs have at least one member; this avoids # potential issues with attempting to malloc space for zero-length # structs in C, and also incompatibility with C++ (where an empty # struct is size 1). diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 2308268a62..b21d3ef200 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,9 +15,9 @@ from qapi import * import re -# visit_type_FOO_fields() is always emitted; track if a forward declaration +# visit_type_FOO_members() is always emitted; track if a forward declaration # or implementation has already been output. -struct_fields_seen = set() +object_members_seen = set() def gen_visit_decl(name, scalar=False): @@ -30,10 +30,10 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error ** c_name=c_name(name), c_type=c_type) -def gen_visit_fields_decl(typ): - if typ.name in struct_fields_seen: +def gen_visit_members_decl(typ): + if typ.name in object_members_seen: return '' - struct_fields_seen.add(typ.name) + object_members_seen.add(typ.name) return mcgen(''' static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp); @@ -41,18 +41,18 @@ static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **er c_type=typ.c_name()) -def gen_visit_struct_fields(name, base, members, variants): +def gen_visit_object_members(name, base, members, variants): ret = '' if base: - ret += gen_visit_fields_decl(base) + ret += gen_visit_members_decl(base) if variants: for var in variants.variants: # Ugly special case for simple union TODO get rid of it if not var.simple_union_type(): - ret += gen_visit_fields_decl(var.type) + ret += gen_visit_members_decl(var.type) - struct_fields_seen.add(name) + object_members_seen.add(name) ret += mcgen(''' static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp) @@ -69,7 +69,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **er c_type=base.c_name()) ret += gen_err_check() - ret += gen_visit_fields(members, prefix='obj->') + ret += gen_visit_members(members, prefix='obj->') if variants: ret += mcgen(''' @@ -108,7 +108,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **er } ''') - # 'goto out' produced for base, by gen_visit_fields() for each member, + # 'goto out' produced for base, by gen_visit_members() for each member, # and if variants were present if base or members or variants: ret += mcgen(''' @@ -174,7 +174,7 @@ def gen_visit_alternate(name, variants): if var.type.alternate_qtype() == 'QTYPE_QINT': promote_int = 'false' if isinstance(var.type, QAPISchemaObjectType): - ret += gen_visit_fields_decl(var.type) + ret += gen_visit_members_decl(var.type) ret += mcgen(''' @@ -235,10 +235,10 @@ out: def gen_visit_object(name, base, members, variants): - ret = gen_visit_struct_fields(name, base, members, variants) + ret = gen_visit_object_members(name, base, members, variants) # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to - # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj + # *obj, but then visit_type_FOO_members() fails, we should clean up *obj # rather than leaving it non-NULL. As currently written, the caller must # call qapi_free_FOO() to avoid a memory leak of the partial FOO. ret += mcgen(''' diff --git a/scripts/qapi.py b/scripts/qapi.py index 18adca753d..6b2aa6e3df 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -326,7 +326,7 @@ class QAPISchemaParser(object): # -def find_base_fields(base): +def find_base_members(base): base_struct_define = find_struct(base) if not base_struct_define: return None @@ -355,11 +355,11 @@ def discriminator_find_enum_define(expr): if not (discriminator and base): return None - base_fields = find_base_fields(base) - if not base_fields: + base_members = find_base_members(base) + if not base_members: return None - discriminator_type = base_fields.get(discriminator) + discriminator_type = base_members.get(discriminator) if not discriminator_type: return None @@ -567,14 +567,14 @@ def check_union(expr, expr_info): raise QAPIExprError(expr_info, "Flat union '%s' must have a base" % name) - base_fields = find_base_fields(base) - assert base_fields + base_members = find_base_members(base) + assert base_members # The value of member 'discriminator' must name a non-optional # member of the base struct. check_name(expr_info, "Discriminator of flat union '%s'" % name, discriminator) - discriminator_type = base_fields.get(discriminator) + discriminator_type = base_members.get(discriminator) if not discriminator_type: raise QAPIExprError(expr_info, "Discriminator '%s' is not a member of base " @@ -969,7 +969,7 @@ class QAPISchemaObjectType(QAPISchemaType): assert self.variants.tag_member in self.members self.variants.check_clash(schema, self.info, seen) - # Check that the members of this type do not cause duplicate JSON fields, + # Check that the members of this type do not cause duplicate JSON members, # and update seen to track the members seen so far. Report any errors # on behalf of info, which is not necessarily self.info def check_clash(self, schema, info, seen): @@ -1647,8 +1647,8 @@ def gen_err_check(label='out', skiperr=False): label=label) -def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False, - label='out'): +def gen_visit_members(members, prefix='', need_cast=False, skiperr=False, + label='out'): ret = '' if skiperr: errparg = 'NULL' diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 632964a6ec..728659e68a 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -77,7 +77,7 @@ 'base': 'UserDefZero', 'data': { 'string': 'str', 'enum1': 'QEnumTwo' } } -# this variant of UserDefFlatUnion defaults to a union that uses fields with +# this variant of UserDefFlatUnion defaults to a union that uses members with # allocated types to test corner cases in the cleanup/dealloc visitor { 'union': 'UserDefFlatUnion2', 'base': 'UserDefUnionBase2', From c81200b01422783cd29796ef4ccc275d05f9ce67 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:44 -0700 Subject: [PATCH 04/12] qapi: Rename 'fields' to 'members' in generated C code C types and JSON objects don't have fields, but members. We shouldn't gratuitously invent terminology. This patch is a strict renaming of static genarated functions, plus the naming of the dummy filler member for empty structs, before the next patch exposes some of that naming to the rest of the code base. Suggested-by: Markus Armbruster Signed-off-by: Eric Blake Message-Id: <1457021813-10704-3-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 2 +- scripts/qapi-visit.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 8858d290ab..19d1fff877 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -92,7 +92,7 @@ struct %(c_name)s { # struct is size 1). if not (base and base.members) and not members and not variants: ret += mcgen(''' - char qapi_dummy_field_for_empty_struct; + char qapi_dummy_for_empty_struct; ''') ret += mcgen(''' diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index b21d3ef200..1e52f76f5b 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -36,7 +36,7 @@ def gen_visit_members_decl(typ): object_members_seen.add(typ.name) return mcgen(''' -static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp); +static void visit_type_%(c_type)s_members(Visitor *v, %(c_type)s *obj, Error **errp); ''', c_type=typ.c_name()) @@ -55,7 +55,7 @@ def gen_visit_object_members(name, base, members, variants): object_members_seen.add(name) ret += mcgen(''' -static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp) +static void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) { Error *err = NULL; @@ -64,7 +64,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **er if base: ret += mcgen(''' - visit_type_%(c_type)s_fields(v, (%(c_type)s *)obj, &err); + visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, &err); ''', c_type=base.c_name()) ret += gen_err_check() @@ -94,7 +94,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **er c_name=c_name(var.name)) else: ret += mcgen(''' - visit_type_%(c_type)s_fields(v, &obj->u.%(c_name)s, &err); + visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); ''', c_type=var.type.c_name(), c_name=c_name(var.name)) @@ -202,7 +202,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (err) { break; } - visit_type_%(c_type)s_fields(v, &(*obj)->u.%(c_name)s, &err); + visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, &err); error_propagate(errp, err); err = NULL; visit_end_struct(v, &err); @@ -254,7 +254,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!*obj) { goto out_obj; } - visit_type_%(c_name)s_fields(v, *obj, &err); + visit_type_%(c_name)s_members(v, *obj, &err); error_propagate(errp, err); err = NULL; out_obj: From 4d91e9115cc6700113e772b19d1f39bbcf345977 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:45 -0700 Subject: [PATCH 05/12] qapi-visit: Expose visit_type_FOO_members() Dan Berrange reported a case where he needs to work with a QCryptoBlockOptions union type using the OptsVisitor, but only visit one of the branches of that type (the discriminator is not visited directly, but learned externally). When things were boxed, it was easy: just visit the variant directly, which took care of both allocating the variant and visiting its members, then store that pointer in the union type. But now that things are unboxed, we need a way to visit the members without allocation, done by exposing visit_type_FOO_members() to the user. Before the patch, we had quite a bit of code associated with object_members_seen to make sure that a declaration of the helper was in scope before any use of the function. But now that the helper is public and declared in the header, the .c file no longer needs to worry about topological sorting (the helper is always in scope), which leads to some nice cleanups. Signed-off-by: Eric Blake Message-Id: <1457021813-10704-4-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi-visit.py | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 1e52f76f5b..a712e9af8a 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,10 +15,6 @@ from qapi import * import re -# visit_type_FOO_members() is always emitted; track if a forward declaration -# or implementation has already been output. -object_members_seen = set() - def gen_visit_decl(name, scalar=False): c_type = c_name(name) + ' *' @@ -30,37 +26,23 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error ** c_name=c_name(name), c_type=c_type) -def gen_visit_members_decl(typ): - if typ.name in object_members_seen: - return '' - object_members_seen.add(typ.name) +def gen_visit_members_decl(name): return mcgen(''' -static void visit_type_%(c_type)s_members(Visitor *v, %(c_type)s *obj, Error **errp); +void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp); ''', - c_type=typ.c_name()) + c_name=c_name(name)) def gen_visit_object_members(name, base, members, variants): - ret = '' + ret = mcgen(''' - if base: - ret += gen_visit_members_decl(base) - if variants: - for var in variants.variants: - # Ugly special case for simple union TODO get rid of it - if not var.simple_union_type(): - ret += gen_visit_members_decl(var.type) - - object_members_seen.add(name) - ret += mcgen(''' - -static void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) +void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) { Error *err = NULL; ''', - c_name=c_name(name)) + c_name=c_name(name)) if base: ret += mcgen(''' @@ -173,8 +155,6 @@ def gen_visit_alternate(name, variants): for var in variants.variants: if var.type.alternate_qtype() == 'QTYPE_QINT': promote_int = 'false' - if isinstance(var.type, QAPISchemaObjectType): - ret += gen_visit_members_decl(var.type) ret += mcgen(''' @@ -316,6 +296,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.defn += defn def visit_object_type(self, name, info, base, members, variants): + self.decl += gen_visit_members_decl(name) self.decl += gen_visit_decl(name) self.defn += gen_visit_object(name, base, members, variants) From 9ee86b852673fd9ec807b1ff3c3a1337351dac0a Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:46 -0700 Subject: [PATCH 06/12] qapi: Update docs to match recent generator changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. - Commit 51e72bc1 switched the parameter order with 'name' occurring earlier. - Commit e65d89bf changed the layout of UserDefOneList. - Prefer the term 'member' over 'field'. - We now expose visit_type_FOO_members() for objects. - 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. Also, rearrange output to show .h files before .c (understanding the interface first often makes the implementation easier to follow). Reported-by: Marc-André Lureau Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster Message-Id: <1457021813-10704-5-git-send-email-eblake@redhat.com> --- docs/qapi-code-gen.txt | 348 +++++++++++++++++++++-------------------- docs/qmp-spec.txt | 4 +- 2 files changed, 184 insertions(+), 168 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 999f3b98f0..e0b2ef11f6 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. @@ -52,7 +52,7 @@ schema. The documentation is delimited between two lines of ##, then the first line names the expression, an optional overview is provided, then individual documentation about each member of 'data' is provided, and finally, a 'Since: x.y.z' tag lists the release that introduced -the expression. Optional fields are tagged with the phrase +the expression. Optional members are tagged with the phrase '#optional', often with their default value; and extensions added after the expression was first released are also given a '(since x.y.z)' comment. For example: @@ -108,15 +108,15 @@ user-defined type names, while built-in types are lowercase. Type definitions should not end in 'Kind', as this namespace is used for creating implicit C enums for visiting union types, or in 'List', as this namespace is used for creating array types. Command names, -and field names within a type, should be all lower case with words +and member names within a type, should be all lower case with words separated by a hyphen. However, some existing older commands and complex types use underscore; when extending such expressions, consistency is preferred over blindly avoiding underscore. Event -names should be ALL_CAPS with words separated by underscore. Field +names should be ALL_CAPS with words separated by underscore. Member names cannot start with 'has-' or 'has_', as this is reserved for -tracking optional fields. +tracking optional members. -Any name (command, event, type, field, or enum value) beginning with +Any name (command, event, type, member, or enum value) beginning with "x-" is marked experimental, and may be withdrawn or changed incompatibly in a future release. All names must begin with a letter, and contain only ASCII letters, digits, dash, and underscore. There @@ -127,7 +127,7 @@ the vendor), even if the rest of the name uses dash (example: __com.redhat_drive-mirror). Names beginning with 'q_' are reserved for the generator: QMP names that resemble C keywords or other problematic strings will be munged in C to use this prefix. For -example, a field named "default" in qapi becomes "q_default" in the +example, a member named "default" in qapi becomes "q_default" in the generated C code. In the rest of this document, usage lines are given for each @@ -217,17 +217,18 @@ and must continue to work). On output structures (only mentioned in the 'returns' side of a command), changing from mandatory to optional is in general unsafe (older clients may be -expecting the field, and could crash if it is missing), although it can be done -if the only way that the optional argument will be omitted is when it is -triggered by the presence of a new input flag to the command that older clients -don't know to send. Changing from optional to mandatory is safe. +expecting the member, and could crash if it is missing), although it +can be done if the only way that the optional argument will be omitted +is when it is triggered by the presence of a new input flag to the +command that older clients don't know to send. Changing from optional +to mandatory is safe. A structure that is used in both input and output of various commands must consider the backwards compatibility constraints of both directions of use. A struct definition can specify another struct as its base. -In this case, the fields of the base type are included as top-level fields +In this case, the members of the base type are included as top-level members of the new struct's dictionary in the Client JSON Protocol wire format. An example definition is: @@ -237,7 +238,7 @@ format. An example definition is: 'data': { '*backing': 'str' } } An example BlockdevOptionsGenericCOWFormat object on the wire could use -both fields like this: +both members like this: { "file": "/some/place/my-image", "backing": "/some/place/my-backing-file" } @@ -262,7 +263,7 @@ The enum constants will be named by using a heuristic to turn the type name into a set of underscore separated words. For the example above, 'MyEnum' will turn into 'MY_ENUM' giving a constant name of 'MY_ENUM_VALUE1' for the first value. If the default heuristic -does not result in a desirable name, the optional 'prefix' field +does not result in a desirable name, the optional 'prefix' member can be used when defining the enum. The enumeration values are passed as strings over the Client JSON @@ -275,9 +276,9 @@ converting between strings and enum values. Since the wire format always passes by name, it is acceptable to reorder or add new enumeration members in any location without breaking clients of Client JSON Protocol; however, removing enum values would break -compatibility. For any struct that has a field that will only contain -a finite set of string values, using an enum type for that field is -better than open-coding the field to be type 'str'. +compatibility. For any struct that has a member that will only contain +a finite set of string values, using an enum type for that member is +better than open-coding the member to be type 'str'. === Union types === @@ -305,8 +306,8 @@ values to data types like in this example: 'qcow2': 'Qcow2Options' } } In the Client JSON Protocol, a simple union is represented by a -dictionary that contains the 'type' field as a discriminator, and a -'data' field that is of the specified data type corresponding to the +dictionary that contains the 'type' member as a discriminator, and a +'data' member that is of the specified data type corresponding to the discriminator value, as in these examples: { "type": "file", "data" : { "filename": "/some/place/my-image" } } @@ -321,14 +322,14 @@ enum. The value for each branch can be of any type. A flat union definition specifies a struct as its base, and avoids nesting on the wire. All branches of the union must be -complex types, and the top-level fields of the union dictionary on -the wire will be combination of fields from both the base type and the +complex types, and the top-level members of the union dictionary on +the wire will be combination of members from both the base type and the appropriate branch type (when merging two dictionaries, there must be -no keys in common). The 'discriminator' field must be the name of an +no keys in common). The 'discriminator' member must be the name of an enum-typed member of the base struct. The following example enhances the above simple union example by -adding a common field 'readonly', renaming the discriminator to +adding a common member 'readonly', renaming the discriminator to something more applicable, and reducing the number of {} required on the wire: @@ -353,8 +354,8 @@ the user, but because it must map to a base member with enum type, the code generator can ensure that branches exist for all values of the enum (although the order of the keys need not match the declaration of the enum). In the resulting generated C data types, a flat union is -represented as a struct with the base member fields included directly, -and then a union of structures for each branch of the struct. +represented as a struct with the base members included directly, and +then a union of structures for each branch of the struct. A simple union can always be re-written as a flat union where the base class has a single member named 'type', and where each branch of the @@ -424,10 +425,10 @@ string name of a complex type, or a dictionary that declares an anonymous type with the same semantics as a 'struct' expression, with one exception noted below when 'gen' is used. -The 'returns' member describes what will appear in the "return" field +The 'returns' member describes what will appear in the "return" member of a Client JSON Protocol reply on successful completion of a command. The member is optional from the command declaration; if absent, the -"return" field will be an empty dictionary. If 'returns' is present, +"return" member will be an empty dictionary. If 'returns' is present, it must be the string name of a complex or built-in type, a one-element array containing the name of a complex or built-in type, with one exception noted below when 'gen' is used. Although it is @@ -435,7 +436,7 @@ permitted to have the 'returns' member name a built-in type or an array of built-in types, any command that does this cannot be extended to return additional information in the future; thus, new commands should strongly consider returning a dictionary-based type or an array -of dictionaries, even if the dictionary only contains one field at the +of dictionaries, even if the dictionary only contains one member at the present. All commands in Client JSON Protocol use a dictionary to report @@ -478,7 +479,7 @@ response is not possible (although the command will still return a normal dictionary error on failure). When a successful reply is not possible, the command expression should include the optional key 'success-response' with boolean value false. So far, only QGA makes -use of this field. +use of this member. === Events === @@ -656,7 +657,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" }, @@ -722,33 +723,38 @@ 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, and returns a single element of that +type. 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 -created: +Used to generate the C types defined by a schema, along with +supporting code. The following files are created: $(prefix)qapi-types.h - C types corresponding to types defined in the schema you pass in @@ -763,38 +769,6 @@ Example: $ python scripts/qapi-types.py --output-dir="qapi-generated" \ --prefix="example-" example-schema.json - $ cat qapi-generated/example-qapi-types.c -[Uninteresting stuff omitted...] - - void qapi_free_UserDefOne(UserDefOne *obj) - { - QapiDeallocVisitor *qdv; - Visitor *v; - - if (!obj) { - return; - } - - qdv = qapi_dealloc_visitor_new(); - v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOne(v, &obj, NULL, NULL); - qapi_dealloc_visitor_cleanup(qdv); - } - - void qapi_free_UserDefOneList(UserDefOneList *obj) - { - QapiDeallocVisitor *qdv; - Visitor *v; - - if (!obj) { - return; - } - - qdv = qapi_dealloc_visitor_new(); - v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOneList(v, &obj, NULL, NULL); - qapi_dealloc_visitor_cleanup(qdv); - } $ cat qapi-generated/example-qapi-types.h [Uninteresting stuff omitted...] @@ -809,29 +783,59 @@ 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); #endif + $ cat qapi-generated/example-qapi-types.c +[Uninteresting stuff omitted...] + + void qapi_free_UserDefOne(UserDefOne *obj) + { + QapiDeallocVisitor *qdv; + Visitor *v; + + if (!obj) { + return; + } + + qdv = qapi_dealloc_visitor_new(); + v = qapi_dealloc_get_visitor(qdv); + visit_type_UserDefOne(v, NULL, &obj, NULL); + qapi_dealloc_visitor_cleanup(qdv); + } + + void qapi_free_UserDefOneList(UserDefOneList *obj) + { + QapiDeallocVisitor *qdv; + Visitor *v; + + if (!obj) { + return; + } + + qdv = qapi_dealloc_visitor_new(); + v = qapi_dealloc_get_visitor(qdv); + visit_type_UserDefOneList(v, NULL, &obj, NULL); + qapi_dealloc_visitor_cleanup(qdv); + } === scripts/qapi-visit.py === -Used to generate the visitor functions used to walk through and convert -a QObject (as provided by QMP) to a native C data structure and -vice-versa, as well as the visitor function used to dealloc a complex -schema-defined C type. +Used to generate the visitor functions used to walk through and +convert between a native QAPI C data structure and some other format +(such as QObject); the generated functions are named visit_type_FOO() +and visit_type_FOO_members(). The following files are generated: @@ -848,41 +852,62 @@ Example: $ python scripts/qapi-visit.py --output-dir="qapi-generated" --prefix="example-" example-schema.json + $ cat qapi-generated/example-qapi-visit.h +[Uninteresting stuff omitted...] + + #ifndef EXAMPLE_QAPI_VISIT_H + #define EXAMPLE_QAPI_VISIT_H + +[Visitors for built-in types omitted...] + + void visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, 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 $ cat qapi-generated/example-qapi-visit.c [Uninteresting stuff omitted...] - static void visit_type_UserDefOne_fields(Visitor *v, UserDefOne **obj, Error **errp) + void visit_type_UserDefOne_members(Visitor *v, UserDefOne *obj, Error **errp) { 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; - 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); + visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), &err); + if (err) { + goto out; } + if (!*obj) { + goto out_obj; + } + visit_type_UserDefOne_members(v, *obj, &err); + error_propagate(errp, err); + err = NULL; + out_obj: + visit_end_struct(v, &err); + 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; @@ -893,35 +918,24 @@ Example: } for (prev = (GenericList **)obj; - !err && (i = visit_next_list(v, prev, &err)) != NULL; + !err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL; prev = &i) { UserDefOneList *native_i = (UserDefOneList *)i; - visit_type_UserDefOne(v, &native_i->value, NULL, &err); + visit_type_UserDefOne(v, NULL, &native_i->value, &err); } - error_propagate(errp, err); - err = NULL; - visit_end_list(v, &err); + visit_end_list(v); out: error_propagate(errp, err); } - $ cat qapi-generated/example-qapi-visit.h -[Uninteresting stuff omitted...] - - #ifndef EXAMPLE_QAPI_VISIT_H - #define EXAMPLE_QAPI_VISIT_H - -[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); - - #endif === scripts/qapi-commands.py === -Used to generate the marshaling/dispatch functions for the commands defined -in the schema. The following files are generated: +Used to generate the marshaling/dispatch functions for the commands +defined in the schema. The generated code implements +qmp_marshal_COMMAND() (mentioned in qmp-commands.hx, and registered +automatically), and declares qmp_COMMAND() that the user must +implement. The following files are generated: $(prefix)qmp-marshal.c: command marshal/dispatch functions for each QMP command defined in the schema. Functions @@ -939,6 +953,19 @@ Example: $ python scripts/qapi-commands.py --output-dir="qapi-generated" --prefix="example-" example-schema.json + $ cat qapi-generated/example-qmp-commands.h +[Uninteresting stuff omitted...] + + #ifndef EXAMPLE_QMP_COMMANDS_H + #define EXAMPLE_QMP_COMMANDS_H + + #include "example-qapi-types.h" + #include "qapi/qmp/qdict.h" + #include "qapi/error.h" + + UserDefOne *qmp_my_command(UserDefOneList *arg1, Error **errp); + + #endif $ cat qapi-generated/example-qmp-marshal.c [Uninteresting stuff omitted...] @@ -950,7 +977,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; } @@ -961,7 +988,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); } @@ -972,10 +999,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_UserDefOneList(v, "arg1", &arg1, &err); if (err) { goto out; } @@ -992,7 +1019,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_UserDefOneList(v, "arg1", &arg1, NULL); qapi_dealloc_visitor_cleanup(qdv); } @@ -1002,24 +1029,12 @@ Example: } qapi_init(qmp_init_marshal); - $ cat qapi-generated/example-qmp-commands.h -[Uninteresting stuff omitted...] - - #ifndef EXAMPLE_QMP_COMMANDS_H - #define EXAMPLE_QMP_COMMANDS_H - - #include "example-qapi-types.h" - #include "qapi/qmp/qdict.h" - #include "qapi/error.h" - - UserDefOne *qmp_my_command(UserDefOne *arg1, Error **errp); - - #endif === scripts/qapi-event.py === -Used to generate the event-related C code defined by a schema. The -following files are created: +Used to generate the event-related C code defined by a schema, with +implementations for qapi_event_send_FOO(). The following files are +created: $(prefix)qapi-event.h - Function prototypes for each event type, plus an enumeration of all event names @@ -1029,6 +1044,27 @@ Example: $ python scripts/qapi-event.py --output-dir="qapi-generated" --prefix="example-" example-schema.json + $ cat qapi-generated/example-qapi-event.h +[Uninteresting stuff omitted...] + + #ifndef EXAMPLE_QAPI_EVENT_H + #define EXAMPLE_QAPI_EVENT_H + + #include "qapi/error.h" + #include "qapi/qmp/qdict.h" + #include "example-qapi-types.h" + + + void qapi_event_send_my_event(Error **errp); + + typedef enum example_QAPIEvent { + EXAMPLE_QAPI_EVENT_MY_EVENT = 0, + EXAMPLE_QAPI_EVENT__MAX = 1, + } example_QAPIEvent; + + extern const char *const example_QAPIEvent_lookup[]; + + #endif $ cat qapi-generated/example-qapi-event.c [Uninteresting stuff omitted...] @@ -1054,27 +1090,6 @@ Example: [EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT", [EXAMPLE_QAPI_EVENT__MAX] = NULL, }; - $ cat qapi-generated/example-qapi-event.h -[Uninteresting stuff omitted...] - - #ifndef EXAMPLE_QAPI_EVENT_H - #define EXAMPLE_QAPI_EVENT_H - - #include "qapi/error.h" - #include "qapi/qmp/qdict.h" - #include "example-qapi-types.h" - - - void qapi_event_send_my_event(Error **errp); - - typedef enum example_QAPIEvent { - EXAMPLE_QAPI_EVENT_MY_EVENT = 0, - EXAMPLE_QAPI_EVENT__MAX = 1, - } example_QAPIEvent; - - extern const char *const example_QAPIEvent_lookup[]; - - #endif === scripts/qapi-introspect.py === @@ -1089,17 +1104,6 @@ Example: $ python scripts/qapi-introspect.py --output-dir="qapi-generated" --prefix="example-" example-schema.json - $ cat qapi-generated/example-qmp-introspect.c -[Uninteresting stuff omitted...] - - const char example_qmp_schema_json[] = "[" - "{\"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\"}, " - "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, " - "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]"; $ cat qapi-generated/example-qmp-introspect.h [Uninteresting stuff omitted...] @@ -1109,3 +1113,15 @@ Example: extern const char example_qmp_schema_json[]; #endif + $ cat qapi-generated/example-qmp-introspect.c +[Uninteresting stuff omitted...] + + const char example_qmp_schema_json[] = "[" + "{\"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\"}, {\"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\"}]"; diff --git a/docs/qmp-spec.txt b/docs/qmp-spec.txt index 8e4bc3d202..f8b5356015 100644 --- a/docs/qmp-spec.txt +++ b/docs/qmp-spec.txt @@ -3,7 +3,7 @@ 0. About This Document ====================== -Copyright (C) 2009-2015 Red Hat, Inc. +Copyright (C) 2009-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. @@ -277,7 +277,7 @@ However, Clients must not assume any particular: - Amount of errors generated by a command, that is, new errors can be added to any existing command in newer versions of the Server -Any command or field name beginning with "x-" is deemed experimental, +Any command or member name beginning with "x-" is deemed experimental, and may be withdrawn or changed in an incompatible manner in a future release. From f194a1ae530e232b994d23aa8651696dd6664b5d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:47 -0700 Subject: [PATCH 07/12] chardev: Shorten references into ChardevBackend An upcoming patch will alter how simple unions, like ChardevBackend, are laid out, which will impact all lines of the form 'backend->u.XXX' (expanding it to the longer 'backend->u.XXX.data'). For better legibility in that patch, and less need for line wrapping, it's better to use a temporary variable to reduce the effect of a layout change to just the variable initializations, rather than every reference within a ChardevBackend. It doesn't hurt that this also makes the code more consistent: some clients touched here already had a temporary variable but weren't using it. Signed-off-by: Eric Blake Reviewed-By: Daniel P. Berrange Message-Id: <1457021813-10704-6-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- qemu-char.c | 122 ++++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index fc8ffda157..5ea1d349b6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -724,7 +724,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id, ChardevMux *mux = backend->u.mux; CharDriverState *chr, *drv; MuxDriver *d; - ChardevCommon *common = qapi_ChardevMux_base(backend->u.mux); + ChardevCommon *common = qapi_ChardevMux_base(mux); drv = qemu_chr_find(mux->chardev); if (drv == NULL) { @@ -1043,7 +1043,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id, char *filename_in; char *filename_out; const char *filename = opts->device; - ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.pipe); + ChardevCommon *common = qapi_ChardevHostdev_base(opts); filename_in = g_strdup_printf("%s.in", filename); @@ -1123,7 +1123,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id, ChardevStdio *opts = backend->u.stdio; CharDriverState *chr; struct sigaction act; - ChardevCommon *common = qapi_ChardevStdio_base(backend->u.stdio); + ChardevCommon *common = qapi_ChardevStdio_base(opts); if (is_daemonized()) { error_setg(errp, "cannot use stdio with -daemonize"); @@ -2141,7 +2141,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id, const char *filename = opts->device; CharDriverState *chr; WinCharState *s; - ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.pipe); + ChardevCommon *common = qapi_ChardevHostdev_base(opts); chr = qemu_chr_alloc(common, errp); if (!chr) { @@ -3216,7 +3216,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const char *id, Error **errp) { ChardevRingbuf *opts = backend->u.ringbuf; - ChardevCommon *common = qapi_ChardevRingbuf_base(backend->u.ringbuf); + ChardevCommon *common = qapi_ChardevRingbuf_base(opts); CharDriverState *chr; RingBufCharDriver *d; @@ -3506,26 +3506,29 @@ static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *path = qemu_opt_get(opts, "path"); + ChardevFile *file; if (path == NULL) { error_setg(errp, "chardev: file: no filename given"); return; } - backend->u.file = g_new0(ChardevFile, 1); - qemu_chr_parse_common(opts, qapi_ChardevFile_base(backend->u.file)); - backend->u.file->out = g_strdup(path); + file = backend->u.file = g_new0(ChardevFile, 1); + qemu_chr_parse_common(opts, qapi_ChardevFile_base(file)); + file->out = g_strdup(path); - backend->u.file->has_append = true; - backend->u.file->append = qemu_opt_get_bool(opts, "append", false); + file->has_append = true; + file->append = qemu_opt_get_bool(opts, "append", false); } static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, Error **errp) { - backend->u.stdio = g_new0(ChardevStdio, 1); - qemu_chr_parse_common(opts, qapi_ChardevStdio_base(backend->u.stdio)); - backend->u.stdio->has_signal = true; - backend->u.stdio->signal = qemu_opt_get_bool(opts, "signal", true); + ChardevStdio *stdio; + + stdio = backend->u.stdio = g_new0(ChardevStdio, 1); + qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio)); + stdio->has_signal = true; + stdio->signal = qemu_opt_get_bool(opts, "signal", true); } #ifdef HAVE_CHARDEV_SERIAL @@ -3533,14 +3536,15 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *device = qemu_opt_get(opts, "path"); + ChardevHostdev *serial; if (device == NULL) { error_setg(errp, "chardev: serial/tty: no device path given"); return; } - backend->u.serial = g_new0(ChardevHostdev, 1); - qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(backend->u.serial)); - backend->u.serial->device = g_strdup(device); + serial = backend->u.serial = g_new0(ChardevHostdev, 1); + qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial)); + serial->device = g_strdup(device); } #endif @@ -3549,14 +3553,15 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *device = qemu_opt_get(opts, "path"); + ChardevHostdev *parallel; if (device == NULL) { error_setg(errp, "chardev: parallel: no device path given"); return; } - backend->u.parallel = g_new0(ChardevHostdev, 1); - qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(backend->u.parallel)); - backend->u.parallel->device = g_strdup(device); + parallel = backend->u.parallel = g_new0(ChardevHostdev, 1); + qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel)); + parallel->device = g_strdup(device); } #endif @@ -3564,28 +3569,30 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *device = qemu_opt_get(opts, "path"); + ChardevHostdev *dev; if (device == NULL) { error_setg(errp, "chardev: pipe: no device path given"); return; } - backend->u.pipe = g_new0(ChardevHostdev, 1); - qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(backend->u.pipe)); - backend->u.pipe->device = g_strdup(device); + dev = backend->u.pipe = g_new0(ChardevHostdev, 1); + qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev)); + dev->device = g_strdup(device); } static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, Error **errp) { int val; + ChardevRingbuf *ringbuf; - backend->u.ringbuf = g_new0(ChardevRingbuf, 1); - qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(backend->u.ringbuf)); + ringbuf = backend->u.ringbuf = g_new0(ChardevRingbuf, 1); + qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf)); val = qemu_opt_get_size(opts, "size", 0); if (val != 0) { - backend->u.ringbuf->has_size = true; - backend->u.ringbuf->size = val; + ringbuf->has_size = true; + ringbuf->size = val; } } @@ -3593,14 +3600,15 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *chardev = qemu_opt_get(opts, "chardev"); + ChardevMux *mux; if (chardev == NULL) { error_setg(errp, "chardev: mux: no chardev given"); return; } - backend->u.mux = g_new0(ChardevMux, 1); - qemu_chr_parse_common(opts, qapi_ChardevMux_base(backend->u.mux)); - backend->u.mux->chardev = g_strdup(chardev); + mux = backend->u.mux = g_new0(ChardevMux, 1); + qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux)); + mux->chardev = g_strdup(chardev); } static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, @@ -3616,6 +3624,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, const char *port = qemu_opt_get(opts, "port"); const char *tls_creds = qemu_opt_get(opts, "tls-creds"); SocketAddress *addr; + ChardevSocket *sock; if (!path) { if (!host) { @@ -3633,20 +3642,20 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, } } - backend->u.socket = g_new0(ChardevSocket, 1); - qemu_chr_parse_common(opts, qapi_ChardevSocket_base(backend->u.socket)); + sock = backend->u.socket = g_new0(ChardevSocket, 1); + qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock)); - backend->u.socket->has_nodelay = true; - backend->u.socket->nodelay = do_nodelay; - backend->u.socket->has_server = true; - backend->u.socket->server = is_listen; - backend->u.socket->has_telnet = true; - backend->u.socket->telnet = is_telnet; - backend->u.socket->has_wait = true; - backend->u.socket->wait = is_waitconnect; - backend->u.socket->has_reconnect = true; - backend->u.socket->reconnect = reconnect; - backend->u.socket->tls_creds = g_strdup(tls_creds); + sock->has_nodelay = true; + sock->nodelay = do_nodelay; + sock->has_server = true; + sock->server = is_listen; + sock->has_telnet = true; + sock->telnet = is_telnet; + sock->has_wait = true; + sock->wait = is_waitconnect; + sock->has_reconnect = true; + sock->reconnect = reconnect; + sock->tls_creds = g_strdup(tls_creds); addr = g_new0(SocketAddress, 1); if (path) { @@ -3665,7 +3674,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6"); addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0); } - backend->u.socket->addr = addr; + sock->addr = addr; } static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, @@ -3677,6 +3686,7 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, const char *localport = qemu_opt_get(opts, "localport"); bool has_local = false; SocketAddress *addr; + ChardevUdp *udp; if (host == NULL || strlen(host) == 0) { host = "localhost"; @@ -3696,8 +3706,8 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, has_local = true; } - backend->u.udp = g_new0(ChardevUdp, 1); - qemu_chr_parse_common(opts, qapi_ChardevUdp_base(backend->u.udp)); + udp = backend->u.udp = g_new0(ChardevUdp, 1); + qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; @@ -3708,16 +3718,16 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0); addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6"); addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0); - backend->u.udp->remote = addr; + udp->remote = addr; if (has_local) { - backend->u.udp->has_local = true; + udp->has_local = true; addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; addr->u.inet = g_new0(InetSocketAddress, 1); addr->u.inet->host = g_strdup(localaddr); addr->u.inet->port = g_strdup(localport); - backend->u.udp->local = addr; + udp->local = addr; } } @@ -4128,7 +4138,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id, Error **errp) { ChardevFile *file = backend->u.file; - ChardevCommon *common = qapi_ChardevFile_base(backend->u.file); + ChardevCommon *common = qapi_ChardevFile_base(file); HANDLE out; if (file->has_in) { @@ -4151,7 +4161,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id, Error **errp) { ChardevHostdev *serial = backend->u.serial; - ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.serial); + ChardevCommon *common = qapi_ChardevHostdev_base(serial); return qemu_chr_open_win_path(serial->device, common, errp); } @@ -4175,7 +4185,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id, Error **errp) { ChardevFile *file = backend->u.file; - ChardevCommon *common = qapi_ChardevFile_base(backend->u.file); + ChardevCommon *common = qapi_ChardevFile_base(file); int flags, in = -1, out; flags = O_WRONLY | O_CREAT | O_BINARY; @@ -4209,7 +4219,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id, Error **errp) { ChardevHostdev *serial = backend->u.serial; - ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.serial); + ChardevCommon *common = qapi_ChardevHostdev_base(serial); int fd; fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); @@ -4228,7 +4238,7 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id, Error **errp) { ChardevHostdev *parallel = backend->u.parallel; - ChardevCommon *common = qapi_ChardevHostdev_base(backend->u.parallel); + ChardevCommon *common = qapi_ChardevHostdev_base(parallel); int fd; fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp); @@ -4280,7 +4290,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id, bool is_telnet = sock->has_telnet ? sock->telnet : false; bool is_waitconnect = sock->has_wait ? sock->wait : false; int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0; - ChardevCommon *common = qapi_ChardevSocket_base(backend->u.socket); + ChardevCommon *common = qapi_ChardevSocket_base(sock); chr = qemu_chr_alloc(common, errp); if (!chr) { @@ -4380,7 +4390,7 @@ static CharDriverState *qmp_chardev_open_udp(const char *id, Error **errp) { ChardevUdp *udp = backend->u.udp; - ChardevCommon *common = qapi_ChardevUdp_base(backend->u.udp); + ChardevCommon *common = qapi_ChardevUdp_base(udp); QIOChannelSocket *sioc = qio_channel_socket_new(); if (qio_channel_socket_dgram_sync(sioc, From 0399293e5b9e5443b82103fa8e2c97deadef9825 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:48 -0700 Subject: [PATCH 08/12] util: Shorten references into SocketAddress An upcoming patch will alter how simple unions, like SocketAddress, are laid out, which will impact all lines of the form 'addr->u.XXX' (expanding it to the longer 'addr->u.XXX.data'). For better legibility in that patch, and less need for line wrapping, it's better to use a temporary variable to reduce the effect of a layout change to just the variable initializations, rather than every reference within a SocketAddress. Also, take advantage of some C99 initialization where it makes sense (simplifying g_new0() to g_new()). Signed-off-by: Eric Blake Message-Id: <1457021813-10704-7-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- block/nbd.c | 14 +++++----- qemu-char.c | 49 +++++++++++++++++++--------------- qemu-nbd.c | 9 ++++--- tests/test-io-channel-socket.c | 34 ++++++++++++++--------- ui/vnc.c | 39 ++++++++++++++------------- util/qemu-sockets.c | 11 ++++---- 6 files changed, 88 insertions(+), 68 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index db57b4951c..9f333c9b11 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -204,18 +204,20 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, char **export, saddr = g_new0(SocketAddress, 1); if (qdict_haskey(options, "path")) { + UnixSocketAddress *q_unix; saddr->type = SOCKET_ADDRESS_KIND_UNIX; - saddr->u.q_unix = g_new0(UnixSocketAddress, 1); - saddr->u.q_unix->path = g_strdup(qdict_get_str(options, "path")); + q_unix = saddr->u.q_unix = g_new0(UnixSocketAddress, 1); + q_unix->path = g_strdup(qdict_get_str(options, "path")); qdict_del(options, "path"); } else { + InetSocketAddress *inet; saddr->type = SOCKET_ADDRESS_KIND_INET; - saddr->u.inet = g_new0(InetSocketAddress, 1); - saddr->u.inet->host = g_strdup(qdict_get_str(options, "host")); + inet = saddr->u.inet = g_new0(InetSocketAddress, 1); + inet->host = g_strdup(qdict_get_str(options, "host")); if (!qdict_get_try_str(options, "port")) { - saddr->u.inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT); + inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT); } else { - saddr->u.inet->port = g_strdup(qdict_get_str(options, "port")); + inet->port = g_strdup(qdict_get_str(options, "port")); } qdict_del(options, "host"); qdict_del(options, "port"); diff --git a/qemu-char.c b/qemu-char.c index 5ea1d349b6..af311023d6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3659,20 +3659,23 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, addr = g_new0(SocketAddress, 1); if (path) { + UnixSocketAddress *q_unix; addr->type = SOCKET_ADDRESS_KIND_UNIX; - addr->u.q_unix = g_new0(UnixSocketAddress, 1); - addr->u.q_unix->path = g_strdup(path); + q_unix = addr->u.q_unix = g_new0(UnixSocketAddress, 1); + q_unix->path = g_strdup(path); } else { addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new0(InetSocketAddress, 1); - addr->u.inet->host = g_strdup(host); - addr->u.inet->port = g_strdup(port); - addr->u.inet->has_to = qemu_opt_get(opts, "to"); - addr->u.inet->to = qemu_opt_get_number(opts, "to", 0); - addr->u.inet->has_ipv4 = qemu_opt_get(opts, "ipv4"); - addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0); - addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6"); - addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0); + addr->u.inet = g_new(InetSocketAddress, 1); + *addr->u.inet = (InetSocketAddress) { + .host = g_strdup(host), + .port = g_strdup(port), + .has_to = qemu_opt_get(opts, "to"), + .to = qemu_opt_get_number(opts, "to", 0), + .has_ipv4 = qemu_opt_get(opts, "ipv4"), + .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), + .has_ipv6 = qemu_opt_get(opts, "ipv6"), + .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), + }; } sock->addr = addr; } @@ -3711,22 +3714,26 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new0(InetSocketAddress, 1); - addr->u.inet->host = g_strdup(host); - addr->u.inet->port = g_strdup(port); - addr->u.inet->has_ipv4 = qemu_opt_get(opts, "ipv4"); - addr->u.inet->ipv4 = qemu_opt_get_bool(opts, "ipv4", 0); - addr->u.inet->has_ipv6 = qemu_opt_get(opts, "ipv6"); - addr->u.inet->ipv6 = qemu_opt_get_bool(opts, "ipv6", 0); + addr->u.inet = g_new(InetSocketAddress, 1); + *addr->u.inet = (InetSocketAddress) { + .host = g_strdup(host), + .port = g_strdup(port), + .has_ipv4 = qemu_opt_get(opts, "ipv4"), + .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), + .has_ipv6 = qemu_opt_get(opts, "ipv6"), + .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), + }; udp->remote = addr; if (has_local) { udp->has_local = true; addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new0(InetSocketAddress, 1); - addr->u.inet->host = g_strdup(localaddr); - addr->u.inet->port = g_strdup(localport); + addr->u.inet = g_new(InetSocketAddress, 1); + *addr->u.inet = (InetSocketAddress) { + .host = g_strdup(localaddr), + .port = g_strdup(localport), + }; udp->local = addr; } } diff --git a/qemu-nbd.c b/qemu-nbd.c index 5fe94d0e7b..a5c1d95344 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -380,13 +380,14 @@ static SocketAddress *nbd_build_socket_address(const char *sockpath, saddr->u.q_unix = g_new0(UnixSocketAddress, 1); saddr->u.q_unix->path = g_strdup(sockpath); } else { + InetSocketAddress *inet; saddr->type = SOCKET_ADDRESS_KIND_INET; - saddr->u.inet = g_new0(InetSocketAddress, 1); - saddr->u.inet->host = g_strdup(bindto); + inet = saddr->u.inet = g_new0(InetSocketAddress, 1); + inet->host = g_strdup(bindto); if (port) { - saddr->u.inet->port = g_strdup(port); + inet->port = g_strdup(port); } else { - saddr->u.inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT); + inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT); } } diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index 069736373c..8a34056670 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -1,7 +1,7 @@ /* * QEMU I/O channel sockets test * - * Copyright (c) 2015 Red Hat, Inc. + * Copyright (c) 2015-2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -283,14 +283,18 @@ static void test_io_channel_ipv4(bool async) SocketAddress *connect_addr = g_new0(SocketAddress, 1); listen_addr->type = SOCKET_ADDRESS_KIND_INET; - listen_addr->u.inet = g_new0(InetSocketAddress, 1); - listen_addr->u.inet->host = g_strdup("127.0.0.1"); - listen_addr->u.inet->port = NULL; /* Auto-select */ + listen_addr->u.inet = g_new(InetSocketAddress, 1); + *listen_addr->u.inet = (InetSocketAddress) { + .host = g_strdup("127.0.0.1"), + .port = NULL, /* Auto-select */ + }; connect_addr->type = SOCKET_ADDRESS_KIND_INET; - connect_addr->u.inet = g_new0(InetSocketAddress, 1); - connect_addr->u.inet->host = g_strdup("127.0.0.1"); - connect_addr->u.inet->port = NULL; /* Filled in later */ + connect_addr->u.inet = g_new(InetSocketAddress, 1); + *connect_addr->u.inet = (InetSocketAddress) { + .host = g_strdup("127.0.0.1"), + .port = NULL, /* Filled in later */ + }; test_io_channel(async, listen_addr, connect_addr, false); @@ -317,14 +321,18 @@ static void test_io_channel_ipv6(bool async) SocketAddress *connect_addr = g_new0(SocketAddress, 1); listen_addr->type = SOCKET_ADDRESS_KIND_INET; - listen_addr->u.inet = g_new0(InetSocketAddress, 1); - listen_addr->u.inet->host = g_strdup("::1"); - listen_addr->u.inet->port = NULL; /* Auto-select */ + listen_addr->u.inet = g_new(InetSocketAddress, 1); + *listen_addr->u.inet = (InetSocketAddress) { + .host = g_strdup("::1"), + .port = NULL, /* Auto-select */ + }; connect_addr->type = SOCKET_ADDRESS_KIND_INET; - connect_addr->u.inet = g_new0(InetSocketAddress, 1); - connect_addr->u.inet->host = g_strdup("::1"); - connect_addr->u.inet->port = NULL; /* Filled in later */ + connect_addr->u.inet = g_new(InetSocketAddress, 1); + *connect_addr->u.inet = (InetSocketAddress) { + .host = g_strdup("::1"), + .port = NULL, /* Filled in later */ + }; test_io_channel(async, listen_addr, connect_addr, false); diff --git a/ui/vnc.c b/ui/vnc.c index ce4c669ec9..6cd63141c4 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3530,12 +3530,13 @@ void vnc_display_open(const char *id, Error **errp) } } else { unsigned long long baseport; + InetSocketAddress *inet; saddr->type = SOCKET_ADDRESS_KIND_INET; - saddr->u.inet = g_new0(InetSocketAddress, 1); + inet = saddr->u.inet = g_new0(InetSocketAddress, 1); if (vnc[0] == '[' && vnc[hlen - 1] == ']') { - saddr->u.inet->host = g_strndup(vnc + 1, hlen - 2); + inet->host = g_strndup(vnc + 1, hlen - 2); } else { - saddr->u.inet->host = g_strndup(vnc, hlen); + inet->host = g_strndup(vnc, hlen); } if (parse_uint_full(h + 1, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", h + 1); @@ -3546,32 +3547,32 @@ void vnc_display_open(const char *id, Error **errp) error_setg(errp, "port %s out of range", h + 1); goto fail; } - saddr->u.inet->port = g_strdup_printf( + inet->port = g_strdup_printf( "%d", (int)baseport + 5900); if (to) { - saddr->u.inet->has_to = true; - saddr->u.inet->to = to + 5900; + inet->has_to = true; + inet->to = to + 5900; } - saddr->u.inet->ipv4 = ipv4; - saddr->u.inet->has_ipv4 = has_ipv4; - saddr->u.inet->ipv6 = ipv6; - saddr->u.inet->has_ipv6 = has_ipv6; + inet->ipv4 = ipv4; + inet->has_ipv4 = has_ipv4; + inet->ipv6 = ipv6; + inet->has_ipv6 = has_ipv6; if (vs->ws_enabled) { wsaddr->type = SOCKET_ADDRESS_KIND_INET; - wsaddr->u.inet = g_new0(InetSocketAddress, 1); - wsaddr->u.inet->host = g_strdup(saddr->u.inet->host); - wsaddr->u.inet->port = g_strdup(websocket); + inet = wsaddr->u.inet = g_new0(InetSocketAddress, 1); + inet->host = g_strdup(saddr->u.inet->host); + inet->port = g_strdup(websocket); if (to) { - wsaddr->u.inet->has_to = true; - wsaddr->u.inet->to = to; + inet->has_to = true; + inet->to = to; } - wsaddr->u.inet->ipv4 = ipv4; - wsaddr->u.inet->has_ipv4 = has_ipv4; - wsaddr->u.inet->ipv6 = ipv6; - wsaddr->u.inet->has_ipv6 = has_ipv6; + inet->ipv4 = ipv4; + inet->has_ipv4 = has_ipv4; + inet->ipv6 = ipv6; + inet->has_ipv6 = has_ipv6; } } } else { diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 557da20bf2..ad7c00c9ad 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1003,6 +1003,7 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, char host[NI_MAXHOST]; char serv[NI_MAXSERV]; SocketAddress *addr; + InetSocketAddress *inet; int ret; ret = getnameinfo((struct sockaddr *)sa, salen, @@ -1017,13 +1018,13 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; - addr->u.inet = g_new0(InetSocketAddress, 1); - addr->u.inet->host = g_strdup(host); - addr->u.inet->port = g_strdup(serv); + inet = addr->u.inet = g_new0(InetSocketAddress, 1); + inet->host = g_strdup(host); + inet->port = g_strdup(serv); if (sa->ss_family == AF_INET) { - addr->u.inet->has_ipv4 = addr->u.inet->ipv4 = true; + inet->has_ipv4 = inet->ipv4 = true; } else { - addr->u.inet->has_ipv6 = addr->u.inet->ipv6 = true; + inet->has_ipv6 = inet->ipv6 = true; } return addr; From b5a1b443183f56e0b9ad0f72614bdff7ace780d5 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:49 -0700 Subject: [PATCH 09/12] ui: Shorten references into InputEvent An upcoming patch will alter how simple unions, like InputEvent, are laid out, which will impact all lines of the form 'evt->u.XXX' (expanding it to the longer 'evt->u.XXX.data'). For better legibility in that patch, and less need for line wrapping, it's better to use a temporary variable to reduce the effect of a layout change to just the variable initializations, rather than every reference within an InputEvent. There was one instance in hid.c:hid_pointer_event() where the code was referring to evt->u.rel inside the case label where evt->u.abs is the correct name; thankfully, both members of the union have the same type, so it happened to work, but it is now cleaner. Signed-off-by: Eric Blake Message-Id: <1457021813-10704-8-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- hw/char/escc.c | 12 +++++---- hw/input/hid.c | 36 ++++++++++++++----------- hw/input/ps2.c | 27 +++++++++++-------- hw/input/virtio-input-hid.c | 33 ++++++++++++++--------- replay/replay-input.c | 31 ++++++++++++--------- ui/input-legacy.c | 25 ++++++++++------- ui/input.c | 54 +++++++++++++++++++++---------------- 7 files changed, 129 insertions(+), 89 deletions(-) diff --git a/hw/char/escc.c b/hw/char/escc.c index 98a1c21a89..c7a24ac421 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -842,14 +842,16 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, { ChannelState *s = (ChannelState *)dev; int qcode, keycode; + InputKeyEvent *key; assert(evt->type == INPUT_EVENT_KIND_KEY); - qcode = qemu_input_key_value_to_qcode(evt->u.key->key); + key = evt->u.key; + qcode = qemu_input_key_value_to_qcode(key->key); trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode], - evt->u.key->down); + key->down); if (qcode == Q_KEY_CODE_CAPS_LOCK) { - if (evt->u.key->down) { + if (key->down) { s->caps_lock_mode ^= 1; if (s->caps_lock_mode == 2) { return; /* Drop second press */ @@ -863,7 +865,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, } if (qcode == Q_KEY_CODE_NUM_LOCK) { - if (evt->u.key->down) { + if (key->down) { s->num_lock_mode ^= 1; if (s->num_lock_mode == 2) { return; /* Drop second press */ @@ -877,7 +879,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, } keycode = qcode_to_keycode[qcode]; - if (!evt->u.key->down) { + if (!key->down) { keycode |= 0x80; } trace_escc_sunkbd_event_out(keycode); diff --git a/hw/input/hid.c b/hw/input/hid.c index 81a85fbdd2..41a9387460 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -116,37 +116,42 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src, }; HIDState *hs = (HIDState *)dev; HIDPointerEvent *e; + InputMoveEvent *move; + InputBtnEvent *btn; assert(hs->n < QUEUE_LENGTH); e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; switch (evt->type) { case INPUT_EVENT_KIND_REL: - if (evt->u.rel->axis == INPUT_AXIS_X) { - e->xdx += evt->u.rel->value; - } else if (evt->u.rel->axis == INPUT_AXIS_Y) { - e->ydy += evt->u.rel->value; + move = evt->u.rel; + if (move->axis == INPUT_AXIS_X) { + e->xdx += move->value; + } else if (move->axis == INPUT_AXIS_Y) { + e->ydy += move->value; } break; case INPUT_EVENT_KIND_ABS: - if (evt->u.rel->axis == INPUT_AXIS_X) { - e->xdx = evt->u.rel->value; - } else if (evt->u.rel->axis == INPUT_AXIS_Y) { - e->ydy = evt->u.rel->value; + move = evt->u.abs; + if (move->axis == INPUT_AXIS_X) { + e->xdx = move->value; + } else if (move->axis == INPUT_AXIS_Y) { + e->ydy = move->value; } break; case INPUT_EVENT_KIND_BTN: - if (evt->u.btn->down) { - e->buttons_state |= bmap[evt->u.btn->button]; - if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) { + btn = evt->u.btn; + if (btn->down) { + e->buttons_state |= bmap[btn->button]; + if (btn->button == INPUT_BUTTON_WHEEL_UP) { e->dz--; - } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) { + } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { e->dz++; } } else { - e->buttons_state &= ~bmap[evt->u.btn->button]; + e->buttons_state &= ~bmap[btn->button]; } break; @@ -223,9 +228,10 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, HIDState *hs = (HIDState *)dev; int scancodes[3], i, count; int slot; + InputKeyEvent *key = evt->u.key; - count = qemu_input_key_value_to_scancode(evt->u.key->key, - evt->u.key->down, + count = qemu_input_key_value_to_scancode(key->key, + key->down, scancodes); if (hs->n + count > QUEUE_LENGTH) { fprintf(stderr, "usb-kbd: warning: key event queue full\n"); diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 1bd0ddef81..86df1a0fd6 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -182,10 +182,11 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, { PS2KbdState *s = (PS2KbdState *)dev; int scancodes[3], i, count; + InputKeyEvent *key = evt->u.key; qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - count = qemu_input_key_value_to_scancode(evt->u.key->key, - evt->u.key->down, + count = qemu_input_key_value_to_scancode(key->key, + key->down, scancodes); for (i = 0; i < count; i++) { ps2_put_keycode(s, scancodes[i]); @@ -389,6 +390,8 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, }; PS2MouseState *s = (PS2MouseState *)dev; + InputMoveEvent *move; + InputBtnEvent *btn; /* check if deltas are recorded when disabled */ if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) @@ -396,23 +399,25 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, switch (evt->type) { case INPUT_EVENT_KIND_REL: - if (evt->u.rel->axis == INPUT_AXIS_X) { - s->mouse_dx += evt->u.rel->value; - } else if (evt->u.rel->axis == INPUT_AXIS_Y) { - s->mouse_dy -= evt->u.rel->value; + move = evt->u.rel; + if (move->axis == INPUT_AXIS_X) { + s->mouse_dx += move->value; + } else if (move->axis == INPUT_AXIS_Y) { + s->mouse_dy -= move->value; } break; case INPUT_EVENT_KIND_BTN: - if (evt->u.btn->down) { - s->mouse_buttons |= bmap[evt->u.btn->button]; - if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) { + btn = evt->u.btn; + if (btn->down) { + s->mouse_buttons |= bmap[btn->button]; + if (btn->button == INPUT_BUTTON_WHEEL_UP) { s->mouse_dz--; - } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) { + } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { s->mouse_dz++; } } else { - s->mouse_buttons &= ~bmap[evt->u.btn->button]; + s->mouse_buttons &= ~bmap[btn->button]; } break; diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 9ca5395739..e5480c3f3d 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -191,46 +191,53 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src, VirtIOInput *vinput = VIRTIO_INPUT(dev); virtio_input_event event; int qcode; + InputKeyEvent *key; + InputMoveEvent *move; + InputBtnEvent *btn; switch (evt->type) { case INPUT_EVENT_KIND_KEY: - qcode = qemu_input_key_value_to_qcode(evt->u.key->key); + key = evt->u.key; + qcode = qemu_input_key_value_to_qcode(key->key); if (qcode && keymap_qcode[qcode]) { event.type = cpu_to_le16(EV_KEY); event.code = cpu_to_le16(keymap_qcode[qcode]); - event.value = cpu_to_le32(evt->u.key->down ? 1 : 0); + event.value = cpu_to_le32(key->down ? 1 : 0); virtio_input_send(vinput, &event); } else { - if (evt->u.key->down) { + if (key->down) { fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__, qcode, QKeyCode_lookup[qcode]); } } break; case INPUT_EVENT_KIND_BTN: - if (keymap_button[evt->u.btn->button]) { + btn = evt->u.btn; + if (keymap_button[btn->button]) { event.type = cpu_to_le16(EV_KEY); - event.code = cpu_to_le16(keymap_button[evt->u.btn->button]); - event.value = cpu_to_le32(evt->u.btn->down ? 1 : 0); + event.code = cpu_to_le16(keymap_button[btn->button]); + event.value = cpu_to_le32(btn->down ? 1 : 0); virtio_input_send(vinput, &event); } else { - if (evt->u.btn->down) { + if (btn->down) { fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__, - evt->u.btn->button, - InputButton_lookup[evt->u.btn->button]); + btn->button, + InputButton_lookup[btn->button]); } } break; case INPUT_EVENT_KIND_REL: + move = evt->u.rel; event.type = cpu_to_le16(EV_REL); - event.code = cpu_to_le16(axismap_rel[evt->u.rel->axis]); - event.value = cpu_to_le32(evt->u.rel->value); + event.code = cpu_to_le16(axismap_rel[move->axis]); + event.value = cpu_to_le32(move->value); virtio_input_send(vinput, &event); break; case INPUT_EVENT_KIND_ABS: + move = evt->u.abs; event.type = cpu_to_le16(EV_ABS); - event.code = cpu_to_le16(axismap_abs[evt->u.abs->axis]); - event.value = cpu_to_le32(evt->u.abs->value); + event.code = cpu_to_le16(axismap_abs[move->axis]); + event.value = cpu_to_le32(move->value); virtio_input_send(vinput, &event); break; default: diff --git a/replay/replay-input.c b/replay/replay-input.c index 93616be930..c38af50f74 100644 --- a/replay/replay-input.c +++ b/replay/replay-input.c @@ -47,20 +47,24 @@ static InputEvent *qapi_clone_InputEvent(InputEvent *src) void replay_save_input_event(InputEvent *evt) { + InputKeyEvent *key; + InputBtnEvent *btn; + InputMoveEvent *move; replay_put_dword(evt->type); switch (evt->type) { case INPUT_EVENT_KIND_KEY: - replay_put_dword(evt->u.key->key->type); + key = evt->u.key; + replay_put_dword(key->key->type); - switch (evt->u.key->key->type) { + switch (key->key->type) { case KEY_VALUE_KIND_NUMBER: - replay_put_qword(evt->u.key->key->u.number); - replay_put_byte(evt->u.key->down); + replay_put_qword(key->key->u.number); + replay_put_byte(key->down); break; case KEY_VALUE_KIND_QCODE: - replay_put_dword(evt->u.key->key->u.qcode); - replay_put_byte(evt->u.key->down); + replay_put_dword(key->key->u.qcode); + replay_put_byte(key->down); break; case KEY_VALUE_KIND__MAX: /* keep gcc happy */ @@ -68,16 +72,19 @@ void replay_save_input_event(InputEvent *evt) } break; case INPUT_EVENT_KIND_BTN: - replay_put_dword(evt->u.btn->button); - replay_put_byte(evt->u.btn->down); + btn = evt->u.btn; + replay_put_dword(btn->button); + replay_put_byte(btn->down); break; case INPUT_EVENT_KIND_REL: - replay_put_dword(evt->u.rel->axis); - replay_put_qword(evt->u.rel->value); + move = evt->u.rel; + replay_put_dword(move->axis); + replay_put_qword(move->value); break; case INPUT_EVENT_KIND_ABS: - replay_put_dword(evt->u.abs->axis); - replay_put_qword(evt->u.abs->value); + move = evt->u.abs; + replay_put_dword(move->axis); + replay_put_qword(move->value); break; case INPUT_EVENT_KIND__MAX: /* keep gcc happy */ diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 703f0a6ed1..f1c5cb4a5e 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -110,12 +110,13 @@ static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, { QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev; int scancodes[3], i, count; + InputKeyEvent *key = evt->u.key; if (!entry || !entry->put_kbd) { return; } - count = qemu_input_key_value_to_scancode(evt->u.key->key, - evt->u.key->down, + count = qemu_input_key_value_to_scancode(key->key, + key->down, scancodes); for (i = 0; i < count; i++) { entry->put_kbd(entry->opaque, scancodes[i]); @@ -150,23 +151,25 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, }; QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; + InputBtnEvent *btn; + InputMoveEvent *move; switch (evt->type) { case INPUT_EVENT_KIND_BTN: - if (evt->u.btn->down) { - s->buttons |= bmap[evt->u.btn->button]; + btn = evt->u.btn; + if (btn->down) { + s->buttons |= bmap[btn->button]; } else { - s->buttons &= ~bmap[evt->u.btn->button]; + s->buttons &= ~bmap[btn->button]; } - if (evt->u.btn->down && evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) { + if (btn->down && btn->button == INPUT_BUTTON_WHEEL_UP) { s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, s->axis[INPUT_AXIS_X], s->axis[INPUT_AXIS_Y], -1, s->buttons); } - if (evt->u.btn->down && - evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) { + if (btn->down && btn->button == INPUT_BUTTON_WHEEL_DOWN) { s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, s->axis[INPUT_AXIS_X], s->axis[INPUT_AXIS_Y], @@ -175,10 +178,12 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, } break; case INPUT_EVENT_KIND_ABS: - s->axis[evt->u.abs->axis] = evt->u.abs->value; + move = evt->u.abs; + s->axis[move->axis] = move->value; break; case INPUT_EVENT_KIND_REL: - s->axis[evt->u.rel->axis] += evt->u.rel->value; + move = evt->u.rel; + s->axis[move->axis] += move->value; break; default: break; diff --git a/ui/input.c b/ui/input.c index 6fd48efb57..13ee1173cb 100644 --- a/ui/input.c +++ b/ui/input.c @@ -166,24 +166,25 @@ void qmp_input_send_event(bool has_device, const char *device, static void qemu_input_transform_abs_rotate(InputEvent *evt) { + InputMoveEvent *move = evt->u.abs; switch (graphic_rotate) { case 90: - if (evt->u.abs->axis == INPUT_AXIS_X) { - evt->u.abs->axis = INPUT_AXIS_Y; - } else if (evt->u.abs->axis == INPUT_AXIS_Y) { - evt->u.abs->axis = INPUT_AXIS_X; - evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value; + if (move->axis == INPUT_AXIS_X) { + move->axis = INPUT_AXIS_Y; + } else if (move->axis == INPUT_AXIS_Y) { + move->axis = INPUT_AXIS_X; + move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value; } break; case 180: - evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value; + move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value; break; case 270: - if (evt->u.abs->axis == INPUT_AXIS_X) { - evt->u.abs->axis = INPUT_AXIS_Y; - evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value; - } else if (evt->u.abs->axis == INPUT_AXIS_Y) { - evt->u.abs->axis = INPUT_AXIS_X; + if (move->axis == INPUT_AXIS_X) { + move->axis = INPUT_AXIS_Y; + move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value; + } else if (move->axis == INPUT_AXIS_Y) { + move->axis = INPUT_AXIS_X; } break; } @@ -193,22 +194,26 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) { const char *name; int qcode, idx = -1; + InputKeyEvent *key; + InputBtnEvent *btn; + InputMoveEvent *move; if (src) { idx = qemu_console_get_index(src); } switch (evt->type) { case INPUT_EVENT_KIND_KEY: - switch (evt->u.key->key->type) { + key = evt->u.key; + switch (key->key->type) { case KEY_VALUE_KIND_NUMBER: - qcode = qemu_input_key_number_to_qcode(evt->u.key->key->u.number); + qcode = qemu_input_key_number_to_qcode(key->key->u.number); name = QKeyCode_lookup[qcode]; - trace_input_event_key_number(idx, evt->u.key->key->u.number, - name, evt->u.key->down); + trace_input_event_key_number(idx, key->key->u.number, + name, key->down); break; case KEY_VALUE_KIND_QCODE: - name = QKeyCode_lookup[evt->u.key->key->u.qcode]; - trace_input_event_key_qcode(idx, name, evt->u.key->down); + name = QKeyCode_lookup[key->key->u.qcode]; + trace_input_event_key_qcode(idx, name, key->down); break; case KEY_VALUE_KIND__MAX: /* keep gcc happy */ @@ -216,16 +221,19 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) } break; case INPUT_EVENT_KIND_BTN: - name = InputButton_lookup[evt->u.btn->button]; - trace_input_event_btn(idx, name, evt->u.btn->down); + btn = evt->u.btn; + name = InputButton_lookup[btn->button]; + trace_input_event_btn(idx, name, btn->down); break; case INPUT_EVENT_KIND_REL: - name = InputAxis_lookup[evt->u.rel->axis]; - trace_input_event_rel(idx, name, evt->u.rel->value); + move = evt->u.rel; + name = InputAxis_lookup[move->axis]; + trace_input_event_rel(idx, name, move->value); break; case INPUT_EVENT_KIND_ABS: - name = InputAxis_lookup[evt->u.abs->axis]; - trace_input_event_abs(idx, name, evt->u.abs->value); + move = evt->u.abs; + name = InputAxis_lookup[move->axis]; + trace_input_event_abs(idx, name, move->value); break; case INPUT_EVENT_KIND__MAX: /* keep gcc happy */ From 10f759079e616a1cc4701fc26ab5e2a048ce912c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:50 -0700 Subject: [PATCH 10/12] qapi: Avoid use of 'data' member of QAPI unions QAPI code generators currently create a 'void *data' member as part of the anonymous union embedded in the C struct corresponding to a QAPI union. However, directly assigning to this member of the union feels a bit fishy, when we can assign to another member of the struct instead. Signed-off-by: Eric Blake Reviewed-by: Daniel P. Berrange Message-Id: <1457021813-10704-9-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- blockdev.c | 31 +++++++++++++++++-------------- ui/input.c | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/blockdev.c b/blockdev.c index d4bc435940..0f20c6511f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1202,15 +1202,11 @@ void hmp_commit(Monitor *mon, const QDict *qdict) } } -static void blockdev_do_action(TransactionActionKind type, void *data, - Error **errp) +static void blockdev_do_action(TransactionAction *action, Error **errp) { - TransactionAction action; TransactionActionList list; - action.type = type; - action.u.data = data; - list.value = &action; + list.value = action; list.next = NULL; qmp_transaction(&list, false, NULL, errp); } @@ -1236,8 +1232,11 @@ void qmp_blockdev_snapshot_sync(bool has_device, const char *device, .has_mode = has_mode, .mode = mode, }; - blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC, - &snapshot, errp); + TransactionAction action = { + .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC, + .u.blockdev_snapshot_sync = &snapshot, + }; + blockdev_do_action(&action, errp); } void qmp_blockdev_snapshot(const char *node, const char *overlay, @@ -1247,9 +1246,11 @@ void qmp_blockdev_snapshot(const char *node, const char *overlay, .node = (char *) node, .overlay = (char *) overlay }; - - blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT, - &snapshot_data, errp); + TransactionAction action = { + .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT, + .u.blockdev_snapshot = &snapshot_data, + }; + blockdev_do_action(&action, errp); } void qmp_blockdev_snapshot_internal_sync(const char *device, @@ -1260,9 +1261,11 @@ void qmp_blockdev_snapshot_internal_sync(const char *device, .device = (char *) device, .name = (char *) name }; - - blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC, - &snapshot, errp); + TransactionAction action = { + .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC, + .u.blockdev_snapshot_internal_sync = &snapshot, + }; + blockdev_do_action(&action, errp); } SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, diff --git a/ui/input.c b/ui/input.c index 13ee1173cb..b035f86d37 100644 --- a/ui/input.c +++ b/ui/input.c @@ -470,7 +470,7 @@ InputEvent *qemu_input_event_new_move(InputEventKind kind, InputMoveEvent *move = g_new0(InputMoveEvent, 1); evt->type = kind; - evt->u.data = move; + evt->u.rel = move; /* evt->u.rel is the same as evt->u.abs */ move->axis = axis; move->value = value; return evt; From b1918fbb1ca080758390a0aee0588e59908d93e2 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 4 Mar 2016 08:42:40 -0700 Subject: [PATCH 11/12] chardev: Drop useless ChardevDummy type Commit d0d7708b made ChardevDummy be an empty wrapper type around ChardevCommon. But there is no technical reason for this indirection, so simplify the code by directly using the base type. Also change the fallback assignment to assign u.null rather than u.data, since a future patch will remove the data member of the C struct generated for QAPI unions. Signed-off-by: Eric Blake Reviewed-by: Daniel P. Berrange Message-Id: <1457106160-23614-1-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- backends/baum.c | 2 +- backends/msmouse.c | 2 +- qapi-schema.json | 15 ++++++--------- qemu-char.c | 8 ++++---- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/backends/baum.c b/backends/baum.c index 374562a483..c11320eecf 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -567,7 +567,7 @@ static CharDriverState *chr_baum_init(const char *id, ChardevReturn *ret, Error **errp) { - ChardevCommon *common = qapi_ChardevDummy_base(backend->u.braille); + ChardevCommon *common = backend->u.braille; BaumDriverState *baum; CharDriverState *chr; brlapi_handle_t *handle; diff --git a/backends/msmouse.c b/backends/msmouse.c index 9a82efda9e..5e1833c6e6 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -68,7 +68,7 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id, ChardevReturn *ret, Error **errp) { - ChardevCommon *common = qapi_ChardevDummy_base(backend->u.msmouse); + ChardevCommon *common = backend->u.msmouse; CharDriverState *chr; chr = qemu_chr_alloc(common, errp); diff --git a/qapi-schema.json b/qapi-schema.json index 42fd61b2ce..362c9d816a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3323,23 +3323,20 @@ # # Since: 1.4 (testdev since 2.2) ## -{ 'struct': 'ChardevDummy', 'data': { }, - 'base': 'ChardevCommon' } - { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', 'serial' : 'ChardevHostdev', 'parallel': 'ChardevHostdev', 'pipe' : 'ChardevHostdev', 'socket' : 'ChardevSocket', 'udp' : 'ChardevUdp', - 'pty' : 'ChardevDummy', - 'null' : 'ChardevDummy', + 'pty' : 'ChardevCommon', + 'null' : 'ChardevCommon', 'mux' : 'ChardevMux', - 'msmouse': 'ChardevDummy', - 'braille': 'ChardevDummy', - 'testdev': 'ChardevDummy', + 'msmouse': 'ChardevCommon', + 'braille': 'ChardevCommon', + 'testdev': 'ChardevCommon', 'stdio' : 'ChardevStdio', - 'console': 'ChardevDummy', + 'console': 'ChardevCommon', 'spicevmc' : 'ChardevSpiceChannel', 'spiceport' : 'ChardevSpicePort', 'vc' : 'ChardevVC', diff --git a/qemu-char.c b/qemu-char.c index af311023d6..e0147f3e8b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -420,7 +420,7 @@ static CharDriverState *qemu_chr_open_null(const char *id, Error **errp) { CharDriverState *chr; - ChardevCommon *common = qapi_ChardevDummy_base(backend->u.null); + ChardevCommon *common = backend->u.null; chr = qemu_chr_alloc(common, errp); if (!chr) { @@ -1366,7 +1366,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id, PtyCharDriver *s; int master_fd, slave_fd; char pty_name[PATH_MAX]; - ChardevCommon *common = qapi_ChardevDummy_base(backend->u.pty); + ChardevCommon *common = backend->u.pty; master_fd = qemu_openpty_raw(&slave_fd, pty_name); if (master_fd < 0) { @@ -2183,7 +2183,7 @@ static CharDriverState *qemu_chr_open_win_con(const char *id, ChardevReturn *ret, Error **errp) { - ChardevCommon *common = qapi_ChardevDummy_base(backend->u.console); + ChardevCommon *common = backend->u.console; return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), common, errp); } @@ -3817,7 +3817,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, } else { ChardevCommon *cc = g_new0(ChardevCommon, 1); qemu_chr_parse_common(opts, cc); - backend->u.data = cc; + backend->u.null = cc; /* Any ChardevCommon member would work */ } ret = qmp_chardev_add(bid ? bid : id, backend, errp); From 48eb62a74fc2d6b0ae9e5f414304a85cfbf33066 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Mar 2016 09:16:52 -0700 Subject: [PATCH 12/12] qapi: Drop useless 'data' member of unions We started moving away from the use of the 'void *data' member in the C union corresponding to a QAPI union back in commit 544a373; recent commits have gotten rid of other uses. Now that it is completely unused, we can remove the member itself as well as the FIXME comment. Update the testsuite to drop the negative test union-clash-data. Signed-off-by: Eric Blake Reviewed-by: Daniel P. Berrange Message-Id: <1457021813-10704-11-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 9 --------- tests/Makefile | 1 - tests/qapi-schema/union-clash-data.err | 0 tests/qapi-schema/union-clash-data.exit | 1 - tests/qapi-schema/union-clash-data.json | 7 ------- tests/qapi-schema/union-clash-data.out | 9 --------- 6 files changed, 27 deletions(-) delete mode 100644 tests/qapi-schema/union-clash-data.err delete mode 100644 tests/qapi-schema/union-clash-data.exit delete mode 100644 tests/qapi-schema/union-clash-data.json delete mode 100644 tests/qapi-schema/union-clash-data.out diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 19d1fff877..0306a884c3 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -116,17 +116,8 @@ static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj) def gen_variants(variants): - # FIXME: What purpose does data serve, besides preventing a union that - # has a branch named 'data'? We use it in qapi-visit.py to decide - # whether to bypass the switch statement if visiting the discriminator - # failed; but since we 0-initialize structs, and cannot tell what - # branch of the union is in use if the discriminator is invalid, there - # should not be any data leaks even without a data pointer. Or, if - # 'data' is merely added to guarantee we don't have an empty union, - # shouldn't we enforce that at .json parse time? ret = mcgen(''' union { /* union tag is @%(c_name)s */ - void *data; ''', c_name=c_name(variants.tag_member.name)) diff --git a/tests/Makefile b/tests/Makefile index 04e34b5c7e..cd4bbd41ad 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -358,7 +358,6 @@ qapi-schema += unicode-str.json qapi-schema += union-base-no-discriminator.json qapi-schema += union-branch-case.json qapi-schema += union-clash-branches.json -qapi-schema += union-clash-data.json qapi-schema += union-empty.json qapi-schema += union-invalid-base.json qapi-schema += union-optional-branch.json diff --git a/tests/qapi-schema/union-clash-data.err b/tests/qapi-schema/union-clash-data.err deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/qapi-schema/union-clash-data.exit b/tests/qapi-schema/union-clash-data.exit deleted file mode 100644 index 573541ac97..0000000000 --- a/tests/qapi-schema/union-clash-data.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/qapi-schema/union-clash-data.json b/tests/qapi-schema/union-clash-data.json deleted file mode 100644 index 7308e69f9c..0000000000 --- a/tests/qapi-schema/union-clash-data.json +++ /dev/null @@ -1,7 +0,0 @@ -# Union branch 'data' -# FIXME: this parses, but then fails to compile due to a duplicate 'data' -# (one from the branch name, another as a filler to avoid an empty union). -# we should either detect the collision at parse time, or change the -# generated struct to allow this to compile. -{ 'union': 'TestUnion', - 'data': { 'data': 'int' } } diff --git a/tests/qapi-schema/union-clash-data.out b/tests/qapi-schema/union-clash-data.out deleted file mode 100644 index f5752f4595..0000000000 --- a/tests/qapi-schema/union-clash-data.out +++ /dev/null @@ -1,9 +0,0 @@ -object :empty -object :obj-int-wrapper - member data: int optional=False -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE -object TestUnion - member type: TestUnionKind optional=False - case data: :obj-int-wrapper -enum TestUnionKind ['data']