qapi: Improve generated event use of qapi visitor

All other successful clients of visit_start_struct() were paired
with an unconditional visit_end_struct(); but the generated
code for events was relying on qmp_output_visitor_cleanup() to
work on an incomplete visit.  Alter the code to guarantee that
the struct is completed, which will make a future patch to
split visit_end_struct() easier to reason about.  While at it,
drop some assertions and comments that are not present in other
uses of the qmp output visitor, and pass NULL rather than "" as
the 'kind' parameter (matching most other uses where obj is NULL).

The changes to the generated code look like:

|     qmp = qmp_event_build_dict("DEVICE_TRAY_MOVED");
|
|     qov = qmp_output_visitor_new();
|-    g_assert(qov);
|-
|     v = qmp_output_get_visitor(qov);
|-    g_assert(v);
|
|-    /* Fake visit, as if all members are under a structure */
|-    visit_start_struct(v, NULL, "", "DEVICE_TRAY_MOVED", 0, &err);
|+    visit_start_struct(v, NULL, NULL, "DEVICE_TRAY_MOVED", 0, &err);
|     if (err) {
|         goto out;
|     }
|     visit_type_str(v, (char **)&device, "device", &err);
|     if (err) {
|-        goto out;
|+        goto out_obj;
|     }
|     visit_type_bool(v, &tray_open, "tray-open", &err);
|     if (err) {
|-        goto out;
|+        goto out_obj;
|     }
|-    visit_end_struct(v, &err);
|+out_obj:
|+    visit_end_struct(v, err ? NULL : &err);
|     if (err) {
|         goto out;
|     }
|
|     obj = qmp_output_get_qobject(qov);
|-    g_assert(obj != NULL);
|+    g_assert(obj);
|
|     qdict_put_obj(qmp, "data", obj);
|     emit(QAPI_EVENT_DEVICE_TRAY_MOVED, qmp, &err);

Note that the 'goto out_obj' with no intervening code before the
label, as well as the construct of 'err ? NULL : &err', are both
a bit unusual but also temporary; they get fixed in a later patch
that splits visit_end_struct() to drop its errp parameter by moving
some checking before the label.  But until that time, this was the
simplest way to avoid the appearance of passing a possibly-set
error to visit_end_struct(), even though actual code inspection
shows that visit_end_struct() for a QMP output visitor will never
set an error.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1454075341-13658-11-git-send-email-eblake@redhat.com>
[Commit message's code diff tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
Eric Blake 2016-01-29 06:48:46 -07:00 committed by Markus Armbruster
parent 9dbb8fa7ef
commit a16e3e5c58
2 changed files with 10 additions and 11 deletions

View File

@ -2,7 +2,7 @@
# QAPI event generator
#
# Copyright (c) 2014 Wenchao Xia
# Copyright (c) 2015 Red Hat Inc.
# Copyright (c) 2015-2016 Red Hat Inc.
#
# Authors:
# Wenchao Xia <wenchaoqemu@gmail.com>
@ -61,25 +61,23 @@ def gen_event_send(name, arg_type):
if arg_type and arg_type.members:
ret += mcgen('''
qov = qmp_output_visitor_new();
g_assert(qov);
v = qmp_output_get_visitor(qov);
g_assert(v);
/* Fake visit, as if all members are under a structure */
visit_start_struct(v, NULL, "", "%(name)s", 0, &err);
visit_start_struct(v, NULL, NULL, "%(name)s", 0, &err);
''',
name=name)
ret += gen_err_check()
ret += gen_visit_fields(arg_type.members, need_cast=True)
ret += gen_visit_fields(arg_type.members, need_cast=True,
label='out_obj')
ret += mcgen('''
visit_end_struct(v, &err);
out_obj:
visit_end_struct(v, err ? NULL : &err);
if (err) {
goto out;
}
obj = qmp_output_get_qobject(qov);
g_assert(obj != NULL);
g_assert(obj);
qdict_put_obj(qmp, "data", obj);
''')

View File

@ -1636,7 +1636,8 @@ def gen_err_check(label='out', skiperr=False):
label=label)
def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False,
label='out'):
ret = ''
if skiperr:
errparg = 'NULL'
@ -1664,7 +1665,7 @@ def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
c_type=memb.type.c_name(), prefix=prefix, cast=cast,
c_name=c_name(memb.name), name=memb.name,
errp=errparg)
ret += gen_err_check(skiperr=skiperr)
ret += gen_err_check(skiperr=skiperr, label=label)
if memb.optional:
pop_indent()