QAPI patches patches for 2022-01-27

-----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmHyqgcSHGFybWJydUBy
 ZWRoYXQuY29tAAoJEDhwtADrkYZT3A0P/3FpDflF8zwLlKEuTaLdprUCowEjouTq
 8lIKE1La0NK+cvuH0lDMSVLitqdk57WzopLvoSU7sSUXtvb9oJuJNnBPiCXVU8Ou
 uapzUnYxSM0KF3ehRtH+eOefyQ9MWpdzfzImmR6DDFjf1Ff03g4dNW9qrNUbMl9D
 Oy0ZUMsTms3OtXqkKeg9giAbDOARYgHcHcQEkm41xp28ORMUJvORiP6HV7CTWF4Q
 M2fLNT2cOtKZcby+YBU1HUYARFZuAII5718OD4YDWcv+ADMpwp0yCl7BRtLHDDNu
 cSm+6KNF+r8SfvwyLVHIvA1W5jP32lzJ/VpgK+2N5mWw8wKAgGzvIZHL8i5rE+b+
 NHXv3bFburrBAM/nzHntbFxzLCl5ysgWvQb32Uc/sDd6KKOwHqf1NqoBsn1POn3D
 AeQCBaXGlgBpKmeHeU99GnmgV5UKputHahAQqTzslSy8OKkEK9P0GTyEwl9KUmgJ
 g8rY2fhsSP8j+dwSRIhHE6B3WDVJ+bxUMUg0Io3BZjAP7SQosoUUYZYhOubTn4B4
 6usz2+QVoJePokC7GFl+LdyO5NOIfxvuRkCH9nw3q5eU5WYskvrh/vBvQ8H9UAvP
 NBeFHdKwTm82ZGTKz18w2/9imyy5NaAZGte0S3isDOLdGdUqmDxUC0hsHuibrSq2
 hjsQSYrsGS5C
 =gEIj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2022-01-27-v2' into staging

QAPI patches patches for 2022-01-27

# gpg: Signature made Thu 27 Jan 2022 14:19:51 GMT
# gpg:                using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg:                issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2022-01-27-v2:
  qapi: generate trace events by default
  meson: document why we don't generate trace events for tests/ and qga/
  docs/qapi-code-gen: update to cover trace events code generation
  meson: generate trace events for qmp commands
  qapi/commands: Optionally generate trace for QMP commands
  qapi/commands: refactor error handling code
  qapi/gen: Add FOO.trace-events output module
  schemas: add missing vim modeline

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
staging
Peter Maydell 2022-01-27 15:45:13 +00:00
commit cfe63e46be
14 changed files with 190 additions and 27 deletions

View File

@ -1630,6 +1630,9 @@ The following files are generated:
``$(prefix)qapi-commands.h``
Function prototypes for the QMP commands specified in the schema
``$(prefix)qapi-commands.trace-events``
Trace event declarations, see :ref:`tracing`.
``$(prefix)qapi-init-commands.h``
Command initialization prototype
@ -1650,6 +1653,13 @@ Example::
void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp);
#endif /* EXAMPLE_QAPI_COMMANDS_H */
$ cat qapi-generated/example-qapi-commands.trace-events
# AUTOMATICALLY GENERATED, DO NOT MODIFY
qmp_enter_my_command(const char *json) "%s"
qmp_exit_my_command(const char *result, bool succeeded) "%s %d"
$ cat qapi-generated/example-qapi-commands.c
[Uninteresting stuff omitted...]
@ -1689,14 +1699,27 @@ Example::
goto out;
}
if (trace_event_get_state_backends(TRACE_QMP_ENTER_MY_COMMAND)) {
g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
trace_qmp_enter_my_command(req_json->str);
}
retval = qmp_my_command(arg.arg1, &err);
error_propagate(errp, err);
if (err) {
trace_qmp_exit_my_command(error_get_pretty(err), false);
error_propagate(errp, err);
goto out;
}
qmp_marshal_output_UserDefOne(retval, ret, errp);
if (trace_event_get_state_backends(TRACE_QMP_EXIT_MY_COMMAND)) {
g_autoptr(GString) ret_json = qobject_to_json(*ret);
trace_qmp_exit_my_command(ret_json->str, true);
}
out:
visit_free(v);
v = qapi_dealloc_visitor_new();

