mirror of
https://github.com/yuzu-emu/unicorn
synced 2024-11-25 09:29:11 +00:00
4ca10929a7
Consolidate the code between visit, command marshalling, and event generation that iterates over the members of a struct. It reduces code duplication in the generator, so that a future patch can reduce the size of generated code while touching only one instead of three locations. There are no changes to the generated marshal code. The visitor code becomes slightly more verbose, but remains semantically equivalent, and is actually easier to read as it follows a more common idiom: | visit_optional(v, &(*obj)->has_device, "device", &err); |- if (!err && (*obj)->has_device) { |- visit_type_str(v, &(*obj)->device, "device", &err); |- } | if (err) { | goto out; | } |+ if ((*obj)->has_device) { |+ visit_type_str(v, &(*obj)->device, "device", &err); |+ if (err) { |+ goto out; |+ } |+ } The event code becomes slightly more verbose, but this is arguably a bug fix: although the visitors are not well documented, use of an optional member should not be attempted unless guarded by a prior call to visit_optional(). Works only because the output qmp visitor has a no-op visit_optional(): |+ visit_optional(v, &has_offset, "offset", &err); |+ if (err) { |+ goto out; |+ } | if (has_offset) { | visit_type_int(v, &offset, "offset", &err); Backports commit 82ca8e469666b169ccf818a0e36136aee97d7db0 from qemu
186 lines
4.1 KiB
Python
186 lines
4.1 KiB
Python
#
|
|
# QAPI event generator
|
|
#
|
|
# Copyright (c) 2014 Wenchao Xia
|
|
# Copyright (c) 2015 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 gen_event_send_proto(name, arg_type):
|
|
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
|
|
'c_name': c_name(name.lower()),
|
|
'param': gen_params(arg_type, 'Error **errp')}
|
|
|
|
|
|
def gen_event_send_decl(name, arg_type):
|
|
return mcgen('''
|
|
|
|
%(proto)s;
|
|
''',
|
|
proto=gen_event_send_proto(name, arg_type))
|
|
|
|
|
|
def gen_event_send(name, arg_type):
|
|
ret = mcgen('''
|
|
|
|
%(proto)s
|
|
{
|
|
QDict *qmp;
|
|
Error *err = NULL;
|
|
QMPEventFuncEmit emit;
|
|
''',
|
|
proto=gen_event_send_proto(name, arg_type))
|
|
|
|
if arg_type and arg_type.members:
|
|
ret += mcgen('''
|
|
QmpOutputVisitor *qov;
|
|
Visitor *v;
|
|
QObject *obj;
|
|
|
|
''')
|
|
|
|
ret += mcgen('''
|
|
emit = qmp_event_get_func_emit();
|
|
if (!emit) {
|
|
return;
|
|
}
|
|
|
|
qmp = qmp_event_build_dict("%(name)s");
|
|
|
|
''',
|
|
name=name)
|
|
|
|
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);
|
|
''',
|
|
name=name)
|
|
ret += gen_err_check()
|
|
ret += gen_visit_fields(arg_type.members, need_cast=True)
|
|
ret += mcgen('''
|
|
visit_end_struct(v, &err);
|
|
if (err) {
|
|
goto out;
|
|
}
|
|
|
|
obj = qmp_output_get_qobject(qov);
|
|
g_assert(obj != NULL);
|
|
|
|
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 arg_type.members:
|
|
ret += mcgen('''
|
|
out:
|
|
qmp_output_visitor_cleanup(qov);
|
|
''')
|
|
ret += mcgen('''
|
|
error_propagate(errp, err);
|
|
QDECREF(qmp);
|
|
}
|
|
''')
|
|
return ret
|
|
|
|
|
|
class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
|
|
def __init__(self):
|
|
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(event_enum_name, self._event_names)
|
|
self.defn += gen_enum_lookup(event_enum_name, self._event_names)
|
|
self._event_names = None;
|
|
|
|
def visit_event(self, name, info, arg_type):
|
|
self.decl += gen_event_send_decl(name, arg_type)
|
|
self.defn += gen_event_send(name, arg_type)
|
|
self._event_names.append(name)
|
|
|
|
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
|
|
|
|
c_comment = '''
|
|
/*
|
|
* schema-defined QAPI event functions
|
|
*
|
|
* Copyright (c) 2014 Wenchao Xia
|
|
*
|
|
* Authors:
|
|
* Wenchao Xia <wenchaoqemu@gmail.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
*
|
|
*/
|
|
'''
|
|
h_comment = '''
|
|
/*
|
|
* schema-defined QAPI event functions
|
|
*
|
|
* Copyright (c) 2014 Wenchao Xia
|
|
*
|
|
* Authors:
|
|
* Wenchao Xia <wenchaoqemu@gmail.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
*
|
|
*/
|
|
'''
|
|
|
|
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
|
|
'qapi-event.c', 'qapi-event.h',
|
|
c_comment, h_comment)
|
|
fdef.write(mcgen('''
|
|
#include "qemu-common.h"
|
|
#include "%(prefix)sqapi-event.h"
|
|
#include "%(prefix)sqapi-visit.h"
|
|
#include "qapi/qmp-output-visitor.h"
|
|
#include "qapi/qmp-event.h"
|
|
|
|
''',
|
|
prefix=prefix))
|
|
|
|
fdecl.write(mcgen('''
|
|
#include "qapi/error.h"
|
|
#include "qapi/qmp/qdict.h"
|
|
#include "%(prefix)sqapi-types.h"
|
|
|
|
''',
|
|
prefix=prefix))
|
|
|
|
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
|
|
|
|
schema = QAPISchema(input_file)
|
|
gen = QAPISchemaGenEventVisitor()
|
|
schema.visit(gen)
|
|
fdef.write(gen.defn)
|
|
fdecl.write(gen.decl)
|
|
|
|
close_output(fdef, fdecl)
|