qapi-event.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #
  2. # QAPI event generator
  3. #
  4. # Copyright (c) 2014 Wenchao Xia
  5. #
  6. # Authors:
  7. # Wenchao Xia <wenchaoqemu@gmail.com>
  8. #
  9. # This work is licensed under the terms of the GNU GPL, version 2.
  10. # See the COPYING file in the top-level directory.
  11. from ordereddict import OrderedDict
  12. from qapi import *
  13. def _generate_event_api_name(event_name, params):
  14. api_name = "void qapi_event_send_%s(" % c_name(event_name).lower();
  15. l = len(api_name)
  16. if params:
  17. for argname, argentry, optional in parse_args(params):
  18. if optional:
  19. api_name += "bool has_%s,\n" % c_name(argname)
  20. api_name += "".ljust(l)
  21. api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
  22. c_name(argname))
  23. api_name += "".ljust(l)
  24. api_name += "Error **errp)"
  25. return api_name;
  26. # Following are the core functions that generate C APIs to emit event.
  27. def generate_event_declaration(api_name):
  28. return mcgen('''
  29. %(api_name)s;
  30. ''',
  31. api_name = api_name)
  32. def generate_event_implement(api_name, event_name, params):
  33. # step 1: declare any variables
  34. ret = mcgen("""
  35. %(api_name)s
  36. {
  37. QDict *qmp;
  38. Error *local_err = NULL;
  39. QMPEventFuncEmit emit;
  40. """,
  41. api_name = api_name)
  42. if params:
  43. ret += mcgen("""
  44. QmpOutputVisitor *qov;
  45. Visitor *v;
  46. QObject *obj;
  47. """)
  48. # step 2: check emit function, create a dict
  49. ret += mcgen("""
  50. emit = qmp_event_get_func_emit();
  51. if (!emit) {
  52. return;
  53. }
  54. qmp = qmp_event_build_dict("%(event_name)s");
  55. """,
  56. event_name = event_name)
  57. # step 3: visit the params if params != None
  58. if params:
  59. ret += mcgen("""
  60. qov = qmp_output_visitor_new();
  61. g_assert(qov);
  62. v = qmp_output_get_visitor(qov);
  63. g_assert(v);
  64. /* Fake visit, as if all members are under a structure */
  65. visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
  66. if (local_err) {
  67. goto clean;
  68. }
  69. """,
  70. event_name = event_name)
  71. for argname, argentry, optional in parse_args(params):
  72. if optional:
  73. ret += mcgen("""
  74. if (has_%(var)s) {
  75. """,
  76. var = c_name(argname))
  77. push_indent()
  78. if argentry == "str":
  79. var_type = "(char **)"
  80. else:
  81. var_type = ""
  82. ret += mcgen("""
  83. visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
  84. if (local_err) {
  85. goto clean;
  86. }
  87. """,
  88. var_type = var_type,
  89. var = c_name(argname),
  90. type = type_name(argentry),
  91. name = argname)
  92. if optional:
  93. pop_indent()
  94. ret += mcgen("""
  95. }
  96. """)
  97. ret += mcgen("""
  98. visit_end_struct(v, &local_err);
  99. if (local_err) {
  100. goto clean;
  101. }
  102. obj = qmp_output_get_qobject(qov);
  103. g_assert(obj != NULL);
  104. qdict_put_obj(qmp, "data", obj);
  105. """)
  106. # step 4: call qmp event api
  107. ret += mcgen("""
  108. emit(%(event_enum_value)s, qmp, &local_err);
  109. """,
  110. event_enum_value = event_enum_value)
  111. # step 5: clean up
  112. if params:
  113. ret += mcgen("""
  114. clean:
  115. qmp_output_visitor_cleanup(qov);
  116. """)
  117. ret += mcgen("""
  118. error_propagate(errp, local_err);
  119. QDECREF(qmp);
  120. }
  121. """)
  122. return ret
  123. # Following are the functions that generate an enum type for all defined
  124. # events, similar to qapi-types.py. Here we already have enum name and
  125. # values which were generated before and recorded in event_enum_*. It also
  126. # works around the issue that "import qapi-types" can't work.
  127. def generate_event_enum_decl(event_enum_name, event_enum_values):
  128. lookup_decl = mcgen('''
  129. extern const char *%(event_enum_name)s_lookup[];
  130. ''',
  131. event_enum_name = event_enum_name)
  132. enum_decl = mcgen('''
  133. typedef enum %(event_enum_name)s
  134. {
  135. ''',
  136. event_enum_name = event_enum_name)
  137. # append automatically generated _MAX value
  138. enum_max_value = c_enum_const(event_enum_name, "MAX")
  139. enum_values = event_enum_values + [ enum_max_value ]
  140. i = 0
  141. for value in enum_values:
  142. enum_decl += mcgen('''
  143. %(value)s = %(i)d,
  144. ''',
  145. value = value,
  146. i = i)
  147. i += 1
  148. enum_decl += mcgen('''
  149. } %(event_enum_name)s;
  150. ''',
  151. event_enum_name = event_enum_name)
  152. return lookup_decl + enum_decl
  153. def generate_event_enum_lookup(event_enum_name, event_enum_strings):
  154. ret = mcgen('''
  155. const char *%(event_enum_name)s_lookup[] = {
  156. ''',
  157. event_enum_name = event_enum_name)
  158. i = 0
  159. for string in event_enum_strings:
  160. ret += mcgen('''
  161. "%(string)s",
  162. ''',
  163. string = string)
  164. ret += mcgen('''
  165. NULL,
  166. };
  167. ''')
  168. return ret
  169. (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
  170. c_comment = '''
  171. /*
  172. * schema-defined QAPI event functions
  173. *
  174. * Copyright (c) 2014 Wenchao Xia
  175. *
  176. * Authors:
  177. * Wenchao Xia <wenchaoqemu@gmail.com>
  178. *
  179. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  180. * See the COPYING.LIB file in the top-level directory.
  181. *
  182. */
  183. '''
  184. h_comment = '''
  185. /*
  186. * schema-defined QAPI event functions
  187. *
  188. * Copyright (c) 2014 Wenchao Xia
  189. *
  190. * Authors:
  191. * Wenchao Xia <wenchaoqemu@gmail.com>
  192. *
  193. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  194. * See the COPYING.LIB file in the top-level directory.
  195. *
  196. */
  197. '''
  198. (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
  199. 'qapi-event.c', 'qapi-event.h',
  200. c_comment, h_comment)
  201. fdef.write(mcgen('''
  202. #include "qemu-common.h"
  203. #include "%(prefix)sqapi-event.h"
  204. #include "%(prefix)sqapi-visit.h"
  205. #include "qapi/qmp-output-visitor.h"
  206. #include "qapi/qmp-event.h"
  207. ''',
  208. prefix=prefix))
  209. fdecl.write(mcgen('''
  210. #include "qapi/error.h"
  211. #include "qapi/qmp/qdict.h"
  212. #include "%(prefix)sqapi-types.h"
  213. ''',
  214. prefix=prefix))
  215. exprs = parse_schema(input_file)
  216. event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
  217. event_enum_values = []
  218. event_enum_strings = []
  219. for expr in exprs:
  220. if expr.has_key('event'):
  221. event_name = expr['event']
  222. params = expr.get('data')
  223. if params and len(params) == 0:
  224. params = None
  225. api_name = _generate_event_api_name(event_name, params)
  226. ret = generate_event_declaration(api_name)
  227. fdecl.write(ret)
  228. # We need an enum value per event
  229. event_enum_value = c_enum_const(event_enum_name, event_name)
  230. ret = generate_event_implement(api_name, event_name, params)
  231. fdef.write(ret)
  232. # Record it, and generate enum later
  233. event_enum_values.append(event_enum_value)
  234. event_enum_strings.append(event_name)
  235. ret = generate_event_enum_decl(event_enum_name, event_enum_values)
  236. fdecl.write(ret)
  237. ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
  238. fdef.write(ret)
  239. close_output(fdef, fdecl)