View File

@ -1,3 +1,5 @@
.. _tracing:
=======
Tracing
=======

View File

@ -41,6 +41,7 @@ qemu_icondir = get_option('datadir') / 'icons'
config_host_data = configuration_data()
genh = []
qapi_trace_events = []
target_dirs = config_host['TARGET_DIRS'].split()
have_linux_user = false
@ -2557,6 +2558,8 @@ if 'CONFIG_VHOST_USER' in config_host
vhost_user = libvhost_user.get_variable('vhost_user_dep')
endif
# NOTE: the trace/ subdirectory needs the qapi_trace_events variable
# that is filled in by qapi/.
subdir('qapi')
subdir('qobject')
subdir('stubs')

View File

@ -1,4 +1,5 @@
# -*- mode: python -*-
# vim: filetype=python
#
# Copyright (C) 2015-2019 Zoltán Kővágó <DirtY.iCE.hu@gmail.com>
#

View File

@ -1,4 +1,5 @@
# -*- Mode: Python -*-
# vim: filetype=python
##
# = Compatibility policy

View File

@ -114,6 +114,7 @@ foreach module : qapi_all_modules
'qapi-events-@0@.h'.format(module),
'qapi-commands-@0@.c'.format(module),
'qapi-commands-@0@.h'.format(module),
'qapi-commands-@0@.trace-events'.format(module),
]
endif
if module.endswith('-target')
@ -137,6 +138,9 @@ foreach output : qapi_util_outputs
if output.endswith('.h')
genh += qapi_files[i]
endif
if output.endswith('.trace-events')
qapi_trace_events += qapi_files[i]
endif
util_ss.add(qapi_files[i])
i = i + 1
endforeach
@ -145,6 +149,9 @@ foreach output : qapi_specific_outputs + qapi_nonmodule_outputs
if output.endswith('.h')
genh += qapi_files[i]
endif
if output.endswith('.trace-events')
qapi_trace_events += qapi_files[i]
endif
specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: qapi_files[i])
i = i + 1
endforeach

View File

@ -1,4 +1,5 @@
# -*- Mode: Python -*-
# vim: filetype=python
#
##

View File

@ -1,4 +1,5 @@
# -*- mode: python -*-
# vim: filetype=python
#
# Copyright (C) 2011-2016 Lluís Vilanova <vilanova@ac.upc.edu>
#

View File

@ -15,10 +15,18 @@ qga_qapi_outputs = [
'qga-qapi-visit.h',
]
# Problem: to generate trace events, we'd have to add the .trace-events
# file to qapi_trace_events like we do in qapi/meson.build. Since
# qapi_trace_events is used by trace/meson.build, we'd have to move
# subdir('qga') above subdir('trace') in the top-level meson.build.
# Can't, because it would break the dependency of qga on qemuutil (which
# depends on trace_ss). Not worth solving now; simply suppress trace
# event generation instead.
qga_qapi_files = custom_target('QGA QAPI files',
output: qga_qapi_outputs,
input: 'qapi-schema.json',
command: [ qapi_gen, '-o', 'qga', '-p', 'qga-', '@INPUT0@' ],
command: [ qapi_gen, '-o', 'qga', '-p', 'qga-', '@INPUT0@',
'--suppress-tracing' ],
depend_files: qapi_gen_depends)
qga_ss = ss.source_set()

View File

