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 * 1621cd70dfSWenchao Xia 17e98859a9SMarkus Armbruster 18086ee7a6SMarc-André Lureaudef build_event_send_proto(name, arg_type, boxed): 1903b4367aSMarkus Armbruster return 'void qapi_event_send_%(c_name)s(%(param)s)' % { 2003b4367aSMarkus Armbruster 'c_name': c_name(name.lower()), 21086ee7a6SMarc-André Lureau 'param': build_params(arg_type, boxed, 'Error **errp')} 2221cd70dfSWenchao Xia 2321cd70dfSWenchao Xia 2448825ca4SEric Blakedef gen_event_send_decl(name, arg_type, boxed): 2521cd70dfSWenchao Xia return mcgen(''' 2621cd70dfSWenchao Xia 27e98859a9SMarkus Armbruster%(proto)s; 2821cd70dfSWenchao Xia''', 29086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 3021cd70dfSWenchao Xia 3121cd70dfSWenchao Xia 32086ee7a6SMarc-André Lureau# Declare and initialize an object 'qapi' using parameters from build_params() 330949e95bSEric Blakedef gen_param_var(typ): 340949e95bSEric Blake assert not typ.variants 350949e95bSEric Blake ret = mcgen(''' 360949e95bSEric Blake %(c_name)s param = { 370949e95bSEric Blake''', 380949e95bSEric Blake c_name=typ.c_name()) 390949e95bSEric Blake sep = ' ' 400949e95bSEric Blake for memb in typ.members: 410949e95bSEric Blake ret += sep 420949e95bSEric Blake sep = ', ' 430949e95bSEric Blake if memb.optional: 440949e95bSEric Blake ret += 'has_' + c_name(memb.name) + sep 450949e95bSEric Blake if memb.type.name == 'str': 46086ee7a6SMarc-André Lureau # Cast away const added in build_params() 470949e95bSEric Blake ret += '(char *)' 480949e95bSEric Blake ret += c_name(memb.name) 490949e95bSEric Blake ret += mcgen(''' 500949e95bSEric Blake 510949e95bSEric Blake }; 520949e95bSEric Blake''') 534d0b268fSEric Blake if not typ.is_implicit(): 544d0b268fSEric Blake ret += mcgen(''' 554d0b268fSEric Blake %(c_name)s *arg = ¶m; 564d0b268fSEric Blake''', 574d0b268fSEric Blake c_name=typ.c_name()) 580949e95bSEric Blake return ret 590949e95bSEric Blake 600949e95bSEric Blake 6193b564c4SMarkus Armbrusterdef gen_event_send(name, arg_type, boxed, event_enum_name): 620949e95bSEric Blake # FIXME: Our declaration of local variables (and of 'errp' in the 630949e95bSEric Blake # parameter list) can collide with exploded members of the event's 640949e95bSEric Blake # data type passed in as parameters. If this collision ever hits in 650949e95bSEric Blake # practice, we can rename our local variables with a leading _ prefix, 660949e95bSEric Blake # or split the code into a wrapper function that creates a boxed 670949e95bSEric Blake # 'param' object then calls another to do the real work. 68e98859a9SMarkus Armbruster ret = mcgen(''' 69e98859a9SMarkus Armbruster 70e98859a9SMarkus Armbruster%(proto)s 7121cd70dfSWenchao Xia{ 7221cd70dfSWenchao Xia QDict *qmp; 732a0f50e8SEric Blake Error *err = NULL; 7421cd70dfSWenchao Xia QMPEventFuncEmit emit; 75e98859a9SMarkus Armbruster''', 76086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 7721cd70dfSWenchao Xia 78b6167706SEric Blake if arg_type and not arg_type.is_empty(): 79e98859a9SMarkus Armbruster ret += mcgen(''' 803b098d56SEric Blake QObject *obj; 8121cd70dfSWenchao Xia Visitor *v; 82e98859a9SMarkus Armbruster''') 83c818408eSEric Blake if not boxed: 840949e95bSEric Blake ret += gen_param_var(arg_type) 85c818408eSEric Blake else: 86c818408eSEric Blake assert not boxed 8721cd70dfSWenchao Xia 88e98859a9SMarkus Armbruster ret += mcgen(''' 890949e95bSEric Blake 9021cd70dfSWenchao Xia emit = qmp_event_get_func_emit(); 9121cd70dfSWenchao Xia if (!emit) { 9221cd70dfSWenchao Xia return; 9321cd70dfSWenchao Xia } 9421cd70dfSWenchao Xia 95e98859a9SMarkus Armbruster qmp = qmp_event_build_dict("%(name)s"); 9621cd70dfSWenchao Xia 97e98859a9SMarkus Armbruster''', 98e98859a9SMarkus Armbruster name=name) 9921cd70dfSWenchao Xia 100b6167706SEric Blake if arg_type and not arg_type.is_empty(): 101e98859a9SMarkus Armbruster ret += mcgen(''' 1027d5e199aSDaniel P. Berrange v = qobject_output_visitor_new(&obj); 1034d0b268fSEric Blake''') 1044d0b268fSEric Blake if not arg_type.is_implicit(): 1054d0b268fSEric Blake ret += mcgen(''' 1064d0b268fSEric Blake visit_type_%(c_name)s(v, "%(name)s", &arg, &err); 1074d0b268fSEric Blake''', 1084d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1094d0b268fSEric Blake else: 1104d0b268fSEric Blake ret += mcgen(''' 11121cd70dfSWenchao Xia 112337283dfSEric Blake visit_start_struct(v, "%(name)s", NULL, 0, &err); 1130949e95bSEric Blake if (err) { 1140949e95bSEric Blake goto out; 1150949e95bSEric Blake } 1160949e95bSEric Blake visit_type_%(c_name)s_members(v, ¶m, &err); 11715c2f669SEric Blake if (!err) { 11815c2f669SEric Blake visit_check_struct(v, &err); 11915c2f669SEric Blake } 1201158bb2aSEric Blake visit_end_struct(v, NULL); 1214d0b268fSEric Blake''', 1224d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1234d0b268fSEric Blake ret += mcgen(''' 1242a0f50e8SEric Blake if (err) { 125f782399cSEric Blake goto out; 12621cd70dfSWenchao Xia } 12721cd70dfSWenchao Xia 1283b098d56SEric Blake visit_complete(v, &obj); 1293b098d56SEric Blake qdict_put_obj(qmp, "data", obj); 1304d0b268fSEric Blake''') 13121cd70dfSWenchao Xia 132e98859a9SMarkus Armbruster ret += mcgen(''' 1332a0f50e8SEric Blake emit(%(c_enum)s, qmp, &err); 13421cd70dfSWenchao Xia 135e98859a9SMarkus Armbruster''', 136e98859a9SMarkus Armbruster c_enum=c_enum_const(event_enum_name, name)) 13721cd70dfSWenchao Xia 138b6167706SEric Blake if arg_type and not arg_type.is_empty(): 139e98859a9SMarkus Armbruster ret += mcgen(''' 140f782399cSEric Blakeout: 1412c0ef9f4SEric Blake visit_free(v); 142e98859a9SMarkus Armbruster''') 143e98859a9SMarkus Armbruster ret += mcgen(''' 1442a0f50e8SEric Blake error_propagate(errp, err); 145cb3e7f08SMarc-André Lureau qobject_unref(qmp); 14621cd70dfSWenchao Xia} 147e98859a9SMarkus Armbruster''') 14821cd70dfSWenchao Xia return ret 14921cd70dfSWenchao Xia 15005f43a96SMarkus Armbruster 151252dc310SMarkus Armbrusterclass QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): 15271b3f045SMarkus Armbruster 15393b564c4SMarkus Armbruster def __init__(self, prefix): 154252dc310SMarkus Armbruster QAPISchemaModularCVisitor.__init__( 155252dc310SMarkus Armbruster self, prefix, 'qapi-events', 15671b3f045SMarkus Armbruster ' * Schema-defined QAPI/QMP events', __doc__) 15793b564c4SMarkus Armbruster self._enum_name = c_name(prefix + 'QAPIEvent', protect=False) 15805f43a96SMarkus Armbruster self._event_names = [] 159252dc310SMarkus Armbruster 160252dc310SMarkus Armbruster def _begin_module(self, name): 1619af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 1629af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 16371b3f045SMarkus Armbruster self._genc.add(mcgen(''' 1649167ebd9SEric Blake#include "qemu/osdep.h" 16521cd70dfSWenchao Xia#include "qemu-common.h" 166eb815e24SMarkus Armbruster#include "%(prefix)sqapi-events.h" 1679af23989SMarkus Armbruster#include "%(visit)s.h" 168e688df6bSMarkus Armbruster#include "qapi/error.h" 169452fcdbcSMarkus Armbruster#include "qapi/qmp/qdict.h" 170b3db211fSDaniel P. Berrange#include "qapi/qobject-output-visitor.h" 17121cd70dfSWenchao Xia#include "qapi/qmp-event.h" 17221cd70dfSWenchao Xia 17321cd70dfSWenchao Xia''', 1749af23989SMarkus Armbruster visit=visit, prefix=self._prefix)) 17571b3f045SMarkus Armbruster self._genh.add(mcgen(''' 1765b5f825dSMarkus Armbruster#include "qapi/util.h" 1779af23989SMarkus Armbruster#include "%(types)s.h" 17821cd70dfSWenchao Xia 17921cd70dfSWenchao Xia''', 1809af23989SMarkus Armbruster types=types)) 18121cd70dfSWenchao Xia 18271b3f045SMarkus Armbruster def visit_end(self): 183*f030ffd3SMarc-André Lureau (genc, genh) = self._module[self._main_module] 184*f030ffd3SMarc-André Lureau genh.add(gen_enum(self._enum_name, self._event_names)) 185*f030ffd3SMarc-André Lureau genc.add(gen_enum_lookup(self._enum_name, self._event_names)) 18671b3f045SMarkus Armbruster 18771b3f045SMarkus Armbruster def visit_event(self, name, info, arg_type, boxed): 18871b3f045SMarkus Armbruster self._genh.add(gen_event_send_decl(name, arg_type, boxed)) 18971b3f045SMarkus Armbruster self._genc.add(gen_event_send(name, arg_type, boxed, self._enum_name)) 19071b3f045SMarkus Armbruster self._event_names.append(name) 19171b3f045SMarkus Armbruster 19271b3f045SMarkus Armbruster 19371b3f045SMarkus Armbrusterdef gen_events(schema, output_dir, prefix): 19493b564c4SMarkus Armbruster vis = QAPISchemaGenEventVisitor(prefix) 195d46eec42SMarkus Armbruster schema.visit(vis) 19671b3f045SMarkus Armbruster vis.write(output_dir) 197