2018-02-11 10:35:41 +01:00
|
|
|
"""
|
|
|
|
|
QAPI command marshaller generator
|
|
|
|
|
|
|
|
|
|
Copyright IBM, Corp. 2011
|
|
|
|
|
Copyright (C) 2014-2018 Red Hat, Inc.
|
|
|
|
|
|
|
|
|
|
Authors:
|
|
|
|
|
Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
|
Michael Roth <mdroth@linux.vnet.ibm.com>
|
|
|
|
|
Markus Armbruster <armbru@redhat.com>
|
|
|
|
|
|
|
|
|
|
This work is licensed under the terms of the GNU GPL, version 2.
|
|
|
|
|
See the COPYING file in the top-level directory.
|
|
|
|
|
"""
|
2011-07-19 14:50:42 -05:00
|
|
|
|
2025-11-18 15:06:57 -05:00
|
|
|
from typing import List, Optional
|
2020-10-09 12:15:44 -04:00
|
|
|
|
2020-10-09 12:15:39 -04:00
|
|
|
from .common import c_name, mcgen
|
|
|
|
|
from .gen import (
|
|
|
|
|
QAPISchemaModularCVisitor,
|
|
|
|
|
build_params,
|
2025-02-05 12:35:49 +00:00
|
|
|
gen_features,
|
2022-02-11 13:36:50 -05:00
|
|
|
ifcontext,
|
2020-10-09 12:15:39 -04:00
|
|
|
)
|
2020-10-09 12:15:44 -04:00
|
|
|
from .schema import (
|
|
|
|
|
QAPISchema,
|
|
|
|
|
QAPISchemaFeature,
|
2021-08-04 12:30:57 +04:00
|
|
|
QAPISchemaIfCond,
|
2020-10-09 12:15:44 -04:00
|
|
|
QAPISchemaObjectType,
|
|
|
|
|
QAPISchemaType,
|
|
|
|
|
)
|
|
|
|
|
from .source import QAPISourceInfo
|
2011-07-19 14:50:42 -05:00
|
|
|
|
2015-09-16 13:06:16 +02:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def gen_command_decl(name: str,
|
|
|
|
|
arg_type: Optional[QAPISchemaObjectType],
|
|
|
|
|
boxed: bool,
|
2022-10-13 10:50:49 +02:00
|
|
|
ret_type: Optional[QAPISchemaType],
|
|
|
|
|
coroutine: bool) -> str:
|
2011-07-19 14:50:42 -05:00
|
|
|
return mcgen('''
|
2022-10-13 10:50:49 +02:00
|
|
|
%(c_type)s %(coroutine_fn)sqmp_%(c_name)s(%(params)s);
|
2011-07-19 14:50:42 -05:00
|
|
|
''',
|
2015-09-16 13:06:16 +02:00
|
|
|
c_type=(ret_type and ret_type.c_type()) or 'void',
|
2022-10-13 10:50:49 +02:00
|
|
|
coroutine_fn='coroutine_fn ' if coroutine else '',
|
2015-09-16 13:06:16 +02:00
|
|
|
c_name=c_name(name),
|
2017-06-01 16:41:41 +04:00
|
|
|
params=build_params(arg_type, boxed, 'Error **errp'))
|
2015-09-16 13:06:16 +02:00
|
|
|
|
2011-07-19 14:50:42 -05:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def gen_call(name: str,
|
|
|
|
|
arg_type: Optional[QAPISchemaObjectType],
|
|
|
|
|
boxed: bool,
|
2022-01-26 17:11:26 +01:00
|
|
|
ret_type: Optional[QAPISchemaType],
|
|
|
|
|
gen_tracing: bool) -> str:
|
2015-09-16 13:06:16 +02:00
|
|
|
ret = ''
|
|
|
|
|
|
|
|
|
|
argstr = ''
|
2016-07-13 21:50:19 -06:00
|
|
|
if boxed:
|
2019-09-13 22:13:41 +02:00
|
|
|
assert arg_type
|
2016-07-13 21:50:20 -06:00
|
|
|
argstr = '&arg, '
|
2016-07-13 21:50:19 -06:00
|
|
|
elif arg_type:
|
2024-03-15 16:33:23 +01:00
|
|
|
assert not arg_type.branches
|
2015-09-16 13:06:16 +02:00
|
|
|
for memb in arg_type.members:
|
2023-03-16 08:13:25 +01:00
|
|
|
assert not memb.ifcond.is_present()
|
qapi: Start to elide redundant has_FOO in generated C
In QAPI, absent optional members are distinct from any present value.
We thus represent an optional schema member FOO as two C members: a
FOO with the member's type, and a bool has_FOO. Likewise for function
arguments.
However, has_FOO is actually redundant for a pointer-valued FOO, which
can be null only when has_FOO is false, i.e. has_FOO == !!FOO. Except
for arrays, where we a null FOO can also be a present empty array.
The redundant has_FOO are a nuisance to work with. Improve the
generator to elide them. Uses of has_FOO need to be replaced as
follows.
Tests of has_FOO become the equivalent comparison of FOO with null.
For brevity, this is commonly done by implicit conversion to bool.
Assignments to has_FOO get dropped.
Likewise for arguments to has_FOO parameters.
Beware: code may violate the invariant has_FOO == !!FOO before the
transformation, and get away with it. The above transformation can
then break things. Two cases:
* Absent: if code ignores FOO entirely when !has_FOO (except for
freeing it if necessary), even non-null / uninitialized FOO works.
Such code is known to exist.
* Present: if code ignores FOO entirely when has_FOO, even null FOO
works. Such code should not exist.
In both cases, replacing tests of has_FOO by FOO reverts their sense.
We have to fix the value of FOO then.
To facilitate review of the necessary updates to handwritten code, add
means to opt out of this change, and opt out for all QAPI schema
modules where the change requires updates to handwritten code. The
next few commits will remove these opt-outs in reviewable chunks, then
drop the means to opt out.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20221104160712.3005652-5-armbru@redhat.com>
2022-11-04 17:06:46 +01:00
|
|
|
if memb.need_has():
|
qapi-commands: Utilize implicit struct visits
Rather than generate inline per-member visits, take advantage
of the 'visit_type_FOO_members()' function for command
marshalling. This is possible now that implicit structs can be
visited like any other. Generate call arguments from a stack-
allocated struct, rather than a list of local variables:
|@@ -57,26 +57,15 @@ void qmp_marshal_add_fd(QDict *args, QOb
| QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args));
| QapiDeallocVisitor *qdv;
| Visitor *v;
|- bool has_fdset_id = false;
|- int64_t fdset_id = 0;
|- bool has_opaque = false;
|- char *opaque = NULL;
|+ q_obj_add_fd_arg arg = {0};
|
| v = qmp_input_get_visitor(qiv);
|- if (visit_optional(v, "fdset-id", &has_fdset_id)) {
|- visit_type_int(v, "fdset-id", &fdset_id, &err);
|- if (err) {
|- goto out;
|- }
|- }
|- if (visit_optional(v, "opaque", &has_opaque)) {
|- visit_type_str(v, "opaque", &opaque, &err);
|- if (err) {
|- goto out;
|- }
|+ visit_type_q_obj_add_fd_arg_members(v, &arg, &err);
|+ if (err) {
|+ goto out;
| }
|
|- retval = qmp_add_fd(has_fdset_id, fdset_id, has_opaque, opaque, &err);
|+ retval = qmp_add_fd(arg.has_fdset_id, arg.fdset_id, arg.has_opaque, arg.opaque, &err);
| if (err) {
| goto out;
| }
|@@ -88,12 +77,7 @@ out:
| qmp_input_visitor_cleanup(qiv);
| qdv = qapi_dealloc_visitor_new();
| v = qapi_dealloc_get_visitor(qdv);
|- if (visit_optional(v, "fdset-id", &has_fdset_id)) {
|- visit_type_int(v, "fdset-id", &fdset_id, NULL);
|- }
|- if (visit_optional(v, "opaque", &has_opaque)) {
|- visit_type_str(v, "opaque", &opaque, NULL);
|- }
|+ visit_type_q_obj_add_fd_arg_members(v, &arg, NULL);
| qapi_dealloc_visitor_cleanup(qdv);
| }
This also has the nice side effect of eliminating a chance of
collision between argument QMP names and local variables.
This patch also paves the way for some followup simplifications
in the generator, in subsequent patches.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-9-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 16:48:33 -06:00
|
|
|
argstr += 'arg.has_%s, ' % c_name(memb.name)
|
|
|
|
|
argstr += 'arg.%s, ' % c_name(memb.name)
|
2015-09-16 13:06:16 +02:00
|
|
|
|
|
|
|
|
lhs = ''
|
|
|
|
|
if ret_type:
|
|
|
|
|
lhs = 'retval = '
|
|
|
|
|
|
2022-01-26 17:11:26 +01:00
|
|
|
name = c_name(name)
|
|
|
|
|
upper = name.upper()
|
|
|
|
|
|
|
|
|
|
if gen_tracing:
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
|
|
|
|
|
if (trace_event_get_state_backends(TRACE_QMP_ENTER_%(upper)s)) {
|
|
|
|
|
g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
|
|
|
|
|
|
|
|
|
|
trace_qmp_enter_%(name)s(req_json->str);
|
|
|
|
|
}
|
2022-11-04 17:06:44 +01:00
|
|
|
''',
|
2022-01-26 17:11:26 +01:00
|
|
|
upper=upper, name=name)
|
|
|
|
|
|
|
|
|
|
ret += mcgen('''
|
2015-09-16 13:06:18 +02:00
|
|
|
|
2022-01-26 17:11:26 +01:00
|
|
|
%(lhs)sqmp_%(name)s(%(args)s&err);
|
2011-07-19 14:50:42 -05:00
|
|
|
''',
|
2022-01-26 17:11:26 +01:00
|
|
|
name=name, args=argstr, lhs=lhs)
|
2022-01-26 17:11:25 +01:00
|
|
|
|
|
|
|
|
ret += mcgen('''
|
2016-07-13 21:50:17 -06:00
|
|
|
if (err) {
|
2022-01-26 17:11:26 +01:00
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
if gen_tracing:
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
trace_qmp_exit_%(name)s(error_get_pretty(err), false);
|
|
|
|
|
''',
|
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
|
|
ret += mcgen('''
|
2022-01-26 17:11:25 +01:00
|
|
|
error_propagate(errp, err);
|
2016-07-13 21:50:17 -06:00
|
|
|
goto out;
|
|
|
|
|
}
|
2022-01-26 17:11:25 +01:00
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
if ret_type:
|
qapi/command: Avoid generating unused qmp_marshal_output_T()
qmp_marshal_output_T() is only ever called by qmp_marshal_C() for a
command C that returns type T.
We've always generated it as a static function on demand, i.e. when we
generate a call.
Since we split up monolithic generated code into modules (commit
252dc3105fc "qapi: Generate separate .h, .c for each module"), we do
this per module. As noted in the commit message, this can result in
identical (static) qmp_marshal_output_T() in several modules. Was
deemed not worth avoiding.
A bit later, we added 'if' conditionals to the schema language (merge
commit 5dafaf4fbce).
When a conditional definition uses a type, then its condition must
imply the type's condition. We made this the user's responsibility.
Hasn't been an issue in practice.
However, the sharing of qmp_marshal_output_T() among commands
complicates matters. To avoid both undefined function errors and
unused function warnings, qmp_marshal_output_T() must be defined
exactly when it's used. It is used when any of the qmp_marshal_C()
calling it is defined, i.e. when any C's condition holds.
The generator uses T's condition instead. To avoid both error and
warning, T's condition must be the conjunction of all C's conditions.
Unfortunately, this can be impossible:
* Conditional command returning a builtin type
A builtin type cannot be conditional. This is noted in a FIXME
comment.
* Commands in multiple modules where the conjunction differs between
modules
An instance of this came up recently. we have unconditional
commands returning HumanReadableText. If we add a conditional one
to a module that does not have unconditional ones, compilation fails
with "defined but not used". If we make HumanReadableText
conditional to fix this module, we break the others.
Instead of complicating the code to compute the conjunction, simplify
it: generate the output marshaling code right into qmp_marshal_C().
This duplicates it when multiple commands return the same type. The
impact on code size is negligible: qemu-system-x86_64's text segment
grows by 1448 bytes.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20250804130602.903904-1-armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
[Commit message typos fixed]
2025-08-04 15:06:02 +02:00
|
|
|
ret += gen_marshal_output(ret_type)
|
2022-01-26 17:11:26 +01:00
|
|
|
|
|
|
|
|
if gen_tracing:
|
|
|
|
|
if ret_type:
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
|
|
|
|
|
if (trace_event_get_state_backends(TRACE_QMP_EXIT_%(upper)s)) {
|
|
|
|
|
g_autoptr(GString) ret_json = qobject_to_json(*ret);
|
|
|
|
|
|
|
|
|
|
trace_qmp_exit_%(name)s(ret_json->str, true);
|
|
|
|
|
}
|
2022-11-04 17:06:44 +01:00
|
|
|
''',
|
2022-01-26 17:11:26 +01:00
|
|
|
upper=upper, name=name)
|
|
|
|
|
else:
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
|
|
|
|
|
trace_qmp_exit_%(name)s("{}", true);
|
2022-11-04 17:06:44 +01:00
|
|
|
''',
|
2022-01-26 17:11:26 +01:00
|
|
|
name=name)
|
|
|
|
|
|
2015-06-27 17:49:34 +02:00
|
|
|
return ret
|
2011-07-19 14:50:42 -05:00
|
|
|
|
2015-09-16 13:06:16 +02:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def gen_marshal_output(ret_type: QAPISchemaType) -> str:
|
2015-09-16 13:06:18 +02:00
|
|
|
return mcgen('''
|
2015-09-16 13:06:11 +02:00
|
|
|
|
qapi/command: Avoid generating unused qmp_marshal_output_T()
qmp_marshal_output_T() is only ever called by qmp_marshal_C() for a
command C that returns type T.
We've always generated it as a static function on demand, i.e. when we
generate a call.
Since we split up monolithic generated code into modules (commit
252dc3105fc "qapi: Generate separate .h, .c for each module"), we do
this per module. As noted in the commit message, this can result in
identical (static) qmp_marshal_output_T() in several modules. Was
deemed not worth avoiding.
A bit later, we added 'if' conditionals to the schema language (merge
commit 5dafaf4fbce).
When a conditional definition uses a type, then its condition must
imply the type's condition. We made this the user's responsibility.
Hasn't been an issue in practice.
However, the sharing of qmp_marshal_output_T() among commands
complicates matters. To avoid both undefined function errors and
unused function warnings, qmp_marshal_output_T() must be defined
exactly when it's used. It is used when any of the qmp_marshal_C()
calling it is defined, i.e. when any C's condition holds.
The generator uses T's condition instead. To avoid both error and
warning, T's condition must be the conjunction of all C's conditions.
Unfortunately, this can be impossible:
* Conditional command returning a builtin type
A builtin type cannot be conditional. This is noted in a FIXME
comment.
* Commands in multiple modules where the conjunction differs between
modules
An instance of this came up recently. we have unconditional
commands returning HumanReadableText. If we add a conditional one
to a module that does not have unconditional ones, compilation fails
with "defined but not used". If we make HumanReadableText
conditional to fix this module, we break the others.
Instead of complicating the code to compute the conjunction, simplify
it: generate the output marshaling code right into qmp_marshal_C().
This duplicates it when multiple commands return the same type. The
impact on code size is negligible: qemu-system-x86_64's text segment
grows by 1448 bytes.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20250804130602.903904-1-armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
[Commit message typos fixed]
2025-08-04 15:06:02 +02:00
|
|
|
ov = qobject_output_visitor_new_qmp(ret);
|
|
|
|
|
if (visit_type_%(c_name)s(ov, "unused", &retval, errp)) {
|
|
|
|
|
visit_complete(ov, ret);
|
2011-07-19 14:50:42 -05:00
|
|
|
}
|
qapi/command: Avoid generating unused qmp_marshal_output_T()
qmp_marshal_output_T() is only ever called by qmp_marshal_C() for a
command C that returns type T.
We've always generated it as a static function on demand, i.e. when we
generate a call.
Since we split up monolithic generated code into modules (commit
252dc3105fc "qapi: Generate separate .h, .c for each module"), we do
this per module. As noted in the commit message, this can result in
identical (static) qmp_marshal_output_T() in several modules. Was
deemed not worth avoiding.
A bit later, we added 'if' conditionals to the schema language (merge
commit 5dafaf4fbce).
When a conditional definition uses a type, then its condition must
imply the type's condition. We made this the user's responsibility.
Hasn't been an issue in practice.
However, the sharing of qmp_marshal_output_T() among commands
complicates matters. To avoid both undefined function errors and
unused function warnings, qmp_marshal_output_T() must be defined
exactly when it's used. It is used when any of the qmp_marshal_C()
calling it is defined, i.e. when any C's condition holds.
The generator uses T's condition instead. To avoid both error and
warning, T's condition must be the conjunction of all C's conditions.
Unfortunately, this can be impossible:
* Conditional command returning a builtin type
A builtin type cannot be conditional. This is noted in a FIXME
comment.
* Commands in multiple modules where the conjunction differs between
modules
An instance of this came up recently. we have unconditional
commands returning HumanReadableText. If we add a conditional one
to a module that does not have unconditional ones, compilation fails
with "defined but not used". If we make HumanReadableText
conditional to fix this module, we break the others.
Instead of complicating the code to compute the conjunction, simplify
it: generate the output marshaling code right into qmp_marshal_C().
This duplicates it when multiple commands return the same type. The
impact on code size is negligible: qemu-system-x86_64's text segment
grows by 1448 bytes.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20250804130602.903904-1-armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
[Commit message typos fixed]
2025-08-04 15:06:02 +02:00
|
|
|
visit_free(ov);
|
|
|
|
|
ov = qapi_dealloc_visitor_new();
|
|
|
|
|
visit_type_%(c_name)s(ov, "unused", &retval, NULL);
|
|
|
|
|
visit_free(ov);
|
2011-07-19 14:50:42 -05:00
|
|
|
''',
|
qapi/command: Avoid generating unused qmp_marshal_output_T()
qmp_marshal_output_T() is only ever called by qmp_marshal_C() for a
command C that returns type T.
We've always generated it as a static function on demand, i.e. when we
generate a call.
Since we split up monolithic generated code into modules (commit
252dc3105fc "qapi: Generate separate .h, .c for each module"), we do
this per module. As noted in the commit message, this can result in
identical (static) qmp_marshal_output_T() in several modules. Was
deemed not worth avoiding.
A bit later, we added 'if' conditionals to the schema language (merge
commit 5dafaf4fbce).
When a conditional definition uses a type, then its condition must
imply the type's condition. We made this the user's responsibility.
Hasn't been an issue in practice.
However, the sharing of qmp_marshal_output_T() among commands
complicates matters. To avoid both undefined function errors and
unused function warnings, qmp_marshal_output_T() must be defined
exactly when it's used. It is used when any of the qmp_marshal_C()
calling it is defined, i.e. when any C's condition holds.
The generator uses T's condition instead. To avoid both error and
warning, T's condition must be the conjunction of all C's conditions.
Unfortunately, this can be impossible:
* Conditional command returning a builtin type
A builtin type cannot be conditional. This is noted in a FIXME
comment.
* Commands in multiple modules where the conjunction differs between
modules
An instance of this came up recently. we have unconditional
commands returning HumanReadableText. If we add a conditional one
to a module that does not have unconditional ones, compilation fails
with "defined but not used". If we make HumanReadableText
conditional to fix this module, we break the others.
Instead of complicating the code to compute the conjunction, simplify
it: generate the output marshaling code right into qmp_marshal_C().
This duplicates it when multiple commands return the same type. The
impact on code size is negligible: qemu-system-x86_64's text segment
grows by 1448 bytes.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20250804130602.903904-1-armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
[Commit message typos fixed]
2025-08-04 15:06:02 +02:00
|
|
|
c_name=ret_type.c_name())
|
2011-07-19 14:50:42 -05:00
|
|
|
|
2015-09-16 13:06:16 +02:00
|
|
|
|
2022-10-13 10:50:49 +02:00
|
|
|
def build_marshal_proto(name: str,
|
|
|
|
|
coroutine: bool) -> str:
|
|
|
|
|
return ('void %(coroutine_fn)sqmp_marshal_%(c_name)s(%(params)s)' % {
|
|
|
|
|
'coroutine_fn': 'coroutine_fn ' if coroutine else '',
|
|
|
|
|
'c_name': c_name(name),
|
|
|
|
|
'params': 'QDict *args, QObject **ret, Error **errp',
|
|
|
|
|
})
|
2011-09-02 12:34:46 -05:00
|
|
|
|
2015-09-16 13:06:16 +02:00
|
|
|
|
2022-10-13 10:50:49 +02:00
|
|
|
def gen_marshal_decl(name: str,
|
|
|
|
|
coroutine: bool) -> str:
|
2015-09-16 13:06:18 +02:00
|
|
|
return mcgen('''
|
|
|
|
|
%(proto)s;
|
|
|
|
|
''',
|
2022-10-13 10:50:49 +02:00
|
|
|
proto=build_marshal_proto(name, coroutine))
|
2015-09-16 13:06:18 +02:00
|
|
|
|
2011-09-02 12:34:46 -05:00
|
|
|
|
2022-01-26 17:11:26 +01:00
|
|
|
def gen_trace(name: str) -> str:
|
|
|
|
|
return mcgen('''
|
|
|
|
|
qmp_enter_%(name)s(const char *json) "%%s"
|
|
|
|
|
qmp_exit_%(name)s(const char *result, bool succeeded) "%%s %%d"
|
|
|
|
|
''',
|
|
|
|
|
name=c_name(name))
|
|
|
|
|
|
|
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def gen_marshal(name: str,
|
|
|
|
|
arg_type: Optional[QAPISchemaObjectType],
|
|
|
|
|
boxed: bool,
|
2022-01-26 17:11:26 +01:00
|
|
|
ret_type: Optional[QAPISchemaType],
|
2022-10-13 10:50:49 +02:00
|
|
|
gen_tracing: bool,
|
|
|
|
|
coroutine: bool) -> str:
|
2019-09-13 22:13:41 +02:00
|
|
|
have_args = boxed or (arg_type and not arg_type.is_empty())
|
2021-02-01 14:37:32 -05:00
|
|
|
if have_args:
|
|
|
|
|
assert arg_type is not None
|
|
|
|
|
arg_type_c_name = arg_type.c_name()
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
|
2011-07-19 14:50:42 -05:00
|
|
|
ret = mcgen('''
|
2015-09-16 13:06:11 +02:00
|
|
|
|
2015-09-16 13:06:18 +02:00
|
|
|
%(proto)s
|
2011-07-19 14:50:42 -05:00
|
|
|
{
|
2016-03-17 16:48:34 -06:00
|
|
|
Error *err = NULL;
|
2020-07-07 18:06:08 +02:00
|
|
|
bool ok = false;
|
2020-04-24 10:43:37 +02:00
|
|
|
Visitor *v;
|
2011-07-19 14:50:42 -05:00
|
|
|
''',
|
2022-10-13 10:50:49 +02:00
|
|
|
proto=build_marshal_proto(name, coroutine))
|
2011-07-19 14:50:42 -05:00
|
|
|
|
2016-03-17 16:48:34 -06:00
|
|
|
if ret_type:
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
%(c_type)s retval;
|
qapi/command: Avoid generating unused qmp_marshal_output_T()
qmp_marshal_output_T() is only ever called by qmp_marshal_C() for a
command C that returns type T.
We've always generated it as a static function on demand, i.e. when we
generate a call.
Since we split up monolithic generated code into modules (commit
252dc3105fc "qapi: Generate separate .h, .c for each module"), we do
this per module. As noted in the commit message, this can result in
identical (static) qmp_marshal_output_T() in several modules. Was
deemed not worth avoiding.
A bit later, we added 'if' conditionals to the schema language (merge
commit 5dafaf4fbce).
When a conditional definition uses a type, then its condition must
imply the type's condition. We made this the user's responsibility.
Hasn't been an issue in practice.
However, the sharing of qmp_marshal_output_T() among commands
complicates matters. To avoid both undefined function errors and
unused function warnings, qmp_marshal_output_T() must be defined
exactly when it's used. It is used when any of the qmp_marshal_C()
calling it is defined, i.e. when any C's condition holds.
The generator uses T's condition instead. To avoid both error and
warning, T's condition must be the conjunction of all C's conditions.
Unfortunately, this can be impossible:
* Conditional command returning a builtin type
A builtin type cannot be conditional. This is noted in a FIXME
comment.
* Commands in multiple modules where the conjunction differs between
modules
An instance of this came up recently. we have unconditional
commands returning HumanReadableText. If we add a conditional one
to a module that does not have unconditional ones, compilation fails
with "defined but not used". If we make HumanReadableText
conditional to fix this module, we break the others.
Instead of complicating the code to compute the conjunction, simplify
it: generate the output marshaling code right into qmp_marshal_C().
This duplicates it when multiple commands return the same type. The
impact on code size is negligible: qemu-system-x86_64's text segment
grows by 1448 bytes.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20250804130602.903904-1-armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
[Commit message typos fixed]
2025-08-04 15:06:02 +02:00
|
|
|
Visitor *ov;
|
2016-03-17 16:48:34 -06:00
|
|
|
''',
|
|
|
|
|
c_type=ret_type.c_type())
|
|
|
|
|
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
if have_args:
|
2016-03-17 16:48:34 -06:00
|
|
|
ret += mcgen('''
|
|
|
|
|
%(c_name)s arg = {0};
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
''',
|
2021-02-01 14:37:32 -05:00
|
|
|
c_name=arg_type_c_name)
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
|
|
|
|
|
ret += mcgen('''
|
2020-04-24 10:43:37 +02:00
|
|
|
|
2021-03-18 16:55:18 +01:00
|
|
|
v = qobject_input_visitor_new_qmp(QOBJECT(args));
|
2020-07-07 18:06:08 +02:00
|
|
|
if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
|
qapi-commands: Wrap argument visit in visit_start_struct
The qmp-input visitor was allowing callers to play rather fast
and loose: when visiting a QDict, you could grab members of the
root dictionary without first pushing into the dict; among the
culprit callers was the generated marshal code on the 'arguments'
dictionary of a QMP command. But we are about to tighten the
input visitor, at which point the generated marshal code MUST
follow the same paradigms as everyone else, of pushing into the
struct before grabbing its keys.
Generated code grows as follows:
|@@ -515,7 +641,12 @@ void qmp_marshal_blockdev_backup(QDict *
| BlockdevBackup arg = {0};
|
| v = qmp_input_get_visitor(qiv);
|+ visit_start_struct(v, NULL, NULL, 0, &err);
|+ if (err) {
|+ goto out;
|+ }
| visit_type_BlockdevBackup_members(v, &arg, &err);
|+ visit_end_struct(v, err ? NULL : &err);
| if (err) {
| goto out;
| }
|@@ -527,7 +715,9 @@ out:
| qmp_input_visitor_cleanup(qiv);
| qdv = qapi_dealloc_visitor_new();
| v = qapi_dealloc_get_visitor(qdv);
|+ visit_start_struct(v, NULL, NULL, 0, NULL);
| visit_type_BlockdevBackup_members(v, &arg, NULL);
|+ visit_end_struct(v, NULL);
| qapi_dealloc_visitor_cleanup(qdv);
| }
The use of 'err ? NULL : &err' is temporary; a later patch will
clean that up when it splits visit_end_struct().
Prior to this patch, the fact that there was no final
visit_end_struct() meant that even though we are using a strict
input visit, the marshalling code was not detecting excess input
at the top level (only in nested levels). Fortunately, we have
code in monitor.c:qmp_check_client_args() that also checks for
no excess arguments at the top level. But as the generated code
is more compact than the manual check, a later patch will clean
up monitor.c to drop the redundancy added here.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-9-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 15:45:16 -06:00
|
|
|
goto out;
|
|
|
|
|
}
|
2020-04-24 10:43:38 +02:00
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
if have_args:
|
|
|
|
|
ret += mcgen('''
|
2020-07-07 18:06:08 +02:00
|
|
|
if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) {
|
|
|
|
|
ok = visit_check_struct(v, errp);
|
qapi: Split visit_end_struct() into pieces
As mentioned in previous patches, we want to call visit_end_struct()
functions unconditionally, so that visitors can release resources
tied up since the matching visit_start_struct() without also having
to worry about error priority if more than one error occurs.
Even though error_propagate() can be safely used to ignore a second
error during cleanup caused by a first error, it is simpler if the
cleanup cannot set an error. So, split out the error checking
portion (basically, input visitors checking for unvisited keys) into
a new function visit_check_struct(), which can be safely skipped if
any earlier errors are encountered, and leave the cleanup portion
(which never fails, but must be called unconditionally if
visit_start_struct() succeeded) in visit_end_struct().
Generated code in qapi-visit.c has diffs resembling:
|@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v,
| goto out_obj;
| }
| visit_type_ACPIOSTInfo_members(v, obj, &err);
|- error_propagate(errp, err);
|- err = NULL;
|+ if (err) {
|+ goto out_obj;
|+ }
|+ visit_check_struct(v, &err);
| out_obj:
|- visit_end_struct(v, &err);
|+ visit_end_struct(v);
| out:
and in qapi-event.c:
@@ -47,7 +47,10 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
| visit_type_q_obj_ACPI_DEVICE_OST_arg_members(v, ¶m, &err);
|- visit_end_struct(v, err ? NULL : &err);
|+ if (!err) {
|+ visit_check_struct(v, &err);
|+ }
|+ visit_end_struct(v);
| if (err) {
| goto out;
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-20-git-send-email-eblake@redhat.com>
[Conflict with a doc fixup resolved]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 15:45:27 -06:00
|
|
|
}
|
2020-04-24 10:43:38 +02:00
|
|
|
''',
|
2021-02-01 14:37:32 -05:00
|
|
|
c_arg_type=arg_type_c_name)
|
2020-04-24 10:43:38 +02:00
|
|
|
else:
|
|
|
|
|
ret += mcgen('''
|
2020-07-07 18:06:08 +02:00
|
|
|
ok = visit_check_struct(v, errp);
|
2020-04-24 10:43:38 +02:00
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
ret += mcgen('''
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 10:48:34 -06:00
|
|
|
visit_end_struct(v, NULL);
|
2020-07-07 18:06:08 +02:00
|
|
|
if (!ok) {
|
2016-03-17 16:48:34 -06:00
|
|
|
goto out;
|
|
|
|
|
}
|
2020-04-24 10:43:38 +02:00
|
|
|
''')
|
2016-03-17 16:48:34 -06:00
|
|
|
|
2022-01-26 17:11:26 +01:00
|
|
|
ret += gen_call(name, arg_type, boxed, ret_type, gen_tracing)
|
2015-06-27 17:49:34 +02:00
|
|
|
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
ret += mcgen('''
|
2011-07-19 14:50:42 -05:00
|
|
|
|
|
|
|
|
out:
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
visit_free(v);
|
2015-06-27 17:49:34 +02:00
|
|
|
''')
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
|
|
|
|
|
ret += mcgen('''
|
qapi: Add new visit_free() function
Making each visitor provide its own (awkwardly-named) FOO_cleanup()
is unusual, when we can instead have a polymorphic visit_free()
interface. Over the next few patches, we can use the polymorphic
functions to eliminate the need for a FOO_get_visitor() function
for accessing specific visitor functionality, once everything can
be accessed directly through the Visitor* interfaces.
The dealloc visitor is the first one converted to completely use
the new entry point, since qapi_dealloc_visitor_cleanup() was the
only reason that qapi_dealloc_get_visitor() existed, and only
generated and testsuite code was even using it. With the new
visit_free() entry point in place, we no longer need to expose
the QapiDeallocVisitor subtype through qapi_dealloc_visitor_new(),
and can get by with less generated code, with diffs that look like:
| void qapi_free_ACPIOSTInfo(ACPIOSTInfo *obj)
| {
|- QapiDeallocVisitor *qdv;
| Visitor *v;
|
| if (!obj) {
| return;
| }
|
|- qdv = qapi_dealloc_visitor_new();
|- v = qapi_dealloc_get_visitor(qdv);
|+ v = qapi_dealloc_visitor_new();
| visit_type_ACPIOSTInfo(v, NULL, &obj, NULL);
|- qapi_dealloc_visitor_cleanup(qdv);
|+ visit_free(v);
|}
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-5-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 10:48:35 -06:00
|
|
|
v = qapi_dealloc_visitor_new();
|
qapi-commands: Wrap argument visit in visit_start_struct
The qmp-input visitor was allowing callers to play rather fast
and loose: when visiting a QDict, you could grab members of the
root dictionary without first pushing into the dict; among the
culprit callers was the generated marshal code on the 'arguments'
dictionary of a QMP command. But we are about to tighten the
input visitor, at which point the generated marshal code MUST
follow the same paradigms as everyone else, of pushing into the
struct before grabbing its keys.
Generated code grows as follows:
|@@ -515,7 +641,12 @@ void qmp_marshal_blockdev_backup(QDict *
| BlockdevBackup arg = {0};
|
| v = qmp_input_get_visitor(qiv);
|+ visit_start_struct(v, NULL, NULL, 0, &err);
|+ if (err) {
|+ goto out;
|+ }
| visit_type_BlockdevBackup_members(v, &arg, &err);
|+ visit_end_struct(v, err ? NULL : &err);
| if (err) {
| goto out;
| }
|@@ -527,7 +715,9 @@ out:
| qmp_input_visitor_cleanup(qiv);
| qdv = qapi_dealloc_visitor_new();
| v = qapi_dealloc_get_visitor(qdv);
|+ visit_start_struct(v, NULL, NULL, 0, NULL);
| visit_type_BlockdevBackup_members(v, &arg, NULL);
|+ visit_end_struct(v, NULL);
| qapi_dealloc_visitor_cleanup(qdv);
| }
The use of 'err ? NULL : &err' is temporary; a later patch will
clean that up when it splits visit_end_struct().
Prior to this patch, the fact that there was no final
visit_end_struct() meant that even though we are using a strict
input visit, the marshalling code was not detecting excess input
at the top level (only in nested levels). Fortunately, we have
code in monitor.c:qmp_check_client_args() that also checks for
no excess arguments at the top level. But as the generated code
is more compact than the manual check, a later patch will clean
up monitor.c to drop the redundancy added here.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-9-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 15:45:16 -06:00
|
|
|
visit_start_struct(v, NULL, NULL, 0, NULL);
|
2020-04-24 10:43:38 +02:00
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
if have_args:
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
visit_type_%(c_arg_type)s_members(v, &arg, NULL);
|
|
|
|
|
''',
|
2021-02-01 14:37:32 -05:00
|
|
|
c_arg_type=arg_type_c_name)
|
2020-04-24 10:43:38 +02:00
|
|
|
|
|
|
|
|
ret += mcgen('''
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 10:48:34 -06:00
|
|
|
visit_end_struct(v, NULL);
|
qapi: Add new visit_free() function
Making each visitor provide its own (awkwardly-named) FOO_cleanup()
is unusual, when we can instead have a polymorphic visit_free()
interface. Over the next few patches, we can use the polymorphic
functions to eliminate the need for a FOO_get_visitor() function
for accessing specific visitor functionality, once everything can
be accessed directly through the Visitor* interfaces.
The dealloc visitor is the first one converted to completely use
the new entry point, since qapi_dealloc_visitor_cleanup() was the
only reason that qapi_dealloc_get_visitor() existed, and only
generated and testsuite code was even using it. With the new
visit_free() entry point in place, we no longer need to expose
the QapiDeallocVisitor subtype through qapi_dealloc_visitor_new(),
and can get by with less generated code, with diffs that look like:
| void qapi_free_ACPIOSTInfo(ACPIOSTInfo *obj)
| {
|- QapiDeallocVisitor *qdv;
| Visitor *v;
|
| if (!obj) {
| return;
| }
|
|- qdv = qapi_dealloc_visitor_new();
|- v = qapi_dealloc_get_visitor(qdv);
|+ v = qapi_dealloc_visitor_new();
| visit_type_ACPIOSTInfo(v, NULL, &obj, NULL);
|- qapi_dealloc_visitor_cleanup(qdv);
|+ visit_free(v);
|}
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-5-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 10:48:35 -06:00
|
|
|
visit_free(v);
|
2020-04-24 10:43:38 +02:00
|
|
|
''')
|
qapi: check invalid arguments on no-args commands
The generated marshal functions do not visit arguments from commands
that take no arguments. Thus they fail to catch invalid
members. Visit the arguments, if provided, to throw an error in case of
invalid members.
Currently, qmp_check_client_args() checks for invalid arguments and
correctly catches this case. When switching to qmp_dispatch() we want to
keep that behaviour. The commands using 'O' may have arbitrary
arguments, and must have 'gen': false in the qapi schema to skip the
generated checks.
Old/new diff:
void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
+ Visitor *v = NULL;
- (void)args;
+ if (args) {
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
+ if (err) {
+ goto out;
+ }
+ }
qmp_stop(&err);
+
+out:
error_propagate(errp, err);
+ visit_free(v);
+ if (args) {
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+
+ visit_end_struct(v, NULL);
+ visit_free(v);
+ }
}
The new code closely resembles code for a command with arguments.
Differences:
- the visit of the argument and its cleanup struct don't visit any
members (because there are none).
- the visit of the argument struct and its cleanup are conditional.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-09-12 13:19:08 +04:00
|
|
|
|
2015-06-27 17:49:34 +02:00
|
|
|
ret += mcgen('''
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-13 17:25:50 +01:00
|
|
|
}
|
2015-06-27 17:49:34 +02:00
|
|
|
''')
|
2011-07-19 14:50:42 -05:00
|
|
|
return ret
|
|
|
|
|
|
2015-09-16 13:06:16 +02:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def gen_register_command(name: str,
|
2021-03-18 16:55:17 +01:00
|
|
|
features: List[QAPISchemaFeature],
|
2020-10-09 12:15:44 -04:00
|
|
|
success_response: bool,
|
|
|
|
|
allow_oob: bool,
|
|
|
|
|
allow_preconfig: bool,
|
|
|
|
|
coroutine: bool) -> str:
|
2018-03-09 17:00:00 +08:00
|
|
|
options = []
|
|
|
|
|
|
2015-09-16 13:06:11 +02:00
|
|
|
if not success_response:
|
2018-03-09 17:00:00 +08:00
|
|
|
options += ['QCO_NO_SUCCESS_RESP']
|
|
|
|
|
if allow_oob:
|
|
|
|
|
options += ['QCO_ALLOW_OOB']
|
2018-05-11 18:51:43 +02:00
|
|
|
if allow_preconfig:
|
|
|
|
|
options += ['QCO_ALLOW_PRECONFIG']
|
2020-10-05 17:58:49 +02:00
|
|
|
if coroutine:
|
|
|
|
|
options += ['QCO_COROUTINE']
|
2018-03-09 17:00:00 +08:00
|
|
|
|
2015-09-16 13:06:11 +02:00
|
|
|
ret = mcgen('''
|
2017-03-15 13:57:35 +01:00
|
|
|
qmp_register_command(cmds, "%(name)s",
|
2021-10-28 12:25:17 +02:00
|
|
|
qmp_marshal_%(c_name)s, %(opts)s, %(feats)s);
|
2011-07-19 14:50:42 -05:00
|
|
|
''',
|
2015-09-16 13:06:16 +02:00
|
|
|
name=name, c_name=c_name(name),
|
2021-10-28 12:25:17 +02:00
|
|
|
opts=' | '.join(options) or 0,
|
2025-02-05 12:35:49 +00:00
|
|
|
feats=gen_features(features))
|
2015-09-16 13:06:11 +02:00
|
|
|
return ret
|
|
|
|
|
|
2015-09-16 13:06:16 +02:00
|
|
|
|
qapi: Generate separate .h, .c for each module
Our qapi-schema.json is composed of modules connected by include
directives, but the generated code is monolithic all the same: one
qapi-types.h with all the types, one qapi-visit.h with all the
visitors, and so forth. These monolithic headers get included all
over the place. In my "build everything" tree, adding a QAPI type
recompiles about 4800 out of 5100 objects.
We wouldn't write such monolithic headers by hand. It stands to
reason that we shouldn't generate them, either.
Split up generated qapi-types.h to mirror the schema's modular
structure: one header per module. Name the main module's header
qapi-types.h, and sub-module D/B.json's header D/qapi-types-B.h.
Mirror the schema's includes in the headers, so that qapi-types.h gets
you everything exactly as before. If you need less, you can include
one or more of the sub-module headers. To be exploited shortly.
Split up qapi-types.c, qapi-visit.h, qapi-visit.c, qmp-commands.h,
qmp-commands.c, qapi-event.h, qapi-event.c the same way.
qmp-introspect.h, qmp-introspect.c and qapi.texi remain monolithic.
The split of qmp-commands.c duplicates static helper function
qmp_marshal_output_str() in qapi-commands-char.c and
qapi-commands-misc.c. This happens when commands returning the same
type occur in multiple modules. Not worth avoiding.
Since I'm going to rename qapi-event.[ch] to qapi-events.[ch], and
qmp-commands.[ch] to qapi-commands.[ch], name the shards that way
already, to reduce churn. This requires temporary hacks in
commands.py and events.py. Similarly, c_name() must temporarily
be taught to munge '/' in common.py. They'll go away with the rename.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180211093607.27351-23-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: declare a dummy variable in each .c file, to shut up OSX
toolchain warnings about empty .o files, including hacking c_name()]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-02-11 10:36:00 +01:00
|
|
|
class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
|
2022-01-26 17:11:26 +01:00
|
|
|
def __init__(self, prefix: str, gen_tracing: bool):
|
2020-03-04 16:59:31 +01:00
|
|
|
super().__init__(
|
|
|
|
|
prefix, 'qapi-commands',
|
2022-01-26 17:11:26 +01:00
|
|
|
' * Schema-defined QAPI/QMP commands', None, __doc__,
|
|
|
|
|
gen_tracing=gen_tracing)
|
|
|
|
|
self._gen_tracing = gen_tracing
|
qapi: Generate separate .h, .c for each module
Our qapi-schema.json is composed of modules connected by include
directives, but the generated code is monolithic all the same: one
qapi-types.h with all the types, one qapi-visit.h with all the
visitors, and so forth. These monolithic headers get included all
over the place. In my "build everything" tree, adding a QAPI type
recompiles about 4800 out of 5100 objects.
We wouldn't write such monolithic headers by hand. It stands to
reason that we shouldn't generate them, either.
Split up generated qapi-types.h to mirror the schema's modular
structure: one header per module. Name the main module's header
qapi-types.h, and sub-module D/B.json's header D/qapi-types-B.h.
Mirror the schema's includes in the headers, so that qapi-types.h gets
you everything exactly as before. If you need less, you can include
one or more of the sub-module headers. To be exploited shortly.
Split up qapi-types.c, qapi-visit.h, qapi-visit.c, qmp-commands.h,
qmp-commands.c, qapi-event.h, qapi-event.c the same way.
qmp-introspect.h, qmp-introspect.c and qapi.texi remain monolithic.
The split of qmp-commands.c duplicates static helper function
qmp_marshal_output_str() in qapi-commands-char.c and
qapi-commands-misc.c. This happens when commands returning the same
type occur in multiple modules. Not worth avoiding.
Since I'm going to rename qapi-event.[ch] to qapi-events.[ch], and
qmp-commands.[ch] to qapi-commands.[ch], name the shards that way
already, to reduce churn. This requires temporary hacks in
commands.py and events.py. Similarly, c_name() must temporarily
be taught to munge '/' in common.py. They'll go away with the rename.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180211093607.27351-23-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: declare a dummy variable in each .c file, to shut up OSX
toolchain warnings about empty .o files, including hacking c_name()]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-02-11 10:36:00 +01:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def _begin_user_module(self, name: str) -> None:
|
2018-02-11 10:36:01 +01:00
|
|
|
commands = self._module_basename('qapi-commands', name)
|
|
|
|
|
types = self._module_basename('qapi-types', name)
|
|
|
|
|
visit = self._module_basename('qapi-visit', name)
|
2018-02-26 13:50:08 -06:00
|
|
|
self._genc.add(mcgen('''
|
2016-02-08 08:36:46 -07:00
|
|
|
#include "qemu/osdep.h"
|
qapi: Implement deprecated-output=hide for QMP command results
This policy suppresses deprecated bits in output, and thus permits
"testing the future". Implement it for QMP command results. Example:
when QEMU is run with -compat deprecated-output=hide, then
{"execute": "query-cpus-fast"}
yields
{"return": [{"thread-id": 9805, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
instead of
{"return": [{"arch": "x86", "thread-id": 22436, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
Note the suppression of deprecated member "arch".
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20210318155519.1224118-4-armbru@redhat.com>
2021-03-18 16:55:11 +01:00
|
|
|
#include "qapi/compat-policy.h"
|
2015-04-02 14:52:55 +02:00
|
|
|
#include "qapi/visitor.h"
|
2024-11-18 16:12:34 +01:00
|
|
|
#include "qobject/qdict.h"
|
2015-04-02 14:52:55 +02:00
|
|
|
#include "qapi/dealloc-visitor.h"
|
2018-02-01 12:18:31 +01:00
|
|
|
#include "qapi/error.h"
|
2018-02-11 10:36:01 +01:00
|
|
|
#include "%(visit)s.h"
|
|
|
|
|
#include "%(commands)s.h"
|
2015-04-02 14:52:55 +02:00
|
|
|
''',
|
2018-02-11 10:36:01 +01:00
|
|
|
commands=commands, visit=visit))
|
2022-01-26 17:11:26 +01:00
|
|
|
|
|
|
|
|
if self._gen_tracing and commands != 'qapi-commands':
|
|
|
|
|
self._genc.add(mcgen('''
|
2024-11-18 16:12:34 +01:00
|
|
|
#include "qobject/qjson.h"
|
2022-01-26 17:11:26 +01:00
|
|
|
#include "trace/trace-%(nm)s_trace_events.h"
|
|
|
|
|
''',
|
|
|
|
|
nm=c_name(commands, protect=False)))
|
|
|
|
|
# We use c_name(commands, protect=False) to turn '-' into '_', to
|
|
|
|
|
# match .underscorify() in trace/meson.build
|
|
|
|
|
|
2018-02-26 13:50:08 -06:00
|
|
|
self._genh.add(mcgen('''
|
2018-02-11 10:36:01 +01:00
|
|
|
#include "%(types)s.h"
|
2015-04-02 14:52:55 +02:00
|
|
|
|
|
|
|
|
''',
|
2018-02-11 10:36:01 +01:00
|
|
|
types=types))
|
2018-02-26 13:50:08 -06:00
|
|
|
|
2021-02-01 14:37:44 -05:00
|
|
|
def visit_begin(self, schema: QAPISchema) -> None:
|
2021-02-01 14:37:40 -05:00
|
|
|
self._add_module('./init', ' * QAPI Commands initialization')
|
2019-11-20 19:25:48 +01:00
|
|
|
self._genh.add(mcgen('''
|
2024-11-18 16:12:35 +01:00
|
|
|
#include "qapi/qmp-registry.h"
|
2019-11-20 19:25:48 +01:00
|
|
|
|
qapi: Generate separate .h, .c for each module
Our qapi-schema.json is composed of modules connected by include
directives, but the generated code is monolithic all the same: one
qapi-types.h with all the types, one qapi-visit.h with all the
visitors, and so forth. These monolithic headers get included all
over the place. In my "build everything" tree, adding a QAPI type
recompiles about 4800 out of 5100 objects.
We wouldn't write such monolithic headers by hand. It stands to
reason that we shouldn't generate them, either.
Split up generated qapi-types.h to mirror the schema's modular
structure: one header per module. Name the main module's header
qapi-types.h, and sub-module D/B.json's header D/qapi-types-B.h.
Mirror the schema's includes in the headers, so that qapi-types.h gets
you everything exactly as before. If you need less, you can include
one or more of the sub-module headers. To be exploited shortly.
Split up qapi-types.c, qapi-visit.h, qapi-visit.c, qmp-commands.h,
qmp-commands.c, qapi-event.h, qapi-event.c the same way.
qmp-introspect.h, qmp-introspect.c and qapi.texi remain monolithic.
The split of qmp-commands.c duplicates static helper function
qmp_marshal_output_str() in qapi-commands-char.c and
qapi-commands-misc.c. This happens when commands returning the same
type occur in multiple modules. Not worth avoiding.
Since I'm going to rename qapi-event.[ch] to qapi-events.[ch], and
qmp-commands.[ch] to qapi-commands.[ch], name the shards that way
already, to reduce churn. This requires temporary hacks in
commands.py and events.py. Similarly, c_name() must temporarily
be taught to munge '/' in common.py. They'll go away with the rename.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180211093607.27351-23-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: declare a dummy variable in each .c file, to shut up OSX
toolchain warnings about empty .o files, including hacking c_name()]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-02-11 10:36:00 +01:00
|
|
|
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
|
|
|
|
|
''',
|
2020-03-04 16:59:32 +01:00
|
|
|
c_prefix=c_name(self._prefix, protect=False)))
|
2021-02-01 14:37:44 -05:00
|
|
|
self._genc.add(mcgen('''
|
2019-11-20 19:25:48 +01:00
|
|
|
#include "qemu/osdep.h"
|
|
|
|
|
#include "%(prefix)sqapi-commands.h"
|
|
|
|
|
#include "%(prefix)sqapi-init-commands.h"
|
2025-02-05 12:35:50 +00:00
|
|
|
#include "%(prefix)sqapi-features.h"
|
2021-02-01 14:37:44 -05:00
|
|
|
|
|
|
|
|
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
|
|
|
|
|
{
|
|
|
|
|
QTAILQ_INIT(cmds);
|
|
|
|
|
|
2019-11-20 19:25:48 +01:00
|
|
|
''',
|
2021-02-01 14:37:44 -05:00
|
|
|
prefix=self._prefix,
|
|
|
|
|
c_prefix=c_name(self._prefix, protect=False)))
|
|
|
|
|
|
|
|
|
|
def visit_end(self) -> None:
|
|
|
|
|
with self._temp_module('./init'):
|
|
|
|
|
self._genc.add(mcgen('''
|
|
|
|
|
}
|
|
|
|
|
'''))
|
2018-02-26 13:50:08 -06:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def visit_command(self,
|
|
|
|
|
name: str,
|
2021-02-01 14:37:46 -05:00
|
|
|
info: Optional[QAPISourceInfo],
|
2021-08-04 12:30:57 +04:00
|
|
|
ifcond: QAPISchemaIfCond,
|
2020-10-09 12:15:44 -04:00
|
|
|
features: List[QAPISchemaFeature],
|
|
|
|
|
arg_type: Optional[QAPISchemaObjectType],
|
|
|
|
|
ret_type: Optional[QAPISchemaType],
|
|
|
|
|
gen: bool,
|
|
|
|
|
success_response: bool,
|
|
|
|
|
boxed: bool,
|
|
|
|
|
allow_oob: bool,
|
|
|
|
|
allow_preconfig: bool,
|
|
|
|
|
coroutine: bool) -> None:
|
2018-02-26 13:50:08 -06:00
|
|
|
if not gen:
|
|
|
|
|
return
|
2021-02-01 14:37:44 -05:00
|
|
|
with ifcontext(ifcond, self._genh, self._genc):
|
2022-10-13 10:50:49 +02:00
|
|
|
self._genh.add(gen_command_decl(name, arg_type, boxed,
|
|
|
|
|
ret_type, coroutine))
|
|
|
|
|
self._genh.add(gen_marshal_decl(name, coroutine))
|
2022-01-26 17:11:26 +01:00
|
|
|
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type,
|
2022-10-13 10:50:49 +02:00
|
|
|
self._gen_tracing, coroutine))
|
2022-01-26 17:11:26 +01:00
|
|
|
if self._gen_tracing:
|
|
|
|
|
self._gen_trace_events.add(gen_trace(name))
|
2021-02-01 14:37:44 -05:00
|
|
|
with self._temp_module('./init'):
|
|
|
|
|
with ifcontext(ifcond, self._genh, self._genc):
|
2021-03-18 16:55:17 +01:00
|
|
|
self._genc.add(gen_register_command(
|
|
|
|
|
name, features, success_response, allow_oob,
|
|
|
|
|
allow_preconfig, coroutine))
|
2018-02-26 13:50:08 -06:00
|
|
|
|
2018-02-26 13:39:37 -06:00
|
|
|
|
2020-10-09 12:15:44 -04:00
|
|
|
def gen_commands(schema: QAPISchema,
|
|
|
|
|
output_dir: str,
|
2022-01-26 17:11:26 +01:00
|
|
|
prefix: str,
|
|
|
|
|
gen_tracing: bool) -> None:
|
|
|
|
|
vis = QAPISchemaGenCommandVisitor(prefix, gen_tracing)
|
2018-02-26 13:39:37 -06:00
|
|
|
schema.visit(vis)
|
2018-02-26 13:50:08 -06:00
|
|
|
vis.write(output_dir)
|