qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qapi: Add 'if' to implicit struct members

The generated code is for now *unconditional*. Later patches generate
the conditionals.

Note that union discriminators may not have 'if' conditionals.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20181213123724.4866-14-marcandre.lureau@redhat.com>
Message-Id: <20181213123724.4866-15-marcandre.lureau@redhat.com>
[Patches squashed, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>

authored by

Marc-André Lureau and committed by
Markus Armbruster
ccadd6bc 87adbbff

+56 -10
+10
docs/devel/qapi-code-gen.txt
··· 752 752 #endif /* defined(HAVE_BAR) */ 753 753 #endif /* defined(CONFIG_FOO) */ 754 754 755 + Where a member can be defined with a single string value for its type, 756 + it is also possible to supply a dictionary instead with both 'type' 757 + and 'if' keys. (TODO: union and alternate) 758 + 759 + Example: a conditional 'bar' member 760 + 761 + { 'struct': 'IfStruct', 'data': 762 + { 'foo': 'int', 763 + 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } } 764 + 755 765 An enum value can be replaced by a dictionary with a 'name' and a 'if' 756 766 key. 757 767
+11 -7
scripts/qapi/common.py
··· 705 705 # Todo: allow dictionaries to represent default values of 706 706 # an optional argument. 707 707 check_known_keys(info, "member '%s' of %s" % (key, source), 708 - arg, ['type'], []) 708 + arg, ['type'], ['if']) 709 709 check_type(info, "Member '%s' of %s" % (key, source), 710 710 arg['type'], allow_array=True, 711 711 allow_metas=['built-in', 'union', 'alternate', 'struct', ··· 784 784 "Discriminator '%s' is not a member of base " 785 785 "struct '%s'" 786 786 % (discriminator, base)) 787 + if discriminator_value.get('if'): 788 + raise QAPISemError(info, 'The discriminator %s.%s for union %s ' 789 + 'must not be conditional' % 790 + (base, discriminator, name)) 787 791 enum_define = enum_types.get(discriminator_value['type']) 788 792 allow_metas = ['struct'] 789 793 # Do not allow string discriminator ··· 1412 1416 1413 1417 1414 1418 class QAPISchemaObjectTypeMember(QAPISchemaMember): 1415 - def __init__(self, name, typ, optional): 1416 - QAPISchemaMember.__init__(self, name) 1419 + def __init__(self, name, typ, optional, ifcond=None): 1420 + QAPISchemaMember.__init__(self, name, ifcond) 1417 1421 assert isinstance(typ, str) 1418 1422 assert isinstance(optional, bool) 1419 1423 self._type_name = typ ··· 1727 1731 name, info, doc, ifcond, 1728 1732 self._make_enum_members(data), prefix)) 1729 1733 1730 - def _make_member(self, name, typ, info): 1734 + def _make_member(self, name, typ, ifcond, info): 1731 1735 optional = False 1732 1736 if name.startswith('*'): 1733 1737 name = name[1:] ··· 1735 1739 if isinstance(typ, list): 1736 1740 assert len(typ) == 1 1737 1741 typ = self._make_array_type(typ[0], info) 1738 - return QAPISchemaObjectTypeMember(name, typ, optional) 1742 + return QAPISchemaObjectTypeMember(name, typ, optional, ifcond) 1739 1743 1740 1744 def _make_members(self, data, info): 1741 - return [self._make_member(key, value['type'], info) 1745 + return [self._make_member(key, value['type'], value.get('if'), info) 1742 1746 for (key, value) in data.items()] 1743 1747 1744 1748 def _def_struct_type(self, expr, info, doc): ··· 1759 1763 typ = self._make_array_type(typ[0], info) 1760 1764 typ = self._make_implicit_object_type( 1761 1765 typ, info, None, self.lookup_type(typ), 1762 - 'wrapper', [self._make_member('data', typ, info)]) 1766 + 'wrapper', [self._make_member('data', typ, None, info)]) 1763 1767 return QAPISchemaObjectTypeVariant(case, typ) 1764 1768 1765 1769 def _def_union_type(self, expr, info, doc):
+1
tests/Makefile.include
··· 409 409 qapi-schema += flat-union-int-branch.json 410 410 qapi-schema += flat-union-invalid-branch-key.json 411 411 qapi-schema += flat-union-invalid-discriminator.json 412 + qapi-schema += flat-union-invalid-if-discriminator.json 412 413 qapi-schema += flat-union-no-base.json 413 414 qapi-schema += flat-union-optional-discriminator.json 414 415 qapi-schema += flat-union-string-discriminator.json
+1
tests/qapi-schema/flat-union-invalid-if-discriminator.err
··· 1 + tests/qapi-schema/flat-union-invalid-if-discriminator.json:13: The discriminator TestBase.enum1 for union TestUnion must not be conditional
+1
tests/qapi-schema/flat-union-invalid-if-discriminator.exit
··· 1 + 1
+17
tests/qapi-schema/flat-union-invalid-if-discriminator.json
··· 1 + { 'enum': 'TestEnum', 2 + 'data': [ 'value1', 'value2' ] } 3 + 4 + { 'struct': 'TestBase', 5 + 'data': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } } } 6 + 7 + { 'struct': 'TestTypeA', 8 + 'data': { 'string': 'str' } } 9 + 10 + { 'struct': 'TestTypeB', 11 + 'data': { 'integer': 'int' } } 12 + 13 + { 'union': 'TestUnion', 14 + 'base': 'TestBase', 15 + 'discriminator': 'enum1', 16 + 'data': { 'value1': 'TestTypeA', 17 + 'value2': 'TestTypeB' } }
tests/qapi-schema/flat-union-invalid-if-discriminator.out