@ -53,7 +53,8 @@ def gen_command_decl(name: str,
def gen_call(name: str,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool,
ret_type: Optional[QAPISchemaType]) -> str:
ret_type: Optional[QAPISchemaType],
gen_tracing: bool) -> str:
ret = ''
argstr = ''
@ -71,21 +72,67 @@ def gen_call(name: str,
if ret_type:
lhs = 'retval = '
ret = mcgen('''
name = c_name(name)
upper = name.upper()
%(lhs)sqmp_%(c_name)s(%(args)s&err);
error_propagate(errp, err);
''',
c_name=c_name(name), args=argstr, lhs=lhs)
if ret_type:
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);
}
''',
upper=upper, name=name)
ret += mcgen('''
%(lhs)sqmp_%(name)s(%(args)s&err);
''',
name=name, args=argstr, lhs=lhs)
ret += mcgen('''
if (err) {
''')
if gen_tracing:
ret += mcgen('''
trace_qmp_exit_%(name)s(error_get_pretty(err), false);
''',
name=name)
ret += mcgen('''
error_propagate(errp, err);
goto out;
}
''')
if ret_type:
ret += mcgen('''
qmp_marshal_output_%(c_name)s(retval, ret, errp);
''',
c_name=ret_type.c_name())
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);
}
''',
upper=upper, name=name)
else:
ret += mcgen('''
trace_qmp_exit_%(name)s("{}", true);
''',
name=name)
return ret
@ -122,10 +169,19 @@ def gen_marshal_decl(name: str) -> str:
proto=build_marshal_proto(name))
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))
def gen_marshal(name: str,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool,
ret_type: Optional[QAPISchemaType]) -> str:
ret_type: Optional[QAPISchemaType],
gen_tracing: bool) -> str:
have_args = boxed or (arg_type and not arg_type.is_empty())
if have_args:
assert arg_type is not None
@ -180,7 +236,7 @@ def gen_marshal(name: str,
}
''')
ret += gen_call(name, arg_type, boxed, ret_type)
ret += gen_call(name, arg_type, boxed, ret_type, gen_tracing)
ret += mcgen('''
@ -238,11 +294,13 @@ def gen_register_command(name: str,
class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
def __init__(self, prefix: str):
def __init__(self, prefix: str, gen_tracing: bool):
super().__init__(
prefix, 'qapi-commands',
' * Schema-defined QAPI/QMP commands', None, __doc__)
' * Schema-defined QAPI/QMP commands', None, __doc__,
gen_tracing=gen_tracing)
self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
self._gen_tracing = gen_tracing
def _begin_user_module(self, name: str) -> None:
self._visited_ret_types[self._genc] = set()
@ -261,6 +319,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
''',
commands=commands, visit=visit))
if self._gen_tracing and commands != 'qapi-commands':
self._genc.add(mcgen('''
#include "qapi/qmp/qjson.h"
#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
self._genh.add(mcgen('''
#include "%(types)s.h"
@ -322,7 +390,10 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
self._genh.add(gen_marshal_decl(name))
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type,
self._gen_tracing))
if self._gen_tracing:
self._gen_trace_events.add(gen_trace(name))
with self._temp_module('./init'):
with ifcontext(ifcond, self._genh, self._genc):
self._genc.add(gen_register_command(
@ -332,7 +403,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
def gen_commands(schema: QAPISchema,
output_dir: str,
prefix: str) -> None:
vis = QAPISchemaGenCommandVisitor(prefix)
prefix: str,
gen_tracing: bool) -> None:
vis = QAPISchemaGenCommandVisitor(prefix, gen_tracing)
schema.visit(vis)
vis.write(output_dir)

View File

@ -192,6 +192,11 @@ class QAPIGenH(QAPIGenC):
return guardend(self.fname)
class QAPIGenTrace(QAPIGen):
def _top(self) -> str:
return super()._top() + '# AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n'
@contextmanager
def ifcontext(ifcond: QAPISchemaIfCond, *args: QAPIGenCCode) -> Iterator[None]:
"""
@ -244,15 +249,18 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
what: str,
user_blurb: str,
builtin_blurb: Optional[str],
pydoc: str):
pydoc: str,
gen_tracing: bool = False):
self._prefix = prefix
self._what = what
self._user_blurb = user_blurb
self._builtin_blurb = builtin_blurb
self._pydoc = pydoc
self._current_module: Optional[str] = None
self._module: Dict[str, Tuple[QAPIGenC, QAPIGenH]] = {}
self._module: Dict[str, Tuple[QAPIGenC, QAPIGenH,
Optional[QAPIGenTrace]]] = {}
self._main_module: Optional[str] = None
self._gen_tracing = gen_tracing
@property
def _genc(self) -> QAPIGenC:
@ -264,6 +272,14 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
assert self._current_module is not None
return self._module[self._current_module][1]
@property
def _gen_trace_events(self) -> QAPIGenTrace:
assert self._gen_tracing
assert self._current_module is not None
gent = self._module[self._current_module][2]
assert gent is not None
return gent
@staticmethod
def _module_dirname(name: str) -> str:
if QAPISchemaModule.is_user_module(name):
@ -293,7 +309,12 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
basename = self._module_filename(self._what, name)
genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
self._module[name] = (genc, genh)
gent: Optional[QAPIGenTrace] = None
if self._gen_tracing:
gent = QAPIGenTrace(basename + '.trace-events')
self._module[name] = (genc, genh, gent)
self._current_module = name
@contextmanager
@ -304,11 +325,13 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
self._current_module = old_module
def write(self, output_dir: str, opt_builtins: bool = False) -> None:
for name, (genc, genh) in self._module.items():
for name, (genc, genh, gent) in self._module.items():
if QAPISchemaModule.is_builtin_module(name) and not opt_builtins:
continue
genc.write(output_dir)
genh.write(output_dir)
if gent is not None:
gent.write(output_dir)
def _begin_builtin_module(self) -> None:
pass

View File

@ -32,7 +32,8 @@ def generate(schema_file: str,
output_dir: str,
prefix: str,
unmask: bool = False,
builtins: bool = False) -> None:
builtins: bool = False,
gen_tracing: bool = False) -> None:
"""
Generate C code for the given schema into the target directory.
@ -49,7 +50,7 @@ def generate(schema_file: str,
schema = QAPISchema(schema_file)
gen_types(schema, output_dir, prefix, builtins)
gen_visit(schema, output_dir, prefix, builtins)
gen_commands(schema, output_dir, prefix)
gen_commands(schema, output_dir, prefix, gen_tracing)
gen_events(schema, output_dir, prefix)
gen_introspect(schema, output_dir, prefix, unmask)
@ -74,6 +75,12 @@ def main() -> int:
parser.add_argument('-u', '--unmask-non-abi-names', action='store_true',
dest='unmask',
help="expose non-ABI names in introspection")
# Option --suppress-tracing exists so we can avoid solving build system
# problems. TODO Drop it when we no longer need it.
parser.add_argument('--suppress-tracing', action='store_true',
help="suppress adding trace events to qmp marshals")
parser.add_argument('schema', action='store')
args = parser.parse_args()
@ -88,7 +95,8 @@ def main() -> int:
output_dir=args.output_dir,
prefix=args.prefix,
unmask=args.unmask,
builtins=args.builtins)
builtins=args.builtins,
gen_tracing=not args.suppress_tracing)
except QAPIError as err:
print(f"{sys.argv[0]}: {str(err)}", file=sys.stderr)
return 1

View File

@ -31,13 +31,21 @@ test_qapi_outputs = [
'test-qapi-visit.h',
]
# Problem: to generate trace events, we'd have to add the .trace-events
# file to qapi_trace_events like we do in qapi/meson.build. Since
# qapi_trace_events is used by trace/meson.build, we'd have to move
# subdir('tests') above subdir('trace') in the top-level meson.build.
# Can't, because it would break the dependency of qga on qemuutil (which
# depends on trace_ss). Not worth solving now; simply suppress trace
# event generation instead.
test_qapi_files = custom_target('Test QAPI files',
output: test_qapi_outputs,
input: files('qapi-schema/qapi-schema-test.json',
'qapi-schema/include/sub-module.json',
'qapi-schema/sub-sub-module.json'),
command: [ qapi_gen, '-o', meson.current_build_dir(),
'-b', '-p', 'test-', '@INPUT0@' ],
'-b', '-p', 'test-', '@INPUT0@',
'--suppress-tracing' ],
depend_files: qapi_gen_depends)
# meson doesn't like generated output in other directories

View File

@ -2,10 +2,15 @@
specific_ss.add(files('control-target.c'))
trace_events_files = []
foreach dir : [ '.' ] + trace_events_subdirs
trace_events_file = meson.project_source_root() / dir / 'trace-events'
foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events
if item in qapi_trace_events
trace_events_file = item
group_name = item.full_path().split('/')[-1].underscorify()
else
trace_events_file = meson.project_source_root() / item / 'trace-events'
group_name = item == '.' ? 'root' : item.underscorify()
endif
trace_events_files += [ trace_events_file ]
group_name = dir == '.' ? 'root' : dir.underscorify()
group = '--group=' + group_name
fmt = '@0@-' + group_name + '.@1@'