2 QAPI command marshaller generator
4 Copyright IBM, Corp. 2011
5 Copyright (C) 2014-2018 Red Hat, Inc.
8 Anthony Liguori <aliguori@us.ibm.com>
9 Michael Roth <mdroth@linux.vnet.ibm.com>
10 Markus Armbruster <armbru@redhat.com>
12 This work is licensed under the terms of the GNU GPL, version 2.
13 See the COPYING file in the top-level directory.
23 from .common
import c_name
, mcgen
27 QAPISchemaModularCVisitor
,
37 from .source
import QAPISourceInfo
40 def gen_command_decl(name
: str,
41 arg_type
: Optional
[QAPISchemaObjectType
],
43 ret_type
: Optional
[QAPISchemaType
]) -> str:
45 %(c_type)s qmp_%(c_name)s(%(params)s);
47 c_type
=(ret_type
and ret_type
.c_type()) or 'void',
49 params
=build_params(arg_type
, boxed
, 'Error **errp'))
52 def gen_call(name
: str,
53 arg_type
: Optional
[QAPISchemaObjectType
],
55 ret_type
: Optional
[QAPISchemaType
]) -> str:
63 assert not arg_type
.variants
64 for memb
in arg_type
.members
:
66 argstr
+= 'arg.has_%s, ' % c_name(memb
.name
)
67 argstr
+= 'arg.%s, ' % c_name(memb
.name
)
75 %(lhs)sqmp_%(c_name)s(%(args)s&err);
76 error_propagate(errp, err);
78 c_name
=c_name(name
), args
=argstr
, lhs
=lhs
)
85 qmp_marshal_output_%(c_name)s(retval, ret, errp);
87 c_name
=ret_type
.c_name())
91 def gen_marshal_output(ret_type
: QAPISchemaType
) -> str:
94 static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in,
95 QObject **ret_out, Error **errp)
99 v = qobject_output_visitor_new(ret_out);
100 if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
101 visit_complete(v, ret_out);
104 v = qapi_dealloc_visitor_new();
105 visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
109 c_type
=ret_type
.c_type(), c_name
=ret_type
.c_name())
112 def build_marshal_proto(name
: str) -> str:
113 return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
117 def gen_marshal_decl(name
: str) -> str:
121 proto
=build_marshal_proto(name
))
124 def gen_marshal(name
: str,
125 arg_type
: Optional
[QAPISchemaObjectType
],
127 ret_type
: Optional
[QAPISchemaType
]) -> str:
128 have_args
= boxed
or (arg_type
and not arg_type
.is_empty())
138 proto
=build_marshal_proto(name
))
144 c_type
=ret_type
.c_type())
148 %(c_name)s arg = {0};
150 c_name
=arg_type
.c_name())
154 v = qobject_input_visitor_new(QOBJECT(args));
155 if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
162 if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) {
163 ok = visit_check_struct(v, errp);
166 c_arg_type
=arg_type
.c_name())
169 ok = visit_check_struct(v, errp);
173 visit_end_struct(v, NULL);
179 ret
+= gen_call(name
, arg_type
, boxed
, ret_type
)
188 v = qapi_dealloc_visitor_new();
189 visit_start_struct(v, NULL, NULL, 0, NULL);
194 visit_type_%(c_arg_type)s_members(v, &arg, NULL);
196 c_arg_type
=arg_type
.c_name())
199 visit_end_struct(v, NULL);
209 def gen_register_command(name
: str,
210 success_response
: bool,
212 allow_preconfig
: bool,
213 coroutine
: bool) -> str:
216 if not success_response
:
217 options
+= ['QCO_NO_SUCCESS_RESP']
219 options
+= ['QCO_ALLOW_OOB']
221 options
+= ['QCO_ALLOW_PRECONFIG']
223 options
+= ['QCO_COROUTINE']
226 options
= ['QCO_NO_OPTIONS']
229 qmp_register_command(cmds, "%(name)s",
230 qmp_marshal_%(c_name)s, %(opts)s);
232 name
=name
, c_name
=c_name(name
),
233 opts
=" | ".join(options
))
237 def gen_registry(registry
: str, prefix
: str) -> str:
240 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
245 c_prefix
=c_name(prefix
, protect
=False))
253 class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor
):
254 def __init__(self
, prefix
: str):
256 prefix
, 'qapi-commands',
257 ' * Schema-defined QAPI/QMP commands', None, __doc__
)
258 self
._regy
= QAPIGenCCode(None)
259 self
._visited
_ret
_types
: Dict
[QAPIGenC
, Set
[QAPISchemaType
]] = {}
261 def _begin_user_module(self
, name
: str) -> None:
262 self
._visited
_ret
_types
[self
._genc
] = set()
263 commands
= self
._module
_basename
('qapi-commands', name
)
264 types
= self
._module
_basename
('qapi-types', name
)
265 visit
= self
._module
_basename
('qapi-visit', name
)
266 self
._genc
.add(mcgen('''
267 #include "qemu/osdep.h"
268 #include "qapi/visitor.h"
269 #include "qapi/qmp/qdict.h"
270 #include "qapi/qobject-output-visitor.h"
271 #include "qapi/qobject-input-visitor.h"
272 #include "qapi/dealloc-visitor.h"
273 #include "qapi/error.h"
274 #include "%(visit)s.h"
275 #include "%(commands)s.h"
278 commands
=commands
, visit
=visit
))
279 self
._genh
.add(mcgen('''
280 #include "%(types)s.h"
285 def visit_end(self
) -> None:
286 self
._add
_system
_module
('init', ' * QAPI Commands initialization')
287 self
._genh
.add(mcgen('''
288 #include "qapi/qmp/dispatch.h"
290 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
292 c_prefix
=c_name(self
._prefix
, protect
=False)))
293 self
._genc
.preamble_add(mcgen('''
294 #include "qemu/osdep.h"
295 #include "%(prefix)sqapi-commands.h"
296 #include "%(prefix)sqapi-init-commands.h"
298 prefix
=self
._prefix
))
299 self
._genc
.add(gen_registry(self
._regy
.get_content(), self
._prefix
))
301 def visit_command(self
,
303 info
: QAPISourceInfo
,
305 features
: List
[QAPISchemaFeature
],
306 arg_type
: Optional
[QAPISchemaObjectType
],
307 ret_type
: Optional
[QAPISchemaType
],
309 success_response
: bool,
312 allow_preconfig
: bool,
313 coroutine
: bool) -> None:
316 # FIXME: If T is a user-defined type, the user is responsible
317 # for making this work, i.e. to make T's condition the
318 # conjunction of the T-returning commands' conditions. If T
319 # is a built-in type, this isn't possible: the
320 # qmp_marshal_output_T() will be generated unconditionally.
321 if ret_type
and ret_type
not in self
._visited
_ret
_types
[self
._genc
]:
322 self
._visited
_ret
_types
[self
._genc
].add(ret_type
)
323 with
ifcontext(ret_type
.ifcond
,
324 self
._genh
, self
._genc
, self
._regy
):
325 self
._genc
.add(gen_marshal_output(ret_type
))
326 with
ifcontext(ifcond
, self
._genh
, self
._genc
, self
._regy
):
327 self
._genh
.add(gen_command_decl(name
, arg_type
, boxed
, ret_type
))
328 self
._genh
.add(gen_marshal_decl(name
))
329 self
._genc
.add(gen_marshal(name
, arg_type
, boxed
, ret_type
))
330 self
._regy
.add(gen_register_command(name
, success_response
,
331 allow_oob
, allow_preconfig
,
335 def gen_commands(schema
: QAPISchema
,
337 prefix
: str) -> None:
338 vis
= QAPISchemaGenCommandVisitor(prefix
)
340 vis
.write(output_dir
)