Message ID | 1454075341-13658-11-git-send-email-eblake@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Eric Blake <eblake@redhat.com> writes: > 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: > > | 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, "", "ACPI_DEVICE_OST", 0, &err); > |+ visit_start_struct(v, NULL, NULL, "ACPI_DEVICE_OST", 0, &err); > | if (err) { > | goto out; > | } > | visit_type_ACPIOSTInfo(v, &info, "info", &err); > | if (err) { > |- goto out; > |+ goto out_obj; > | } > |- visit_end_struct(v, &err); > |+out_obj: > |+ visit_end_struct(v, err ? NULL : &err); Slightly awkward example, because out_obj is pointless in this degenerated case. You could pick one with multiple members (thus multiple goto out_obj), or do pseudo-code hinting at multiple members. > | 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_ACPI_DEVICE_OST, qmp, &err); > | > |out: > | qmp_output_visitor_cleanup(qov); > | error_propagate(errp, 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> > > --- > v10: avoid appearance of &err misuse; enhance commit message > v9: save churn in declaration order for later series on boxed params, > drop Marc-Andre's R-b > v8: no change > v7: place earlier in series, adjust handling of 'kind' > v6: new patch > > If desired, I can defer the hunk re-ordering the declaration of > obj to later in the series where it actually comes in handy. Patch looks good.
On 02/01/2016 05:31 AM, Markus Armbruster wrote: >> |+ visit_start_struct(v, NULL, NULL, "ACPI_DEVICE_OST", 0, &err); >> | if (err) { >> | goto out; >> | } >> | visit_type_ACPIOSTInfo(v, &info, "info", &err); >> | if (err) { >> |- goto out; >> |+ goto out_obj; >> | } >> |- visit_end_struct(v, &err); >> |+out_obj: >> |+ visit_end_struct(v, err ? NULL : &err); > > Slightly awkward example, because out_obj is pointless in this > degenerated case. You could pick one with multiple members (thus > multiple goto out_obj), or do pseudo-code hinting at multiple members. DEVICE_DELETED, DEVICE_TRAY_MOVED, MEM_UNPLUG_ERROR, NET_RX_FILTER_CHANGED, and SPICE_CONNECTED are nice candidates (two members instead of one). Do you want to take care of redoing any portion of the commit message?
Eric Blake <eblake@redhat.com> writes: > On 02/01/2016 05:31 AM, Markus Armbruster wrote: > >>> |+ visit_start_struct(v, NULL, NULL, "ACPI_DEVICE_OST", 0, &err); >>> | if (err) { >>> | goto out; >>> | } >>> | visit_type_ACPIOSTInfo(v, &info, "info", &err); >>> | if (err) { >>> |- goto out; >>> |+ goto out_obj; >>> | } >>> |- visit_end_struct(v, &err); >>> |+out_obj: >>> |+ visit_end_struct(v, err ? NULL : &err); >> >> Slightly awkward example, because out_obj is pointless in this >> degenerated case. You could pick one with multiple members (thus >> multiple goto out_obj), or do pseudo-code hinting at multiple members. > > DEVICE_DELETED, DEVICE_TRAY_MOVED, MEM_UNPLUG_ERROR, > NET_RX_FILTER_CHANGED, and SPICE_CONNECTED are nice candidates (two > members instead of one). Do you want to take care of redoing any > portion of the commit message? Can do. Unless something comes along that requires a respin.
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 720486f..0f5534f 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -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); ''') diff --git a/scripts/qapi.py b/scripts/qapi.py index 37aa6fe..43b3251 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -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()
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: | 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, "", "ACPI_DEVICE_OST", 0, &err); |+ visit_start_struct(v, NULL, NULL, "ACPI_DEVICE_OST", 0, &err); | if (err) { | goto out; | } | visit_type_ACPIOSTInfo(v, &info, "info", &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_ACPI_DEVICE_OST, qmp, &err); | |out: | qmp_output_visitor_cleanup(qov); | error_propagate(errp, 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> --- v10: avoid appearance of &err misuse; enhance commit message v9: save churn in declaration order for later series on boxed params, drop Marc-Andre's R-b v8: no change v7: place earlier in series, adjust handling of 'kind' v6: new patch If desired, I can defer the hunk re-ordering the declaration of obj to later in the series where it actually comes in handy. --- scripts/qapi-event.py | 16 +++++++--------- scripts/qapi.py | 5 +++-- 2 files changed, 10 insertions(+), 11 deletions(-)