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 * 16e6c42b96SMarkus Armbrusterfrom qapi.gen import QAPISchemaModularCVisitor, ifcontext 17e6c42b96SMarkus Armbrusterfrom qapi.schema import QAPISchemaEnumMember 1861bfb2e1SMarkus Armbrusterfrom qapi.types import gen_enum, gen_enum_lookup 1921cd70dfSWenchao Xia 20e98859a9SMarkus Armbruster 21086ee7a6SMarc-André Lureaudef build_event_send_proto(name, arg_type, boxed): 2203b4367aSMarkus Armbruster return 'void qapi_event_send_%(c_name)s(%(param)s)' % { 2303b4367aSMarkus Armbruster 'c_name': c_name(name.lower()), 243ab72385SPeter Xu 'param': build_params(arg_type, boxed)} 2521cd70dfSWenchao Xia 2621cd70dfSWenchao Xia 2748825ca4SEric Blakedef gen_event_send_decl(name, arg_type, boxed): 2821cd70dfSWenchao Xia return mcgen(''' 2921cd70dfSWenchao Xia 30e98859a9SMarkus Armbruster%(proto)s; 3121cd70dfSWenchao Xia''', 32086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 3321cd70dfSWenchao Xia 3421cd70dfSWenchao Xia 35086ee7a6SMarc-André Lureau# Declare and initialize an object 'qapi' using parameters from build_params() 360949e95bSEric Blakedef gen_param_var(typ): 370949e95bSEric Blake assert not typ.variants 380949e95bSEric Blake ret = mcgen(''' 390949e95bSEric Blake %(c_name)s param = { 400949e95bSEric Blake''', 410949e95bSEric Blake c_name=typ.c_name()) 420949e95bSEric Blake sep = ' ' 430949e95bSEric Blake for memb in typ.members: 440949e95bSEric Blake ret += sep 450949e95bSEric Blake sep = ', ' 460949e95bSEric Blake if memb.optional: 470949e95bSEric Blake ret += 'has_' + c_name(memb.name) + sep 480949e95bSEric Blake if memb.type.name == 'str': 49086ee7a6SMarc-André Lureau # Cast away const added in build_params() 500949e95bSEric Blake ret += '(char *)' 510949e95bSEric Blake ret += c_name(memb.name) 520949e95bSEric Blake ret += mcgen(''' 530949e95bSEric Blake 540949e95bSEric Blake }; 550949e95bSEric Blake''') 564d0b268fSEric Blake if not typ.is_implicit(): 574d0b268fSEric Blake ret += mcgen(''' 584d0b268fSEric Blake %(c_name)s *arg = ¶m; 594d0b268fSEric Blake''', 604d0b268fSEric Blake c_name=typ.c_name()) 610949e95bSEric Blake return ret 620949e95bSEric Blake 630949e95bSEric Blake 64a9529100SMarkus Armbrusterdef gen_event_send(name, arg_type, boxed, event_enum_name, event_emit): 650949e95bSEric Blake # FIXME: Our declaration of local variables (and of 'errp' in the 660949e95bSEric Blake # parameter list) can collide with exploded members of the event's 670949e95bSEric Blake # data type passed in as parameters. If this collision ever hits in 680949e95bSEric Blake # practice, we can rename our local variables with a leading _ prefix, 690949e95bSEric Blake # or split the code into a wrapper function that creates a boxed 700949e95bSEric Blake # 'param' object then calls another to do the real work. 71675b214bSMarkus Armbruster have_args = boxed or (arg_type and not arg_type.is_empty()) 72675b214bSMarkus Armbruster 73e98859a9SMarkus Armbruster ret = mcgen(''' 74e98859a9SMarkus Armbruster 75e98859a9SMarkus Armbruster%(proto)s 7621cd70dfSWenchao Xia{ 7721cd70dfSWenchao Xia QDict *qmp; 78e98859a9SMarkus Armbruster''', 79086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 8021cd70dfSWenchao Xia 81675b214bSMarkus Armbruster if have_args: 82e98859a9SMarkus Armbruster ret += mcgen(''' 833b098d56SEric Blake QObject *obj; 8421cd70dfSWenchao Xia Visitor *v; 85e98859a9SMarkus Armbruster''') 86c818408eSEric Blake if not boxed: 870949e95bSEric Blake ret += gen_param_var(arg_type) 8821cd70dfSWenchao Xia 89e98859a9SMarkus Armbruster ret += mcgen(''' 900949e95bSEric Blake 91e98859a9SMarkus Armbruster qmp = qmp_event_build_dict("%(name)s"); 9221cd70dfSWenchao Xia 93e98859a9SMarkus Armbruster''', 94e98859a9SMarkus Armbruster name=name) 9521cd70dfSWenchao Xia 96675b214bSMarkus Armbruster if have_args: 97e98859a9SMarkus Armbruster ret += mcgen(''' 987d5e199aSDaniel P. Berrange v = qobject_output_visitor_new(&obj); 994d0b268fSEric Blake''') 1004d0b268fSEric Blake if not arg_type.is_implicit(): 1014d0b268fSEric Blake ret += mcgen(''' 1023ab72385SPeter Xu visit_type_%(c_name)s(v, "%(name)s", &arg, &error_abort); 1034d0b268fSEric Blake''', 1044d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1054d0b268fSEric Blake else: 1064d0b268fSEric Blake ret += mcgen(''' 10721cd70dfSWenchao Xia 1083ab72385SPeter Xu visit_start_struct(v, "%(name)s", NULL, 0, &error_abort); 1093ab72385SPeter Xu visit_type_%(c_name)s_members(v, ¶m, &error_abort); 1103ab72385SPeter Xu visit_check_struct(v, &error_abort); 1111158bb2aSEric Blake visit_end_struct(v, NULL); 1124d0b268fSEric Blake''', 1134d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1144d0b268fSEric Blake ret += mcgen(''' 11521cd70dfSWenchao Xia 1163b098d56SEric Blake visit_complete(v, &obj); 1173b098d56SEric Blake qdict_put_obj(qmp, "data", obj); 1184d0b268fSEric Blake''') 11921cd70dfSWenchao Xia 120e98859a9SMarkus Armbruster ret += mcgen(''' 121a9529100SMarkus Armbruster %(event_emit)s(%(c_enum)s, qmp); 12221cd70dfSWenchao Xia 123e98859a9SMarkus Armbruster''', 124a9529100SMarkus Armbruster event_emit=event_emit, 125e98859a9SMarkus Armbruster c_enum=c_enum_const(event_enum_name, name)) 12621cd70dfSWenchao Xia 127675b214bSMarkus Armbruster if have_args: 128e98859a9SMarkus Armbruster ret += mcgen(''' 1292c0ef9f4SEric Blake visit_free(v); 130e98859a9SMarkus Armbruster''') 131e98859a9SMarkus Armbruster ret += mcgen(''' 132cb3e7f08SMarc-André Lureau qobject_unref(qmp); 13321cd70dfSWenchao Xia} 134e98859a9SMarkus Armbruster''') 13521cd70dfSWenchao Xia return ret 13621cd70dfSWenchao Xia 13705f43a96SMarkus Armbruster 138252dc310SMarkus Armbrusterclass QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): 13971b3f045SMarkus Armbruster 14093b564c4SMarkus Armbruster def __init__(self, prefix): 141252dc310SMarkus Armbruster QAPISchemaModularCVisitor.__init__( 142252dc310SMarkus Armbruster self, prefix, 'qapi-events', 143*3bef3aaeSMarkus Armbruster ' * Schema-defined QAPI/QMP events', None, __doc__) 1441962bd39SMarc-André Lureau self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False) 1451962bd39SMarc-André Lureau self._event_enum_members = [] 146a9529100SMarkus Armbruster self._event_emit_name = c_name(prefix + 'qapi_event_emit') 147252dc310SMarkus Armbruster 148dcac6471SMarkus Armbruster def _begin_user_module(self, name): 1495d75648bSMarkus Armbruster events = self._module_basename('qapi-events', name) 1509af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 1519af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 15271b3f045SMarkus Armbruster self._genc.add(mcgen(''' 1539167ebd9SEric Blake#include "qemu/osdep.h" 1545d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 1555d75648bSMarkus Armbruster#include "%(events)s.h" 1569af23989SMarkus Armbruster#include "%(visit)s.h" 157e688df6bSMarkus Armbruster#include "qapi/error.h" 158452fcdbcSMarkus Armbruster#include "qapi/qmp/qdict.h" 159b3db211fSDaniel P. Berrange#include "qapi/qobject-output-visitor.h" 16021cd70dfSWenchao Xia#include "qapi/qmp-event.h" 16121cd70dfSWenchao Xia 16221cd70dfSWenchao Xia''', 1635d75648bSMarkus Armbruster events=events, visit=visit, 1645d75648bSMarkus Armbruster prefix=self._prefix)) 16571b3f045SMarkus Armbruster self._genh.add(mcgen(''' 1665b5f825dSMarkus Armbruster#include "qapi/util.h" 1679af23989SMarkus Armbruster#include "%(types)s.h" 16821cd70dfSWenchao Xia''', 1699af23989SMarkus Armbruster types=types)) 17021cd70dfSWenchao Xia 17171b3f045SMarkus Armbruster def visit_end(self): 1725d75648bSMarkus Armbruster self._add_system_module('emit', ' * QAPI Events emission') 1735d75648bSMarkus Armbruster self._genc.preamble_add(mcgen(''' 1745d75648bSMarkus Armbruster#include "qemu/osdep.h" 1755d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 1765d75648bSMarkus Armbruster''', 1775d75648bSMarkus Armbruster prefix=self._prefix)) 1785d75648bSMarkus Armbruster self._genh.preamble_add(mcgen(''' 1795d75648bSMarkus Armbruster#include "qapi/util.h" 1805d75648bSMarkus Armbruster''')) 1815d75648bSMarkus Armbruster self._genh.add(gen_enum(self._event_enum_name, 182a9529100SMarkus Armbruster self._event_enum_members)) 1835d75648bSMarkus Armbruster self._genc.add(gen_enum_lookup(self._event_enum_name, 1841962bd39SMarc-André Lureau self._event_enum_members)) 1855d75648bSMarkus Armbruster self._genh.add(mcgen(''' 186a9529100SMarkus Armbruster 187a9529100SMarkus Armbrustervoid %(event_emit)s(%(event_enum)s event, QDict *qdict); 188a9529100SMarkus Armbruster''', 189a9529100SMarkus Armbruster event_emit=self._event_emit_name, 190a9529100SMarkus Armbruster event_enum=self._event_enum_name)) 19171b3f045SMarkus Armbruster 192fbf09a2fSMarc-André Lureau def visit_event(self, name, info, ifcond, arg_type, boxed): 193c3cd6aa0SMarc-André Lureau with ifcontext(ifcond, self._genh, self._genc): 19471b3f045SMarkus Armbruster self._genh.add(gen_event_send_decl(name, arg_type, boxed)) 195c3cd6aa0SMarc-André Lureau self._genc.add(gen_event_send(name, arg_type, boxed, 196a9529100SMarkus Armbruster self._event_enum_name, 197a9529100SMarkus Armbruster self._event_emit_name)) 198093e3679SMarkus Armbruster # Note: we generate the enum member regardless of @ifcond, to 199093e3679SMarkus Armbruster # keep the enumeration usable in target-independent code. 200e6f9678dSMarkus Armbruster self._event_enum_members.append(QAPISchemaEnumMember(name, None)) 20171b3f045SMarkus Armbruster 20271b3f045SMarkus Armbruster 20371b3f045SMarkus Armbrusterdef gen_events(schema, output_dir, prefix): 20493b564c4SMarkus Armbruster vis = QAPISchemaGenEventVisitor(prefix) 205d46eec42SMarkus Armbruster schema.visit(vis) 20671b3f045SMarkus Armbruster vis.write(output_dir) 207