This is a binary file and will not be displayed.

+9 -3
tests/qapi-schema/qapi-schema-test.json
··· 201 201 202 202 # test 'if' condition handling 203 203 204 - { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' }, 204 + { 'struct': 'TestIfStruct', 'data': 205 + { 'foo': 'int', 206 + 'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} }, 205 207 'if': 'defined(TEST_IF_STRUCT)' } 206 208 207 209 { 'enum': 'TestIfEnum', 'data': ··· 220 222 { 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' }, 221 223 'if': 'defined(TEST_IF_ALT)' } 222 224 223 - { 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' }, 225 + { 'command': 'TestIfCmd', 'data': 226 + { 'foo': 'TestIfStruct', 227 + 'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } }, 224 228 'returns': 'UserDefThree', 225 229 'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] } 226 230 227 231 { 'command': 'TestCmdReturnDefThree', 'returns': 'UserDefThree' } 228 232 229 - { 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' }, 233 + { 'event': 'TestIfEvent', 'data': 234 + { 'foo': 'TestIfStruct', 235 + 'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_EVT_BAR)' } }, 230 236 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
+5
tests/qapi-schema/qapi-schema-test.out
··· 268 268 gen=True success_response=True boxed=False oob=False preconfig=False 269 269 object TestIfStruct 270 270 member foo: int optional=False 271 + member bar: int optional=False 272 + if ['defined(TEST_IF_STRUCT_BAR)'] 271 273 if ['defined(TEST_IF_STRUCT)'] 272 274 enum TestIfEnum 273 275 member foo ··· 304 306 object q_obj_TestIfCmd-arg 305 307 member foo: TestIfStruct optional=False 306 308 member bar: TestIfEnum optional=False 309 + if ['defined(TEST_IF_CMD_BAR)'] 307 310 if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] 308 311 command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree 309 312 gen=True success_response=True boxed=False oob=False preconfig=False ··· 312 315 gen=True success_response=True boxed=False oob=False preconfig=False 313 316 object q_obj_TestIfEvent-arg 314 317 member foo: TestIfStruct optional=False 318 + member bar: TestIfEnum optional=False 319 + if ['defined(TEST_IF_EVT_BAR)'] 315 320 if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)'] 316 321 event TestIfEvent q_obj_TestIfEvent-arg 317 322 boxed=False
+1
tests/qapi-schema/test-qapi.py
··· 39 39 for m in members: 40 40 print(' member %s: %s optional=%s' 41 41 % (m.name, m.type.name, m.optional)) 42 + self._print_if(m.ifcond, 8) 42 43 self._print_variants(variants) 43 44 self._print_if(ifcond) 44 45