qapi-event: Utilize implicit struct visits

Rather than generate inline per-member visits, take advantage
of the 'visit_type_FOO_members()' function for emitting events.
This is possible now that implicit structs can be visited like
any other. Generated code shrinks accordingly; by initializing
a struct based on parameters, through a new gen_param_var()
helper, like:

|@@ -338,6 +250,9 @@ void qapi_event_send_block_job_error(con
| QMPEventFuncEmit emit = qmp_event_get_func_emit();
| QmpOutputVisitor *qov;
| Visitor *v;
|+ q_obj_BLOCK_JOB_ERROR_arg param = {
|+ (char *)device, operation, action
|+ };
|
| if (!emit) {
| return;
@@ -351,19 +266,7 @@ void qapi_event_send_block_job_error(con
| if (err) {
| goto out;
| }
|- visit_type_str(v, "device", (char **)&device, &err);
|- if (err) {
|- goto out_obj;
|- }
|- visit_type_IoOperationType(v, "operation", &operation, &err);
|- if (err) {
|- goto out_obj;
|- }
|- visit_type_BlockErrorAction(v, "action", &action, &err);
|- if (err) {
|- goto out_obj;
|- }
|-out_obj:
|+ visit_type_q_obj_BLOCK_JOB_ERROR_arg_members(v, &param, &err);
| visit_end_struct(v, err ? NULL : &err);

Notice that the initialization of 'param' has to cast away const
(just as the old gen_visit_members() had to do): we can't change
the signature of the user function (which uses 'const char *'), but
have to assign it to a non-const QAPI object (which requires
'char *').

While touching this, document with a FIXME comment that there is
still a potential collision between QMP members and our choice of
local variable names within qapi_event_send_FOO().

This patch also paves the way for some followup simplifications
in the generator, in subsequent patches.

Backports commit 0949e95b48e30715e157cabbc59dcb0ed912d3ff from qemu
This commit is contained in:
Eric Blake 2018-02-21 22:45:26 -05:00 committed by Lioncash
parent eb4b02705a
commit a86b89f166
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -27,7 +27,37 @@ def gen_event_send_decl(name, arg_type):
proto=gen_event_send_proto(name, arg_type))
# Declare and initialize an object 'qapi' using parameters from gen_params()
def gen_param_var(typ):
assert not typ.variants
ret = mcgen('''
%(c_name)s param = {
''',
c_name=typ.c_name())
sep = ' '
for memb in typ.members:
ret += sep
sep = ', '
if memb.optional:
ret += 'has_' + c_name(memb.name) + sep
if memb.type.name == 'str':
# Cast away const added in gen_params()
ret += '(char *)'
ret += c_name(memb.name)
ret += mcgen('''
};
''')
return ret
def gen_event_send(name, arg_type):
# FIXME: Our declaration of local variables (and of 'errp' in the
# parameter list) can collide with exploded members of the event's
# data type passed in as parameters. If this collision ever hits in
# practice, we can rename our local variables with a leading _ prefix,
# or split the code into a wrapper function that creates a boxed
# 'param' object then calls another to do the real work.
ret = mcgen('''
%(proto)s
@ -43,10 +73,11 @@ def gen_event_send(name, arg_type):
ret += mcgen('''
QmpOutputVisitor *qov;
Visitor *v;
''')
ret += gen_param_var(arg_type)
ret += mcgen('''
emit = qmp_event_get_func_emit();
if (!emit) {
return;
@ -60,24 +91,21 @@ def gen_event_send(name, arg_type):
if arg_type and arg_type.members:
ret += mcgen('''
qov = qmp_output_visitor_new();
v = qmp_output_get_visitor(qov);
visit_start_struct(v, "%(name)s", NULL, 0, &err);
''',
name=name)
ret += gen_err_check()
ret += gen_visit_members(arg_type.members, need_cast=True,
label='out_obj')
ret += mcgen('''
out_obj:
if (err) {
goto out;
}
visit_type_%(c_name)s_members(v, &param, &err);
visit_end_struct(v, err ? NULL : &err);
if (err) {
goto out;
}
qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
''')
''',
name=name, c_name=arg_type.c_name())
ret += mcgen('''
emit(%(c_enum)s, qmp, &err);