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 152184bca7SJohn Snowfrom typing import List, Optional, Sequence 16d1b21b39SJohn Snow 17e6a34cd7SJohn Snowfrom .common import c_enum_const, c_name, mcgen 18e6a34cd7SJohn Snowfrom .gen import QAPISchemaModularCVisitor, build_params, ifcontext 19d1b21b39SJohn Snowfrom .schema import ( 20d1b21b39SJohn Snow QAPISchema, 21d1b21b39SJohn Snow QAPISchemaEnumMember, 22d1b21b39SJohn Snow QAPISchemaFeature, 23d1b21b39SJohn Snow QAPISchemaObjectType, 24d1b21b39SJohn Snow) 25d1b21b39SJohn Snowfrom .source import QAPISourceInfo 267137a960SJohn Snowfrom .types import gen_enum, gen_enum_lookup 2721cd70dfSWenchao Xia 28e98859a9SMarkus Armbruster 29d1b21b39SJohn Snowdef build_event_send_proto(name: str, 303cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 31d1b21b39SJohn Snow boxed: bool) -> str: 3203b4367aSMarkus Armbruster return 'void qapi_event_send_%(c_name)s(%(param)s)' % { 3303b4367aSMarkus Armbruster 'c_name': c_name(name.lower()), 343ab72385SPeter Xu 'param': build_params(arg_type, boxed)} 3521cd70dfSWenchao Xia 3621cd70dfSWenchao Xia 37d1b21b39SJohn Snowdef gen_event_send_decl(name: str, 383cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 39d1b21b39SJohn Snow boxed: bool) -> str: 4021cd70dfSWenchao Xia return mcgen(''' 4121cd70dfSWenchao Xia 42e98859a9SMarkus Armbruster%(proto)s; 4321cd70dfSWenchao Xia''', 44086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 4521cd70dfSWenchao Xia 4621cd70dfSWenchao Xia 47d1b21b39SJohn Snowdef gen_param_var(typ: QAPISchemaObjectType) -> str: 481a503761SJohn Snow """ 491a503761SJohn Snow Generate a struct variable holding the event parameters. 501a503761SJohn Snow 511a503761SJohn Snow Initialize it with the function arguments defined in `gen_event_send`. 521a503761SJohn Snow """ 530949e95bSEric Blake assert not typ.variants 540949e95bSEric Blake ret = mcgen(''' 550949e95bSEric Blake %(c_name)s param = { 560949e95bSEric Blake''', 570949e95bSEric Blake c_name=typ.c_name()) 580949e95bSEric Blake sep = ' ' 590949e95bSEric Blake for memb in typ.members: 600949e95bSEric Blake ret += sep 610949e95bSEric Blake sep = ', ' 620949e95bSEric Blake if memb.optional: 630949e95bSEric Blake ret += 'has_' + c_name(memb.name) + sep 640949e95bSEric Blake if memb.type.name == 'str': 65086ee7a6SMarc-André Lureau # Cast away const added in build_params() 660949e95bSEric Blake ret += '(char *)' 670949e95bSEric Blake ret += c_name(memb.name) 680949e95bSEric Blake ret += mcgen(''' 690949e95bSEric Blake 700949e95bSEric Blake }; 710949e95bSEric Blake''') 724d0b268fSEric Blake if not typ.is_implicit(): 734d0b268fSEric Blake ret += mcgen(''' 744d0b268fSEric Blake %(c_name)s *arg = ¶m; 754d0b268fSEric Blake''', 764d0b268fSEric Blake c_name=typ.c_name()) 770949e95bSEric Blake return ret 780949e95bSEric Blake 790949e95bSEric Blake 80d1b21b39SJohn Snowdef gen_event_send(name: str, 813cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 82*278fc2f7SMarkus Armbruster features: List[QAPISchemaFeature], 83d1b21b39SJohn Snow boxed: bool, 84d1b21b39SJohn Snow event_enum_name: str, 85d1b21b39SJohn Snow event_emit: str) -> str: 860949e95bSEric Blake # FIXME: Our declaration of local variables (and of 'errp' in the 870949e95bSEric Blake # parameter list) can collide with exploded members of the event's 880949e95bSEric Blake # data type passed in as parameters. If this collision ever hits in 890949e95bSEric Blake # practice, we can rename our local variables with a leading _ prefix, 900949e95bSEric Blake # or split the code into a wrapper function that creates a boxed 910949e95bSEric Blake # 'param' object then calls another to do the real work. 92675b214bSMarkus Armbruster have_args = boxed or (arg_type and not arg_type.is_empty()) 93675b214bSMarkus Armbruster 94e98859a9SMarkus Armbruster ret = mcgen(''' 95e98859a9SMarkus Armbruster 96e98859a9SMarkus Armbruster%(proto)s 9721cd70dfSWenchao Xia{ 9821cd70dfSWenchao Xia QDict *qmp; 99e98859a9SMarkus Armbruster''', 100086ee7a6SMarc-André Lureau proto=build_event_send_proto(name, arg_type, boxed)) 10121cd70dfSWenchao Xia 102675b214bSMarkus Armbruster if have_args: 1033cc01c54SJohn Snow assert arg_type is not None 104e98859a9SMarkus Armbruster ret += mcgen(''' 1053b098d56SEric Blake QObject *obj; 10621cd70dfSWenchao Xia Visitor *v; 107e98859a9SMarkus Armbruster''') 108c818408eSEric Blake if not boxed: 1090949e95bSEric Blake ret += gen_param_var(arg_type) 11021cd70dfSWenchao Xia 111*278fc2f7SMarkus Armbruster if 'deprecated' in [f.name for f in features]: 112*278fc2f7SMarkus Armbruster ret += mcgen(''' 113*278fc2f7SMarkus Armbruster 114*278fc2f7SMarkus Armbruster if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) { 115*278fc2f7SMarkus Armbruster return; 116*278fc2f7SMarkus Armbruster } 117*278fc2f7SMarkus Armbruster''') 118*278fc2f7SMarkus Armbruster 119e98859a9SMarkus Armbruster ret += mcgen(''' 1200949e95bSEric Blake 121e98859a9SMarkus Armbruster qmp = qmp_event_build_dict("%(name)s"); 12221cd70dfSWenchao Xia 123e98859a9SMarkus Armbruster''', 124e98859a9SMarkus Armbruster name=name) 12521cd70dfSWenchao Xia 126675b214bSMarkus Armbruster if have_args: 1273cc01c54SJohn Snow assert arg_type is not None 128e98859a9SMarkus Armbruster ret += mcgen(''' 1297d5e199aSDaniel P. Berrange v = qobject_output_visitor_new(&obj); 1304d0b268fSEric Blake''') 1314d0b268fSEric Blake if not arg_type.is_implicit(): 1324d0b268fSEric Blake ret += mcgen(''' 1333ab72385SPeter Xu visit_type_%(c_name)s(v, "%(name)s", &arg, &error_abort); 1344d0b268fSEric Blake''', 1354d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1364d0b268fSEric Blake else: 1374d0b268fSEric Blake ret += mcgen(''' 13821cd70dfSWenchao Xia 1393ab72385SPeter Xu visit_start_struct(v, "%(name)s", NULL, 0, &error_abort); 1403ab72385SPeter Xu visit_type_%(c_name)s_members(v, ¶m, &error_abort); 1413ab72385SPeter Xu visit_check_struct(v, &error_abort); 1421158bb2aSEric Blake visit_end_struct(v, NULL); 1434d0b268fSEric Blake''', 1444d0b268fSEric Blake name=name, c_name=arg_type.c_name()) 1454d0b268fSEric Blake ret += mcgen(''' 14621cd70dfSWenchao Xia 1473b098d56SEric Blake visit_complete(v, &obj); 1483b098d56SEric Blake qdict_put_obj(qmp, "data", obj); 1494d0b268fSEric Blake''') 15021cd70dfSWenchao Xia 151e98859a9SMarkus Armbruster ret += mcgen(''' 152a9529100SMarkus Armbruster %(event_emit)s(%(c_enum)s, qmp); 15321cd70dfSWenchao Xia 154e98859a9SMarkus Armbruster''', 155a9529100SMarkus Armbruster event_emit=event_emit, 156e98859a9SMarkus Armbruster c_enum=c_enum_const(event_enum_name, name)) 15721cd70dfSWenchao Xia 158675b214bSMarkus Armbruster if have_args: 159e98859a9SMarkus Armbruster ret += mcgen(''' 1602c0ef9f4SEric Blake visit_free(v); 161e98859a9SMarkus Armbruster''') 162e98859a9SMarkus Armbruster ret += mcgen(''' 163cb3e7f08SMarc-André Lureau qobject_unref(qmp); 16421cd70dfSWenchao Xia} 165e98859a9SMarkus Armbruster''') 16621cd70dfSWenchao Xia return ret 16721cd70dfSWenchao Xia 16805f43a96SMarkus Armbruster 169252dc310SMarkus Armbrusterclass QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): 17071b3f045SMarkus Armbruster 171d1b21b39SJohn Snow def __init__(self, prefix: str): 1722cae67bcSMarkus Armbruster super().__init__( 1732cae67bcSMarkus Armbruster prefix, 'qapi-events', 1743bef3aaeSMarkus Armbruster ' * Schema-defined QAPI/QMP events', None, __doc__) 1751962bd39SMarc-André Lureau self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False) 176d1b21b39SJohn Snow self._event_enum_members: List[QAPISchemaEnumMember] = [] 177a9529100SMarkus Armbruster self._event_emit_name = c_name(prefix + 'qapi_event_emit') 178252dc310SMarkus Armbruster 179d1b21b39SJohn Snow def _begin_user_module(self, name: str) -> None: 1805d75648bSMarkus Armbruster events = self._module_basename('qapi-events', name) 1819af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 1829af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 18371b3f045SMarkus Armbruster self._genc.add(mcgen(''' 1849167ebd9SEric Blake#include "qemu/osdep.h" 1855d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 1865d75648bSMarkus Armbruster#include "%(events)s.h" 1879af23989SMarkus Armbruster#include "%(visit)s.h" 188*278fc2f7SMarkus Armbruster#include "qapi/compat-policy.h" 189e688df6bSMarkus Armbruster#include "qapi/error.h" 190452fcdbcSMarkus Armbruster#include "qapi/qmp/qdict.h" 191b3db211fSDaniel P. Berrange#include "qapi/qobject-output-visitor.h" 19221cd70dfSWenchao Xia#include "qapi/qmp-event.h" 19321cd70dfSWenchao Xia 19421cd70dfSWenchao Xia''', 1955d75648bSMarkus Armbruster events=events, visit=visit, 1965d75648bSMarkus Armbruster prefix=self._prefix)) 19771b3f045SMarkus Armbruster self._genh.add(mcgen(''' 1985b5f825dSMarkus Armbruster#include "qapi/util.h" 1999af23989SMarkus Armbruster#include "%(types)s.h" 20021cd70dfSWenchao Xia''', 2019af23989SMarkus Armbruster types=types)) 20221cd70dfSWenchao Xia 203d1b21b39SJohn Snow def visit_end(self) -> None: 2044ab0ff6dSMarkus Armbruster self._add_module('./emit', ' * QAPI Events emission') 2055d75648bSMarkus Armbruster self._genc.preamble_add(mcgen(''' 2065d75648bSMarkus Armbruster#include "qemu/osdep.h" 2075d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 2085d75648bSMarkus Armbruster''', 2095d75648bSMarkus Armbruster prefix=self._prefix)) 2105d75648bSMarkus Armbruster self._genh.preamble_add(mcgen(''' 2115d75648bSMarkus Armbruster#include "qapi/util.h" 2125d75648bSMarkus Armbruster''')) 2135d75648bSMarkus Armbruster self._genh.add(gen_enum(self._event_enum_name, 214a9529100SMarkus Armbruster self._event_enum_members)) 2155d75648bSMarkus Armbruster self._genc.add(gen_enum_lookup(self._event_enum_name, 2161962bd39SMarc-André Lureau self._event_enum_members)) 2175d75648bSMarkus Armbruster self._genh.add(mcgen(''' 218a9529100SMarkus Armbruster 219a9529100SMarkus Armbrustervoid %(event_emit)s(%(event_enum)s event, QDict *qdict); 220a9529100SMarkus Armbruster''', 221a9529100SMarkus Armbruster event_emit=self._event_emit_name, 222a9529100SMarkus Armbruster event_enum=self._event_enum_name)) 22371b3f045SMarkus Armbruster 224d1b21b39SJohn Snow def visit_event(self, 225d1b21b39SJohn Snow name: str, 2264a82e468SJohn Snow info: Optional[QAPISourceInfo], 2272184bca7SJohn Snow ifcond: Sequence[str], 228d1b21b39SJohn Snow features: List[QAPISchemaFeature], 2293cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 230d1b21b39SJohn Snow boxed: bool) -> None: 231c3cd6aa0SMarc-André Lureau with ifcontext(ifcond, self._genh, self._genc): 23271b3f045SMarkus Armbruster self._genh.add(gen_event_send_decl(name, arg_type, boxed)) 233*278fc2f7SMarkus Armbruster self._genc.add(gen_event_send(name, arg_type, features, boxed, 234a9529100SMarkus Armbruster self._event_enum_name, 235a9529100SMarkus Armbruster self._event_emit_name)) 236093e3679SMarkus Armbruster # Note: we generate the enum member regardless of @ifcond, to 237093e3679SMarkus Armbruster # keep the enumeration usable in target-independent code. 238e6f9678dSMarkus Armbruster self._event_enum_members.append(QAPISchemaEnumMember(name, None)) 23971b3f045SMarkus Armbruster 24071b3f045SMarkus Armbruster 241d1b21b39SJohn Snowdef gen_events(schema: QAPISchema, 242d1b21b39SJohn Snow output_dir: str, 243d1b21b39SJohn Snow prefix: str) -> None: 24493b564c4SMarkus Armbruster vis = QAPISchemaGenEventVisitor(prefix) 245d46eec42SMarkus Armbruster schema.visit(vis) 24671b3f045SMarkus Armbruster vis.write(output_dir) 247