qemu/scripts/qapi-event.py
Markus Armbruster 93b564c444 qapi: Reduce use of global variables in generators some
In preparation of the next commit, which will turn the generators into
modules.  These global variables will become local to main() then.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20180211093607.27351-7-armbru@redhat.com>
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-03-02 13:14:09 -06:00

211 lines
5.1 KiB
Python

"""
QAPI event generator
Copyright (c) 2014 Wenchao Xia
Copyright (c) 2015-2018 Red Hat Inc.
Authors:
Wenchao Xia <wenchaoqemu@gmail.com>
Markus Armbruster <armbru@redhat.com>
This work is licensed under the terms of the GNU GPL, version 2.
See the COPYING file in the top-level directory.
"""
from qapi import *
def build_event_send_proto(name, arg_type, boxed):
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
'c_name': c_name(name.lower()),
'param': build_params(arg_type, boxed, 'Error **errp')}
def gen_event_send_decl(name, arg_type, boxed):
return mcgen('''
%(proto)s;
''',
proto=build_event_send_proto(name, arg_type, boxed))
# Declare and initialize an object 'qapi' using parameters from build_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 build_params()
ret += '(char *)'
ret += c_name(memb.name)
ret += mcgen('''
};
''')
if not typ.is_implicit():
ret += mcgen('''
%(c_name)s *arg = &param;
''',
c_name=typ.c_name())
return ret
def gen_event_send(name, arg_type, boxed, event_enum_name):
# 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
{
QDict *qmp;
Error *err = NULL;
QMPEventFuncEmit emit;
''',
proto=build_event_send_proto(name, arg_type, boxed))
if arg_type and not arg_type.is_empty():
ret += mcgen('''
QObject *obj;
Visitor *v;
''')
if not boxed:
ret += gen_param_var(arg_type)
else:
assert not boxed
ret += mcgen('''
emit = qmp_event_get_func_emit();
if (!emit) {
return;
}
qmp = qmp_event_build_dict("%(name)s");
''',
name=name)
if arg_type and not arg_type.is_empty():
ret += mcgen('''
v = qobject_output_visitor_new(&obj);
''')
if not arg_type.is_implicit():
ret += mcgen('''
visit_type_%(c_name)s(v, "%(name)s", &arg, &err);
''',
name=name, c_name=arg_type.c_name())
else:
ret += mcgen('''
visit_start_struct(v, "%(name)s", NULL, 0, &err);
if (err) {
goto out;
}
visit_type_%(c_name)s_members(v, &param, &err);
if (!err) {
visit_check_struct(v, &err);
}
visit_end_struct(v, NULL);
''',
name=name, c_name=arg_type.c_name())
ret += mcgen('''
if (err) {
goto out;
}
visit_complete(v, &obj);
qdict_put_obj(qmp, "data", obj);
''')
ret += mcgen('''
emit(%(c_enum)s, qmp, &err);
''',
c_enum=c_enum_const(event_enum_name, name))
if arg_type and not arg_type.is_empty():
ret += mcgen('''
out:
visit_free(v);
''')
ret += mcgen('''
error_propagate(errp, err);
QDECREF(qmp);
}
''')
return ret
class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
def __init__(self, prefix):
self._enum_name = c_name(prefix + 'QAPIEvent', protect=False)
self.decl = None
self.defn = None
self._event_names = None
def visit_begin(self, schema):
self.decl = ''
self.defn = ''
self._event_names = []
def visit_end(self):
self.decl += gen_enum(self._enum_name, self._event_names)
self.defn += gen_enum_lookup(self._enum_name, self._event_names)
self._event_names = None
def visit_event(self, name, info, arg_type, boxed):
self.decl += gen_event_send_decl(name, arg_type, boxed)
self.defn += gen_event_send(name, arg_type, boxed, self._enum_name)
self._event_names.append(name)
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
blurb = ' * Schema-defined QAPI/QMP events'
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
#include "%(prefix)sqapi-visit.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp-event.h"
''',
prefix=prefix))
genh.add(mcgen('''
#include "qapi/util.h"
#include "%(prefix)sqapi-types.h"
''',
prefix=prefix))
schema = QAPISchema(input_file)
vis = QAPISchemaGenEventVisitor(prefix)
schema.visit(vis)
genc.add(vis.defn)
genh.add(vis.decl)
if do_c:
genc.write(output_dir, prefix + 'qapi-event.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-event.h')