1fb0bc835SMarkus Armbruster""" 2fb0bc835SMarkus ArmbrusterQAPI event generator 3fb0bc835SMarkus Armbruster 4fb0bc835SMarkus ArmbrusterCopyright (c) 2014 Wenchao Xia 5fb0bc835SMarkus ArmbrusterCopyright (c) 2015-2018 Red Hat Inc. 6fb0bc835SMarkus Armbruster 7fb0bc835SMarkus ArmbrusterAuthors: 8fb0bc835SMarkus Armbruster Wenchao Xia <wenchaoqemu@gmail.com> 9fb0bc835SMarkus Armbruster Markus Armbruster <armbru@redhat.com> 10fb0bc835SMarkus Armbruster 11fb0bc835SMarkus ArmbrusterThis work is licensed under the terms of the GNU GPL, version 2. 12fb0bc835SMarkus ArmbrusterSee the COPYING file in the top-level directory. 13fb0bc835SMarkus Armbruster""" 14fb0bc835SMarkus Armbruster 15f17539c8SMarc-André Lureaufrom typing import List, Optional 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, 23f17539c8SMarc-André Lureau QAPISchemaIfCond, 24d1b21b39SJohn Snow QAPISchemaObjectType, 25d1b21b39SJohn Snow) 26d1b21b39SJohn Snowfrom .source import QAPISourceInfo 277137a960SJohn Snowfrom .types import gen_enum, gen_enum_lookup 28fb0bc835SMarkus Armbruster 29fb0bc835SMarkus Armbruster 30d1b21b39SJohn Snowdef build_event_send_proto(name: str, 313cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 32d1b21b39SJohn Snow boxed: bool) -> str: 33fb0bc835SMarkus Armbruster return 'void qapi_event_send_%(c_name)s(%(param)s)' % { 34fb0bc835SMarkus Armbruster 'c_name': c_name(name.lower()), 353ab72385SPeter Xu 'param': build_params(arg_type, boxed)} 36fb0bc835SMarkus Armbruster 37fb0bc835SMarkus Armbruster 38d1b21b39SJohn Snowdef gen_event_send_decl(name: str, 393cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 40d1b21b39SJohn Snow boxed: bool) -> str: 41fb0bc835SMarkus Armbruster return mcgen(''' 42fb0bc835SMarkus Armbruster 43fb0bc835SMarkus Armbruster%(proto)s; 44fb0bc835SMarkus Armbruster''', 45fb0bc835SMarkus Armbruster proto=build_event_send_proto(name, arg_type, boxed)) 46fb0bc835SMarkus Armbruster 47fb0bc835SMarkus Armbruster 48d1b21b39SJohn Snowdef gen_param_var(typ: QAPISchemaObjectType) -> str: 491a503761SJohn Snow """ 501a503761SJohn Snow Generate a struct variable holding the event parameters. 511a503761SJohn Snow 521a503761SJohn Snow Initialize it with the function arguments defined in `gen_event_send`. 531a503761SJohn Snow """ 54*3ff2a5a3SMarkus Armbruster assert not typ.branches 55fb0bc835SMarkus Armbruster ret = mcgen(''' 56fb0bc835SMarkus Armbruster %(c_name)s param = { 57fb0bc835SMarkus Armbruster''', 58fb0bc835SMarkus Armbruster c_name=typ.c_name()) 59fb0bc835SMarkus Armbruster sep = ' ' 60fb0bc835SMarkus Armbruster for memb in typ.members: 61fb0bc835SMarkus Armbruster ret += sep 62fb0bc835SMarkus Armbruster sep = ', ' 6344ea9d9bSMarkus Armbruster if memb.need_has(): 64fb0bc835SMarkus Armbruster ret += 'has_' + c_name(memb.name) + sep 65fb0bc835SMarkus Armbruster if memb.type.name == 'str': 66fb0bc835SMarkus Armbruster # Cast away const added in build_params() 67fb0bc835SMarkus Armbruster ret += '(char *)' 68fb0bc835SMarkus Armbruster ret += c_name(memb.name) 69fb0bc835SMarkus Armbruster ret += mcgen(''' 70fb0bc835SMarkus Armbruster 71fb0bc835SMarkus Armbruster }; 72fb0bc835SMarkus Armbruster''') 73fb0bc835SMarkus Armbruster if not typ.is_implicit(): 74fb0bc835SMarkus Armbruster ret += mcgen(''' 75fb0bc835SMarkus Armbruster %(c_name)s *arg = ¶m; 76fb0bc835SMarkus Armbruster''', 77fb0bc835SMarkus Armbruster c_name=typ.c_name()) 78fb0bc835SMarkus Armbruster return ret 79fb0bc835SMarkus Armbruster 80fb0bc835SMarkus Armbruster 81d1b21b39SJohn Snowdef gen_event_send(name: str, 823cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 83278fc2f7SMarkus Armbruster features: List[QAPISchemaFeature], 84d1b21b39SJohn Snow boxed: bool, 85d1b21b39SJohn Snow event_enum_name: str, 86d1b21b39SJohn Snow event_emit: str) -> str: 87fb0bc835SMarkus Armbruster # FIXME: Our declaration of local variables (and of 'errp' in the 88fb0bc835SMarkus Armbruster # parameter list) can collide with exploded members of the event's 89fb0bc835SMarkus Armbruster # data type passed in as parameters. If this collision ever hits in 90fb0bc835SMarkus Armbruster # practice, we can rename our local variables with a leading _ prefix, 91fb0bc835SMarkus Armbruster # or split the code into a wrapper function that creates a boxed 92fb0bc835SMarkus Armbruster # 'param' object then calls another to do the real work. 93675b214bSMarkus Armbruster have_args = boxed or (arg_type and not arg_type.is_empty()) 94675b214bSMarkus Armbruster 95fb0bc835SMarkus Armbruster ret = mcgen(''' 96fb0bc835SMarkus Armbruster 97fb0bc835SMarkus Armbruster%(proto)s 98fb0bc835SMarkus Armbruster{ 99fb0bc835SMarkus Armbruster QDict *qmp; 100fb0bc835SMarkus Armbruster''', 101fb0bc835SMarkus Armbruster proto=build_event_send_proto(name, arg_type, boxed)) 102fb0bc835SMarkus Armbruster 103675b214bSMarkus Armbruster if have_args: 1043cc01c54SJohn Snow assert arg_type is not None 105fb0bc835SMarkus Armbruster ret += mcgen(''' 106fb0bc835SMarkus Armbruster QObject *obj; 107fb0bc835SMarkus Armbruster Visitor *v; 108fb0bc835SMarkus Armbruster''') 109fb0bc835SMarkus Armbruster if not boxed: 110fb0bc835SMarkus Armbruster ret += gen_param_var(arg_type) 111fb0bc835SMarkus Armbruster 11257df0dffSMarkus Armbruster for f in features: 11357df0dffSMarkus Armbruster if f.is_special(): 114278fc2f7SMarkus Armbruster ret += mcgen(''' 115278fc2f7SMarkus Armbruster 11657df0dffSMarkus Armbruster if (compat_policy.%(feat)s_output == COMPAT_POLICY_OUTPUT_HIDE) { 117278fc2f7SMarkus Armbruster return; 118278fc2f7SMarkus Armbruster } 11957df0dffSMarkus Armbruster''', 12057df0dffSMarkus Armbruster feat=f.name) 121278fc2f7SMarkus Armbruster 122fb0bc835SMarkus Armbruster ret += mcgen(''' 123fb0bc835SMarkus Armbruster 124fb0bc835SMarkus Armbruster qmp = qmp_event_build_dict("%(name)s"); 125fb0bc835SMarkus Armbruster 126fb0bc835SMarkus Armbruster''', 127fb0bc835SMarkus Armbruster name=name) 128fb0bc835SMarkus Armbruster 129675b214bSMarkus Armbruster if have_args: 1303cc01c54SJohn Snow assert arg_type is not None 131fb0bc835SMarkus Armbruster ret += mcgen(''' 132a291a38fSMarkus Armbruster v = qobject_output_visitor_new_qmp(&obj); 133fb0bc835SMarkus Armbruster''') 134fb0bc835SMarkus Armbruster if not arg_type.is_implicit(): 135fb0bc835SMarkus Armbruster ret += mcgen(''' 1363ab72385SPeter Xu visit_type_%(c_name)s(v, "%(name)s", &arg, &error_abort); 137fb0bc835SMarkus Armbruster''', 138fb0bc835SMarkus Armbruster name=name, c_name=arg_type.c_name()) 139fb0bc835SMarkus Armbruster else: 140fb0bc835SMarkus Armbruster ret += mcgen(''' 141fb0bc835SMarkus Armbruster 1423ab72385SPeter Xu visit_start_struct(v, "%(name)s", NULL, 0, &error_abort); 1433ab72385SPeter Xu visit_type_%(c_name)s_members(v, ¶m, &error_abort); 1443ab72385SPeter Xu visit_check_struct(v, &error_abort); 145fb0bc835SMarkus Armbruster visit_end_struct(v, NULL); 146fb0bc835SMarkus Armbruster''', 147fb0bc835SMarkus Armbruster name=name, c_name=arg_type.c_name()) 148fb0bc835SMarkus Armbruster ret += mcgen(''' 149fb0bc835SMarkus Armbruster 150fb0bc835SMarkus Armbruster visit_complete(v, &obj); 151a291a38fSMarkus Armbruster if (qdict_size(qobject_to(QDict, obj))) { 152fb0bc835SMarkus Armbruster qdict_put_obj(qmp, "data", obj); 153a291a38fSMarkus Armbruster } else { 154a291a38fSMarkus Armbruster qobject_unref(obj); 155a291a38fSMarkus Armbruster } 156fb0bc835SMarkus Armbruster''') 157fb0bc835SMarkus Armbruster 158fb0bc835SMarkus Armbruster ret += mcgen(''' 159a9529100SMarkus Armbruster %(event_emit)s(%(c_enum)s, qmp); 160fb0bc835SMarkus Armbruster 161fb0bc835SMarkus Armbruster''', 162a9529100SMarkus Armbruster event_emit=event_emit, 163fb0bc835SMarkus Armbruster c_enum=c_enum_const(event_enum_name, name)) 164fb0bc835SMarkus Armbruster 165675b214bSMarkus Armbruster if have_args: 166fb0bc835SMarkus Armbruster ret += mcgen(''' 167fb0bc835SMarkus Armbruster visit_free(v); 168fb0bc835SMarkus Armbruster''') 169fb0bc835SMarkus Armbruster ret += mcgen(''' 170cb3e7f08SMarc-André Lureau qobject_unref(qmp); 171fb0bc835SMarkus Armbruster} 172fb0bc835SMarkus Armbruster''') 173fb0bc835SMarkus Armbruster return ret 174fb0bc835SMarkus Armbruster 175fb0bc835SMarkus Armbruster 176252dc310SMarkus Armbrusterclass QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor): 17771b3f045SMarkus Armbruster 178d1b21b39SJohn Snow def __init__(self, prefix: str): 1792cae67bcSMarkus Armbruster super().__init__( 1802cae67bcSMarkus Armbruster prefix, 'qapi-events', 1813bef3aaeSMarkus Armbruster ' * Schema-defined QAPI/QMP events', None, __doc__) 1821962bd39SMarc-André Lureau self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False) 183d1b21b39SJohn Snow self._event_enum_members: List[QAPISchemaEnumMember] = [] 184a9529100SMarkus Armbruster self._event_emit_name = c_name(prefix + 'qapi_event_emit') 185252dc310SMarkus Armbruster 186d1b21b39SJohn Snow def _begin_user_module(self, name: str) -> None: 1875d75648bSMarkus Armbruster events = self._module_basename('qapi-events', name) 1889af23989SMarkus Armbruster types = self._module_basename('qapi-types', name) 1899af23989SMarkus Armbruster visit = self._module_basename('qapi-visit', name) 19071b3f045SMarkus Armbruster self._genc.add(mcgen(''' 191fb0bc835SMarkus Armbruster#include "qemu/osdep.h" 1925d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 1935d75648bSMarkus Armbruster#include "%(events)s.h" 1949af23989SMarkus Armbruster#include "%(visit)s.h" 195278fc2f7SMarkus Armbruster#include "qapi/compat-policy.h" 196fb0bc835SMarkus Armbruster#include "qapi/error.h" 197fb0bc835SMarkus Armbruster#include "qapi/qmp/qdict.h" 198fb0bc835SMarkus Armbruster#include "qapi/qmp-event.h" 199fb0bc835SMarkus Armbruster''', 2005d75648bSMarkus Armbruster events=events, visit=visit, 2015d75648bSMarkus Armbruster prefix=self._prefix)) 20271b3f045SMarkus Armbruster self._genh.add(mcgen(''' 203fb0bc835SMarkus Armbruster#include "qapi/util.h" 2049af23989SMarkus Armbruster#include "%(types)s.h" 205fb0bc835SMarkus Armbruster''', 2069af23989SMarkus Armbruster types=types)) 207fb0bc835SMarkus Armbruster 208d1b21b39SJohn Snow def visit_end(self) -> None: 2094ab0ff6dSMarkus Armbruster self._add_module('./emit', ' * QAPI Events emission') 2105d75648bSMarkus Armbruster self._genc.preamble_add(mcgen(''' 2115d75648bSMarkus Armbruster#include "qemu/osdep.h" 2125d75648bSMarkus Armbruster#include "%(prefix)sqapi-emit-events.h" 2135d75648bSMarkus Armbruster''', 2145d75648bSMarkus Armbruster prefix=self._prefix)) 2155d75648bSMarkus Armbruster self._genh.preamble_add(mcgen(''' 2165d75648bSMarkus Armbruster#include "qapi/util.h" 2175d75648bSMarkus Armbruster''')) 2185d75648bSMarkus Armbruster self._genh.add(gen_enum(self._event_enum_name, 219a9529100SMarkus Armbruster self._event_enum_members)) 2205d75648bSMarkus Armbruster self._genc.add(gen_enum_lookup(self._event_enum_name, 2211962bd39SMarc-André Lureau self._event_enum_members)) 2225d75648bSMarkus Armbruster self._genh.add(mcgen(''' 223a9529100SMarkus Armbruster 224a9529100SMarkus Armbrustervoid %(event_emit)s(%(event_enum)s event, QDict *qdict); 225a9529100SMarkus Armbruster''', 226a9529100SMarkus Armbruster event_emit=self._event_emit_name, 227a9529100SMarkus Armbruster event_enum=self._event_enum_name)) 22871b3f045SMarkus Armbruster 229d1b21b39SJohn Snow def visit_event(self, 230d1b21b39SJohn Snow name: str, 2314a82e468SJohn Snow info: Optional[QAPISourceInfo], 232f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 233d1b21b39SJohn Snow features: List[QAPISchemaFeature], 2343cc01c54SJohn Snow arg_type: Optional[QAPISchemaObjectType], 235d1b21b39SJohn Snow boxed: bool) -> None: 236c3cd6aa0SMarc-André Lureau with ifcontext(ifcond, self._genh, self._genc): 23771b3f045SMarkus Armbruster self._genh.add(gen_event_send_decl(name, arg_type, boxed)) 238278fc2f7SMarkus Armbruster self._genc.add(gen_event_send(name, arg_type, features, boxed, 239a9529100SMarkus Armbruster self._event_enum_name, 240a9529100SMarkus Armbruster self._event_emit_name)) 241093e3679SMarkus Armbruster # Note: we generate the enum member regardless of @ifcond, to 242093e3679SMarkus Armbruster # keep the enumeration usable in target-independent code. 243e6f9678dSMarkus Armbruster self._event_enum_members.append(QAPISchemaEnumMember(name, None)) 24471b3f045SMarkus Armbruster 24571b3f045SMarkus Armbruster 246d1b21b39SJohn Snowdef gen_events(schema: QAPISchema, 247d1b21b39SJohn Snow output_dir: str, 248d1b21b39SJohn Snow prefix: str) -> None: 249fb0bc835SMarkus Armbruster vis = QAPISchemaGenEventVisitor(prefix) 250fb0bc835SMarkus Armbruster schema.visit(vis) 25171b3f045SMarkus Armbruster vis.write(output_dir) 252