events.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. """
  2. QAPI event generator
  3. Copyright (c) 2014 Wenchao Xia
  4. Copyright (c) 2015-2018 Red Hat Inc.
  5. Authors:
  6. Wenchao Xia <wenchaoqemu@gmail.com>
  7. Markus Armbruster <armbru@redhat.com>
  8. This work is licensed under the terms of the GNU GPL, version 2.
  9. See the COPYING file in the top-level directory.
  10. """
  11. from qapi.common import *
  12. def build_event_send_proto(name, arg_type, boxed):
  13. return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
  14. 'c_name': c_name(name.lower()),
  15. 'param': build_params(arg_type, boxed)}
  16. def gen_event_send_decl(name, arg_type, boxed):
  17. return mcgen('''
  18. %(proto)s;
  19. ''',
  20. proto=build_event_send_proto(name, arg_type, boxed))
  21. # Declare and initialize an object 'qapi' using parameters from build_params()
  22. def gen_param_var(typ):
  23. assert not typ.variants
  24. ret = mcgen('''
  25. %(c_name)s param = {
  26. ''',
  27. c_name=typ.c_name())
  28. sep = ' '
  29. for memb in typ.members:
  30. ret += sep
  31. sep = ', '
  32. if memb.optional:
  33. ret += 'has_' + c_name(memb.name) + sep
  34. if memb.type.name == 'str':
  35. # Cast away const added in build_params()
  36. ret += '(char *)'
  37. ret += c_name(memb.name)
  38. ret += mcgen('''
  39. };
  40. ''')
  41. if not typ.is_implicit():
  42. ret += mcgen('''
  43. %(c_name)s *arg = &param;
  44. ''',
  45. c_name=typ.c_name())
  46. return ret
  47. def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit):
  48. # FIXME: Our declaration of local variables (and of 'errp' in the
  49. # parameter list) can collide with exploded members of the event's
  50. # data type passed in as parameters. If this collision ever hits in
  51. # practice, we can rename our local variables with a leading _ prefix,
  52. # or split the code into a wrapper function that creates a boxed
  53. # 'param' object then calls another to do the real work.
  54. ret = mcgen('''
  55. %(proto)s
  56. {
  57. QDict *qmp;
  58. ''',
  59. proto=build_event_send_proto(name, arg_type, boxed))
  60. if arg_type and not arg_type.is_empty():
  61. ret += mcgen('''
  62. QObject *obj;
  63. Visitor *v;
  64. ''')
  65. if not boxed:
  66. ret += gen_param_var(arg_type)
  67. else:
  68. assert not boxed
  69. ret += mcgen('''
  70. qmp = qmp_event_build_dict("%(name)s");
  71. ''',
  72. name=name)
  73. if arg_type and not arg_type.is_empty():
  74. ret += mcgen('''
  75. v = qobject_output_visitor_new(&obj);
  76. ''')
  77. if not arg_type.is_implicit():
  78. ret += mcgen('''
  79. visit_type_%(c_name)s(v, "%(name)s", &arg, &error_abort);
  80. ''',
  81. name=name, c_name=arg_type.c_name())
  82. else:
  83. ret += mcgen('''
  84. visit_start_struct(v, "%(name)s", NULL, 0, &error_abort);
  85. visit_type_%(c_name)s_members(v, &param, &error_abort);
  86. visit_check_struct(v, &error_abort);
  87. visit_end_struct(v, NULL);
  88. ''',
  89. name=name, c_name=arg_type.c_name())
  90. ret += mcgen('''
  91. visit_complete(v, &obj);
  92. qdict_put_obj(qmp, "data", obj);
  93. ''')
  94. ret += mcgen('''
  95. %(event_emit)s(%(c_enum)s, qmp);
  96. ''',
  97. event_emit=event_emit,
  98. c_enum=c_enum_const(event_enum_name, name))
  99. if arg_type and not arg_type.is_empty():
  100. ret += mcgen('''
  101. visit_free(v);
  102. ''')
  103. ret += mcgen('''
  104. qobject_unref(qmp);
  105. }
  106. ''')
  107. return ret
  108. class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
  109. def __init__(self, prefix):
  110. QAPISchemaModularCVisitor.__init__(
  111. self, prefix, 'qapi-events',
  112. ' * Schema-defined QAPI/QMP events', __doc__)
  113. self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
  114. self._event_enum_members = []
  115. self._event_emit_name = c_name(prefix + 'qapi_event_emit')
  116. def _begin_module(self, name):
  117. types = self._module_basename('qapi-types', name)
  118. visit = self._module_basename('qapi-visit', name)
  119. self._genc.add(mcgen('''
  120. #include "qemu/osdep.h"
  121. #include "qemu-common.h"
  122. #include "%(prefix)sqapi-events.h"
  123. #include "%(visit)s.h"
  124. #include "qapi/error.h"
  125. #include "qapi/qmp/qdict.h"
  126. #include "qapi/qobject-output-visitor.h"
  127. #include "qapi/qmp-event.h"
  128. ''',
  129. visit=visit, prefix=self._prefix))
  130. self._genh.add(mcgen('''
  131. #include "qapi/util.h"
  132. #include "%(types)s.h"
  133. ''',
  134. types=types))
  135. def visit_end(self):
  136. (genc, genh) = self._module[self._main_module]
  137. genh.add(gen_enum(self._event_enum_name,
  138. self._event_enum_members))
  139. genc.add(gen_enum_lookup(self._event_enum_name,
  140. self._event_enum_members))
  141. genh.add(mcgen('''
  142. void %(event_emit)s(%(event_enum)s event, QDict *qdict);
  143. ''',
  144. event_emit=self._event_emit_name,
  145. event_enum=self._event_enum_name))
  146. def visit_event(self, name, info, ifcond, arg_type, boxed):
  147. with ifcontext(ifcond, self._genh, self._genc):
  148. self._genh.add(gen_event_send_decl(name, arg_type, boxed))
  149. self._genc.add(gen_event_send(name, arg_type, boxed,
  150. self._event_enum_name,
  151. self._event_emit_name))
  152. self._event_enum_members.append(QAPISchemaMember(name, ifcond))
  153. def gen_events(schema, output_dir, prefix):
  154. vis = QAPISchemaGenEventVisitor(prefix)
  155. schema.visit(vis)
  156. vis.write(output_dir)