qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

events.py (7572B)


      1 """
      2 QAPI event generator
      3 
      4 Copyright (c) 2014 Wenchao Xia
      5 Copyright (c) 2015-2018 Red Hat Inc.
      6 
      7 Authors:
      8  Wenchao Xia <wenchaoqemu@gmail.com>
      9  Markus Armbruster <armbru@redhat.com>
     10 
     11 This work is licensed under the terms of the GNU GPL, version 2.
     12 See the COPYING file in the top-level directory.
     13 """
     14 
     15 from typing import List, Optional
     16 
     17 from .common import c_enum_const, c_name, mcgen
     18 from .gen import QAPISchemaModularCVisitor, build_params, ifcontext
     19 from .schema import (
     20     QAPISchema,
     21     QAPISchemaEnumMember,
     22     QAPISchemaFeature,
     23     QAPISchemaIfCond,
     24     QAPISchemaObjectType,
     25 )
     26 from .source import QAPISourceInfo
     27 from .types import gen_enum, gen_enum_lookup
     28 
     29 
     30 def build_event_send_proto(name: str,
     31                            arg_type: Optional[QAPISchemaObjectType],
     32                            boxed: bool) -> str:
     33     return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
     34         'c_name': c_name(name.lower()),
     35         'param': build_params(arg_type, boxed)}
     36 
     37 
     38 def gen_event_send_decl(name: str,
     39                         arg_type: Optional[QAPISchemaObjectType],
     40                         boxed: bool) -> str:
     41     return mcgen('''
     42 
     43 %(proto)s;
     44 ''',
     45                  proto=build_event_send_proto(name, arg_type, boxed))
     46 
     47 
     48 def gen_param_var(typ: QAPISchemaObjectType) -> str:
     49     """
     50     Generate a struct variable holding the event parameters.
     51 
     52     Initialize it with the function arguments defined in `gen_event_send`.
     53     """
     54     assert not typ.variants
     55     ret = mcgen('''
     56     %(c_name)s param = {
     57 ''',
     58                 c_name=typ.c_name())
     59     sep = '        '
     60     for memb in typ.members:
     61         ret += sep
     62         sep = ', '
     63         if memb.optional:
     64             ret += 'has_' + c_name(memb.name) + sep
     65         if memb.type.name == 'str':
     66             # Cast away const added in build_params()
     67             ret += '(char *)'
     68         ret += c_name(memb.name)
     69     ret += mcgen('''
     70 
     71     };
     72 ''')
     73     if not typ.is_implicit():
     74         ret += mcgen('''
     75     %(c_name)s *arg = &param;
     76 ''',
     77                      c_name=typ.c_name())
     78     return ret
     79 
     80 
     81 def gen_event_send(name: str,
     82                    arg_type: Optional[QAPISchemaObjectType],
     83                    features: List[QAPISchemaFeature],
     84                    boxed: bool,
     85                    event_enum_name: str,
     86                    event_emit: str) -> str:
     87     # FIXME: Our declaration of local variables (and of 'errp' in the
     88     # parameter list) can collide with exploded members of the event's
     89     # data type passed in as parameters.  If this collision ever hits in
     90     # practice, we can rename our local variables with a leading _ prefix,
     91     # or split the code into a wrapper function that creates a boxed
     92     # 'param' object then calls another to do the real work.
     93     have_args = boxed or (arg_type and not arg_type.is_empty())
     94 
     95     ret = mcgen('''
     96 
     97 %(proto)s
     98 {
     99     QDict *qmp;
    100 ''',
    101                 proto=build_event_send_proto(name, arg_type, boxed))
    102 
    103     if have_args:
    104         assert arg_type is not None
    105         ret += mcgen('''
    106     QObject *obj;
    107     Visitor *v;
    108 ''')
    109         if not boxed:
    110             ret += gen_param_var(arg_type)
    111 
    112     for f in features:
    113         if f.is_special():
    114             ret += mcgen('''
    115 
    116     if (compat_policy.%(feat)s_output == COMPAT_POLICY_OUTPUT_HIDE) {
    117         return;
    118     }
    119 ''',
    120                          feat=f.name)
    121 
    122     ret += mcgen('''
    123 
    124     qmp = qmp_event_build_dict("%(name)s");
    125 
    126 ''',
    127                  name=name)
    128 
    129     if have_args:
    130         assert arg_type is not None
    131         ret += mcgen('''
    132     v = qobject_output_visitor_new_qmp(&obj);
    133 ''')
    134         if not arg_type.is_implicit():
    135             ret += mcgen('''
    136     visit_type_%(c_name)s(v, "%(name)s", &arg, &error_abort);
    137 ''',
    138                          name=name, c_name=arg_type.c_name())
    139         else:
    140             ret += mcgen('''
    141 
    142     visit_start_struct(v, "%(name)s", NULL, 0, &error_abort);
    143     visit_type_%(c_name)s_members(v, &param, &error_abort);
    144     visit_check_struct(v, &error_abort);
    145     visit_end_struct(v, NULL);
    146 ''',
    147                          name=name, c_name=arg_type.c_name())
    148         ret += mcgen('''
    149 
    150     visit_complete(v, &obj);
    151     if (qdict_size(qobject_to(QDict, obj))) {
    152         qdict_put_obj(qmp, "data", obj);
    153     } else {
    154         qobject_unref(obj);
    155     }
    156 ''')
    157 
    158     ret += mcgen('''
    159     %(event_emit)s(%(c_enum)s, qmp);
    160 
    161 ''',
    162                  event_emit=event_emit,
    163                  c_enum=c_enum_const(event_enum_name, name))
    164 
    165     if have_args:
    166         ret += mcgen('''
    167     visit_free(v);
    168 ''')
    169     ret += mcgen('''
    170     qobject_unref(qmp);
    171 }
    172 ''')
    173     return ret
    174 
    175 
    176 class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
    177 
    178     def __init__(self, prefix: str):
    179         super().__init__(
    180             prefix, 'qapi-events',
    181             ' * Schema-defined QAPI/QMP events', None, __doc__)
    182         self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
    183         self._event_enum_members: List[QAPISchemaEnumMember] = []
    184         self._event_emit_name = c_name(prefix + 'qapi_event_emit')
    185 
    186     def _begin_user_module(self, name: str) -> None:
    187         events = self._module_basename('qapi-events', name)
    188         types = self._module_basename('qapi-types', name)
    189         visit = self._module_basename('qapi-visit', name)
    190         self._genc.add(mcgen('''
    191 #include "qemu/osdep.h"
    192 #include "%(prefix)sqapi-emit-events.h"
    193 #include "%(events)s.h"
    194 #include "%(visit)s.h"
    195 #include "qapi/compat-policy.h"
    196 #include "qapi/error.h"
    197 #include "qapi/qmp/qdict.h"
    198 #include "qapi/qmp-event.h"
    199 
    200 ''',
    201                              events=events, visit=visit,
    202                              prefix=self._prefix))
    203         self._genh.add(mcgen('''
    204 #include "qapi/util.h"
    205 #include "%(types)s.h"
    206 ''',
    207                              types=types))
    208 
    209     def visit_end(self) -> None:
    210         self._add_module('./emit', ' * QAPI Events emission')
    211         self._genc.preamble_add(mcgen('''
    212 #include "qemu/osdep.h"
    213 #include "%(prefix)sqapi-emit-events.h"
    214 ''',
    215                                       prefix=self._prefix))
    216         self._genh.preamble_add(mcgen('''
    217 #include "qapi/util.h"
    218 '''))
    219         self._genh.add(gen_enum(self._event_enum_name,
    220                                 self._event_enum_members))
    221         self._genc.add(gen_enum_lookup(self._event_enum_name,
    222                                        self._event_enum_members))
    223         self._genh.add(mcgen('''
    224 
    225 void %(event_emit)s(%(event_enum)s event, QDict *qdict);
    226 ''',
    227                              event_emit=self._event_emit_name,
    228                              event_enum=self._event_enum_name))
    229 
    230     def visit_event(self,
    231                     name: str,
    232                     info: Optional[QAPISourceInfo],
    233                     ifcond: QAPISchemaIfCond,
    234                     features: List[QAPISchemaFeature],
    235                     arg_type: Optional[QAPISchemaObjectType],
    236                     boxed: bool) -> None:
    237         with ifcontext(ifcond, self._genh, self._genc):
    238             self._genh.add(gen_event_send_decl(name, arg_type, boxed))
    239             self._genc.add(gen_event_send(name, arg_type, features, boxed,
    240                                           self._event_enum_name,
    241                                           self._event_emit_name))
    242         # Note: we generate the enum member regardless of @ifcond, to
    243         # keep the enumeration usable in target-independent code.
    244         self._event_enum_members.append(QAPISchemaEnumMember(name, None))
    245 
    246 
    247 def gen_events(schema: QAPISchema,
    248                output_dir: str,
    249                prefix: str) -> None:
    250     vis = QAPISchemaGenEventVisitor(prefix)
    251     schema.visit(vis)
    252     vis.write(output_dir)