15ddeec83SMarkus Armbruster""" 25ddeec83SMarkus ArmbrusterQAPI event generator 35ddeec83SMarkus Armbruster 45ddeec83SMarkus ArmbrusterCopyright (c) 2014 Wenchao Xia 55ddeec83SMarkus ArmbrusterCopyright (c) 2015-2018 Red Hat Inc. 65ddeec83SMarkus Armbruster 75ddeec83SMarkus ArmbrusterAuthors: 85ddeec83SMarkus Armbruster Wenchao Xia <wenchaoqemu@gmail.com> 95ddeec83SMarkus Armbruster Markus Armbruster <armbru@redhat.com> 105ddeec83SMarkus Armbruster 115ddeec83SMarkus ArmbrusterThis work is licensed under the terms of the GNU GPL, version 2. 125ddeec83SMarkus ArmbrusterSee the COPYING file in the top-level directory. 135ddeec83SMarkus Armbruster""" 1421cd70dfSWenchao Xia 15fb0bc835SMarkus Armbrusterfrom qapi.common import * 16*61bfb2e1SMarkus Armbrusterfrom qapi.types import gen_enum, gen_enum_lookup 1721cd70dfSWenchao Xia 18e98859a9SMarkus Armbruster 19086ee7a6SMarc-André Lureaudef build_event_send_proto(name, arg_type, boxed): 2003b4367aSMarkus Armbruster return 'void qapi_event_send_%(c_name)s(%(param)s)' % { 2103b4367aSMarkus Armbruster 'c_name': c_name(name.lower()), 223ab72385SPeter Xu 'param': build_params(arg_type, boxed)} 2321cd70dfSWenchao Xia 2421cd70dfSWenchao Xia 2548825ca4SEric Blakedef gen_event_send_decl(name, arg_type, boxed): 2621cd70dfSWenchao Xia return mcgen(''' 2721cd70dfSWenchao Xia 28e98859a9SMarkus Armbruster%(proto)s; 2921cd70dfSWenchao Xia''', 30086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 3121cd70dfSWenchao Xia 3221cd70dfSWenchao Xia 33086ee7a6SMarc-André Lureau# Declare and initialize an object 'qapi' using parameters from build_params() 340949e95bSEric Blakedef gen_param_var(typ): 350949e95bSEric Blake assert not typ.variants 360949e95bSEric Blake ret = mcgen(''' 370949e95bSEric Blake %(c_name)s param = { 380949e95bSEric Blake''', 390949e95bSEric Blake c_name=typ.c_name()) 400949e95bSEric Blake sep = ' ' 410949e95bSEric Blake for memb in typ.members: 420949e95bSEric Blake ret += sep 430949e95bSEric Blake sep = ', ' 440949e95bSEric Blake if memb.optional: 450949e95bSEric Blake ret += 'has_' + c_name(memb.name) + sep 460949e95bSEric Blake if memb.type.name == 'str': 47086ee7a6SMarc-André Lureau # Cast away const added in build_params() 480949e95bSEric Blake ret += '(char *)' 490949e95bSEric Blake ret += c_name(memb.name) 500949e95bSEric Blake ret += mcgen(''' 510949e95bSEric Blake 520949e95bSEric Blake }; 530949e95bSEric Blake''') 544d0b268fSEric Blake if not typ.is_implicit(): 554d0b268fSEric Blake ret += mcgen(''' 564d0b268fSEric Blake %(c_name)s *arg = ¶m; 574d0b268fSEric Blake''', 584d0b268fSEric Blake c_name=typ.c_name()) 590949e95bSEric Blake return ret 600949e95bSEric Blake 610949e95bSEric Blake 62a9529100SMarkus Armbrusterdef gen_event_send(name, arg_type, boxed, event_enum_name, event_emit): 630949e95bSEric Blake # FIXME: Our declaration of local variables (and of 'errp' in the 640949e95bSEric Blake # parameter list) can collide with exploded members of the event's 650949e95bSEric Blake # data type passed in as parameters. If this collision ever hits in 660949e95bSEric Blake # practice, we can rename our local variables with a leading _ prefix, 670949e95bSEric Blake # or split the code into a wrapper function that creates a boxed 680949e95bSEric Blake # 'param' object then calls another to do the real work. 69675b214bSMarkus Armbruster have_args = boxed or (arg_type and not arg_type.is_empty()) 70675b214bSMarkus Armbruster 71e98859a9SMarkus Armbruster ret = mcgen(''' 72e98859a9SMarkus Armbruster 73e98859a9SMarkus Armbruster%(proto)s 7421cd70dfSWenchao Xia{ 7521cd70dfSWenchao Xia QDict *qmp; 76e98859a9SMarkus Armbruster''', 77086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 7821cd70dfSWenchao Xia 79675b214bSMarkus Armbruster if have_args: 80e98859a9SMarkus Armbruster ret += mcgen(''' 813b098d56SEric Blake QObject *obj; 8221cd70dfSWenchao Xia Visitor *v; 83e98859a9SMarkus Armbruster''') 84c818408eSEric Blake if not boxed: 850949e95bSEric Blake ret += gen_param_var(arg_type) 8621cd70dfSWenchao Xia 87e98859a9SMarkus Armbruster ret += mcgen(''' 880949e95bSEric Blake 89e98859a9SMarkus Armbruster qmp = qmp_event_build_dict("%(name)s"); 9021cd70dfSWenchao Xia 91e98859a9SMarkus Armbruster''', 92e98859a9SMarkus Armbruster name=name) 9321cd70dfSWenchao Xia 94675b214bSMarkus Armbruster if have_args: 95e98859a9SMarkus Armbruster ret += mcgen(''' 967d5e199aSDaniel P. Berrange v = qobject_output_visitor_new(&obj); 974d0b268fSEric Blake''') 984d0b268fSEric Blake if not arg_type.is_implicit(): 994d0b268fSEric Blake ret += mcgen(''' 1003ab72385SPeter Xu visit_type_%(c_name)s(v, "%(name)s", &arg, &error_abort); 1014d0b268fSEric Blake''', 1024d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1034d0b268fSEric Blake else: 1044d0b268fSEric Blake ret += mcgen(''' 10521cd70dfSWenchao Xia 1063ab72385SPeter Xu visit_start_struct(v, "%(name)s", NULL, 0, &error_abort); 1073ab72385SPeter Xu visit_type_%(c_name)s_members(v, ¶m, &error_abort); 1083ab72385SPeter Xu visit_check_struct(v, &error_abort); 1091158bb2aSEric Blake visit_end_struct(v, NULL); 1104d0b268fSEric Blake''', 1114d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1124d0b268fSEric Blake ret += mcgen(''' 11321cd70dfSWenchao Xia 1143b098d56SEric Blake visit_complete(v, &obj); 1153b098d56SEric Blake qdict_put_obj(qmp, "data", obj); 1164d0b268fSEric Blake''') 11721cd70dfSWenchao Xia 118e98859a9SMarkus Armbruster ret += mcgen(''' 119a9529100SMarkus Armbruster %(event_emit)s(%(c_enum)s, qmp); 12021cd70dfSWenchao Xia 121e98859a9SMarkus Armbruster''', 122a9529100SMarkus Armbruster event_emit=event_emit, 123e98859a9SMarkus Armbruster c_enum=c_enum_const(event_enum_name, name)) 12421cd70dfSWenchao Xia 125675b214bSMarkus Armbruster if have_args: 126e98859a9SMarkus Armbruster ret += mcgen(''' 1272c0ef9f4SEric Blake visit_free(v); 128e98859a9SMarkus Armbruster''') 129e98859a9SMarkus Armbruster ret += mcgen(''' 130cb3e7f08SMarc-André Lureau qobject_unref(qmp); 13121cd70dfSWenchao Xia} 132e98859a9SMarkus Armbruster''') 13321cd70dfSWenchao Xia return ret 13421cd70dfSWenchao Xia 13505f43a96SMarkus Armbruster 136252dc310SMarkus Armbrusterclass QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): 13771b3f045SMarkus Armbruster 13893b564c4SMarkus Armbruster def __init__(self, prefix): 139252dc310SMarkus Armbruster QAPISchemaModularCVisitor.__init__( 140252dc310SMarkus Armbruster self, prefix, 'qapi-events', 14171b3f045SMarkus Armbruster ' * Schema-defined QAPI/QMP events', __doc__) 1421962bd39SMarc-André Lureau self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False) 1431962bd39SMarc-André Lureau self._event_enum_members = [] 144a9529100SMarkus Armbruster self._event_emit_name = c_name(prefix + 'qapi_event_emit') 145252dc310SMarkus Armbruster 146dcac6471SMarkus Armbruster def _begin_user_module(self, name): 1475d75648bSMarkus Armbruster events = self._module_basename('qapi-events', name) 1489af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 1499af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 15071b3f045SMarkus Armbruster self._genc.add(mcgen(''' 1519167ebd9SEric Blake#include "qemu/osdep.h" 1525d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 1535d75648bSMarkus Armbruster#include "%(events)s.h" 1549af23989SMarkus Armbruster#include "%(visit)s.h" 155e688df6bSMarkus Armbruster#include "qapi/error.h" 156452fcdbcSMarkus Armbruster#include "qapi/qmp/qdict.h" 157b3db211fSDaniel P. Berrange#include "qapi/qobject-output-visitor.h" 15821cd70dfSWenchao Xia#include "qapi/qmp-event.h" 15921cd70dfSWenchao Xia 16021cd70dfSWenchao Xia''', 1615d75648bSMarkus Armbruster events=events, visit=visit, 1625d75648bSMarkus Armbruster prefix=self._prefix)) 16371b3f045SMarkus Armbruster self._genh.add(mcgen(''' 1645b5f825dSMarkus Armbruster#include "qapi/util.h" 1659af23989SMarkus Armbruster#include "%(types)s.h" 16621cd70dfSWenchao Xia''', 1679af23989SMarkus Armbruster types=types)) 16821cd70dfSWenchao Xia 16971b3f045SMarkus Armbruster def visit_end(self): 1705d75648bSMarkus Armbruster self._add_system_module('emit', ' * QAPI Events emission') 1715d75648bSMarkus Armbruster self._genc.preamble_add(mcgen(''' 1725d75648bSMarkus Armbruster#include "qemu/osdep.h" 1735d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 1745d75648bSMarkus Armbruster''', 1755d75648bSMarkus Armbruster prefix=self._prefix)) 1765d75648bSMarkus Armbruster self._genh.preamble_add(mcgen(''' 1775d75648bSMarkus Armbruster#include "qapi/util.h" 1785d75648bSMarkus Armbruster''')) 1795d75648bSMarkus Armbruster self._genh.add(gen_enum(self._event_enum_name, 180a9529100SMarkus Armbruster self._event_enum_members)) 1815d75648bSMarkus Armbruster self._genc.add(gen_enum_lookup(self._event_enum_name, 1821962bd39SMarc-André Lureau self._event_enum_members)) 1835d75648bSMarkus Armbruster self._genh.add(mcgen(''' 184a9529100SMarkus Armbruster 185a9529100SMarkus Armbrustervoid %(event_emit)s(%(event_enum)s event, QDict *qdict); 186a9529100SMarkus Armbruster''', 187a9529100SMarkus Armbruster event_emit=self._event_emit_name, 188a9529100SMarkus Armbruster event_enum=self._event_enum_name)) 18971b3f045SMarkus Armbruster 190fbf09a2fSMarc-André Lureau def visit_event(self, name, info, ifcond, arg_type, boxed): 191c3cd6aa0SMarc-André Lureau with ifcontext(ifcond, self._genh, self._genc): 19271b3f045SMarkus Armbruster self._genh.add(gen_event_send_decl(name, arg_type, boxed)) 193c3cd6aa0SMarc-André Lureau self._genc.add(gen_event_send(name, arg_type, boxed, 194a9529100SMarkus Armbruster self._event_enum_name, 195a9529100SMarkus Armbruster self._event_emit_name)) 196093e3679SMarkus Armbruster # Note: we generate the enum member regardless of @ifcond, to 197093e3679SMarkus Armbruster # keep the enumeration usable in target-independent code. 198e6f9678dSMarkus Armbruster self._event_enum_members.append(QAPISchemaEnumMember(name, None)) 19971b3f045SMarkus Armbruster 20071b3f045SMarkus Armbruster 20171b3f045SMarkus Armbrusterdef gen_events(schema, output_dir, prefix): 20293b564c4SMarkus Armbruster vis = QAPISchemaGenEventVisitor(prefix) 203d46eec42SMarkus Armbruster schema.visit(vis) 20471b3f045SMarkus Armbruster vis.write(output_dir) 205