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

qapi: Introduce a first class 'any' type

It's first class, because unlike '**', it actually works, i.e. doesn't
require 'gen': false.

'**' will go away next.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>

+171 -10
+1
docs/qapi-code-gen.txt
··· 158 158 size uint64_t like uint64_t, except StringInputVisitor 159 159 accepts size suffixes 160 160 bool bool JSON true or false 161 + any QObject * any JSON value 161 162 162 163 163 164 === Includes ===
+2
include/qapi/visitor-impl.h
··· 40 40 void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp); 41 41 void (*type_number)(Visitor *v, double *obj, const char *name, 42 42 Error **errp); 43 + void (*type_any)(Visitor *v, QObject **obj, const char *name, 44 + Error **errp); 43 45 44 46 /* May be NULL */ 45 47 void (*optional)(Visitor *v, bool *present, const char *name,
+1
include/qapi/visitor.h
··· 58 58 void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp); 59 59 void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp); 60 60 void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp); 61 + void visit_type_any(Visitor *v, QObject **obj, const char *name, Error **errp); 61 62 bool visit_start_union(Visitor *v, bool data_present, Error **errp); 62 63 void visit_end_union(Visitor *v, bool data_present, Error **errp); 63 64
+9
qapi/qapi-dealloc-visitor.c
··· 151 151 { 152 152 } 153 153 154 + static void qapi_dealloc_type_anything(Visitor *v, QObject **obj, 155 + const char *name, Error **errp) 156 + { 157 + if (obj) { 158 + qobject_decref(*obj); 159 + } 160 + } 161 + 154 162 static void qapi_dealloc_type_size(Visitor *v, uint64_t *obj, const char *name, 155 163 Error **errp) 156 164 { ··· 216 224 v->visitor.type_bool = qapi_dealloc_type_bool; 217 225 v->visitor.type_str = qapi_dealloc_type_str; 218 226 v->visitor.type_number = qapi_dealloc_type_number; 227 + v->visitor.type_any = qapi_dealloc_type_anything; 219 228 v->visitor.type_size = qapi_dealloc_type_size; 220 229 v->visitor.start_union = qapi_dealloc_start_union; 221 230
+6
qapi/qapi-visit-core.c
··· 260 260 v->type_number(v, obj, name, errp); 261 261 } 262 262 263 + void visit_type_any(Visitor *v, QObject **obj, const char *name, 264 + Error **errp) 265 + { 266 + v->type_any(v, obj, name, errp); 267 + } 268 + 263 269 void output_type_enum(Visitor *v, int *obj, const char * const strings[], 264 270 const char *kind, const char *name, 265 271 Error **errp)
+11
qapi/qmp-input-visitor.c
··· 286 286 } 287 287 } 288 288 289 + static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name, 290 + Error **errp) 291 + { 292 + QmpInputVisitor *qiv = to_qiv(v); 293 + QObject *qobj = qmp_input_get_object(qiv, name, true); 294 + 295 + qobject_incref(qobj); 296 + *obj = qobj; 297 + } 298 + 289 299 static void qmp_input_optional(Visitor *v, bool *present, const char *name, 290 300 Error **errp) 291 301 { ··· 329 339 v->visitor.type_bool = qmp_input_type_bool; 330 340 v->visitor.type_str = qmp_input_type_str; 331 341 v->visitor.type_number = qmp_input_type_number; 342 + v->visitor.type_any = qmp_input_type_any; 332 343 v->visitor.optional = qmp_input_optional; 333 344 v->visitor.get_next_type = qmp_input_get_next_type; 334 345
+9
qapi/qmp-output-visitor.c
··· 190 190 qmp_output_add(qov, name, qfloat_from_double(*obj)); 191 191 } 192 192 193 + static void qmp_output_type_any(Visitor *v, QObject **obj, const char *name, 194 + Error **errp) 195 + { 196 + QmpOutputVisitor *qov = to_qov(v); 197 + qobject_incref(*obj); 198 + qmp_output_add_obj(qov, name, *obj); 199 + } 200 + 193 201 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) 194 202 { 195 203 QObject *obj = qmp_output_first(qov); ··· 237 245 v->visitor.type_bool = qmp_output_type_bool; 238 246 v->visitor.type_str = qmp_output_type_str; 239 247 v->visitor.type_number = qmp_output_type_number; 248 + v->visitor.type_any = qmp_output_type_any; 240 249 241 250 QTAILQ_INIT(&v->stack); 242 251
+1
scripts/qapi-types.py
··· 327 327 fdecl.write(mcgen(''' 328 328 #include <stdbool.h> 329 329 #include <stdint.h> 330 + #include "qapi/qmp/qobject.h" 330 331 ''')) 331 332 332 333 schema = QAPISchema(input_file)
+6 -3
scripts/qapi.py
··· 33 33 'uint32': 'QTYPE_QINT', 34 34 'uint64': 'QTYPE_QINT', 35 35 'size': 'QTYPE_QINT', 36 + 'any': None, # any qtype_code possible, actually 36 37 } 37 38 38 39 # Whitelist of commands allowed to return a non-dictionary ··· 1102 1103 def _def_builtin_type(self, name, json_type, c_type, c_null): 1103 1104 self._def_entity(QAPISchemaBuiltinType(name, json_type, 1104 1105 c_type, c_null)) 1105 - if name != '**': 1106 - self._make_array_type(name) # TODO really needed? 1106 + self._make_array_type(name) # TODO really needed? 1107 1107 1108 1108 def _def_predefineds(self): 1109 1109 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'), ··· 1119 1119 ('uint64', 'int', 'uint64_t', '0'), 1120 1120 ('size', 'int', 'uint64_t', '0'), 1121 1121 ('bool', 'boolean', 'bool', 'false'), 1122 - ('**', 'value', None, None)]: 1122 + ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]: 1123 1123 self._def_builtin_type(*t) 1124 + self._entity_dict['**'] = self.lookup_type('any') # TODO drop this alias 1124 1125 1125 1126 def _make_implicit_enum_type(self, name, values): 1126 1127 name = name + 'Kind' ··· 1270 1271 def visit(self, visitor): 1271 1272 visitor.visit_begin(self) 1272 1273 for name in sorted(self._entity_dict.keys()): 1274 + if self._entity_dict[name].name != name: 1275 + continue # ignore alias TODO drop alias and remove 1273 1276 self._entity_dict[name].visit(visitor) 1274 1277 visitor.visit_end() 1275 1278
+2 -1
tests/Makefile
··· 239 239 args-array-empty.json args-array-unknown.json args-int.json \ 240 240 args-unknown.json args-member-unknown.json args-member-array.json \ 241 241 args-member-array-bad.json args-alternate.json args-union.json \ 242 + args-any.json \ 242 243 returns-array-bad.json returns-int.json returns-dict.json \ 243 244 returns-unknown.json returns-alternate.json returns-whitelist.json \ 244 245 missing-colon.json missing-comma-list.json missing-comma-object.json \ ··· 255 256 flat-union-invalid-branch-key.json flat-union-reverse-define.json \ 256 257 flat-union-string-discriminator.json union-base-no-discriminator.json \ 257 258 flat-union-bad-discriminator.json flat-union-bad-base.json \ 258 - flat-union-base-star.json \ 259 + flat-union-base-any.json \ 259 260 flat-union-array-branch.json flat-union-int-branch.json \ 260 261 flat-union-base-union.json flat-union-branch-clash.json \ 261 262 alternate-nested.json alternate-unknown.json alternate-clash.json \
+1
tests/qapi-schema/args-any.err
··· 1 + tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any'
+2
tests/qapi-schema/args-any.json
··· 1 + # we do not allow an 'any' argument 2 + { 'command': 'oops', 'data': 'any' }
+1
tests/qapi-schema/flat-union-base-any.err
··· 1 + tests/qapi-schema/flat-union-base-any.json:8: Base 'any' is not a valid struct
+1
tests/qapi-schema/flat-union-base-any.exit
··· 1 + 1
tests/qapi-schema/flat-union-base-any.out

This is a binary file and will not be displayed.

-1
tests/qapi-schema/flat-union-base-star.err
··· 1 - tests/qapi-schema/flat-union-base-star.json:8: Base '**' is not a valid struct
tests/qapi-schema/flat-union-base-star.exit tests/qapi-schema/args-any.exit
+1 -1
tests/qapi-schema/flat-union-base-star.json tests/qapi-schema/flat-union-base-any.json
··· 6 6 { 'struct': 'TestTypeB', 7 7 'data': { 'integer': 'int' } } 8 8 { 'union': 'TestUnion', 9 - 'base': '**', 9 + 'base': 'any', 10 10 'discriminator': 'enum1', 11 11 'data': { 'value1': 'TestTypeA', 12 12 'value2': 'TestTypeB' } }
tests/qapi-schema/flat-union-base-star.out tests/qapi-schema/args-any.out
+4 -1
tests/qapi-schema/qapi-schema-test.json
··· 78 78 'number': ['number'], 79 79 'boolean': ['bool'], 80 80 'string': ['str'], 81 - 'sizes': ['size'] } } 81 + 'sizes': ['size'], 82 + 'any': ['any'] } } 82 83 83 84 # testing commands 84 85 { 'command': 'user_def_cmd', 'data': {} } ··· 88 89 'returns': 'UserDefTwo' } 89 90 { 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' }, 90 91 'returns': 'int' } 92 + # note: command name 'guest-sync' chosen to avoid "cannot use built-in" error 93 + { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' } 91 94 92 95 # For testing integer range flattening in opts-visitor. The following schema 93 96 # corresponds to the option format:
+8 -1
tests/qapi-schema/qapi-schema-test.out
··· 12 12 member b: __org.qemu_x-StructList optional=False 13 13 member c: __org.qemu_x-Union2 optional=False 14 14 member d: __org.qemu_x-Alt optional=False 15 + object :obj-anyList-wrapper 16 + member data: anyList optional=False 15 17 object :obj-boolList-wrapper 16 18 member data: boolList optional=False 19 + object :obj-guest-sync-arg 20 + member arg: any optional=False 17 21 object :obj-int16List-wrapper 18 22 member data: int16List optional=False 19 23 object :obj-int32List-wrapper ··· 102 106 case boolean: :obj-boolList-wrapper 103 107 case string: :obj-strList-wrapper 104 108 case sizes: :obj-sizeList-wrapper 105 - enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes'] 109 + case any: :obj-anyList-wrapper 110 + enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any'] 106 111 object UserDefOne 107 112 base UserDefZero 108 113 member string: str optional=False ··· 150 155 tag __org.qemu_x-member1 151 156 case __org.qemu_x-value: __org.qemu_x-Struct2 152 157 command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1 158 + gen=True success_response=True 159 + command guest-sync :obj-guest-sync-arg -> any 153 160 gen=True success_response=True 154 161 command user_def_cmd None -> None 155 162 gen=True success_response=True
+2 -2
tests/qapi-schema/type-bypass.out
··· 1 1 object :obj-unsafe-arg 2 - member arg: ** optional=False 3 - command unsafe :obj-unsafe-arg -> ** 2 + member arg: any optional=False 3 + command unsafe :obj-unsafe-arg -> any 4 4 gen=False success_response=True
+5
tests/test-qmp-commands.c
··· 51 51 return a + (has_b ? b : 0); 52 52 } 53 53 54 + QObject *qmp_guest_sync(QObject *arg, Error **errp) 55 + { 56 + return arg; 57 + } 58 + 54 59 __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, 55 60 __org_qemu_x_StructList *b, 56 61 __org_qemu_x_Union2 *c,
+45
tests/test-qmp-input-visitor.c
··· 298 298 qapi_free_UserDefOneList(head); 299 299 } 300 300 301 + static void test_visitor_in_any(TestInputVisitorData *data, 302 + const void *unused) 303 + { 304 + QObject *res = NULL; 305 + Error *err = NULL; 306 + Visitor *v; 307 + QInt *qint; 308 + QBool *qbool; 309 + QString *qstring; 310 + QDict *qdict; 311 + QObject *qobj; 312 + 313 + v = visitor_input_test_init(data, "-42"); 314 + visit_type_any(v, &res, NULL, &err); 315 + g_assert(!err); 316 + qint = qobject_to_qint(res); 317 + g_assert(qint); 318 + g_assert_cmpint(qint_get_int(qint), ==, -42); 319 + qobject_decref(res); 320 + 321 + v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); 322 + visit_type_any(v, &res, NULL, &err); 323 + g_assert(!err); 324 + qdict = qobject_to_qdict(res); 325 + g_assert(qdict && qdict_size(qdict) == 3); 326 + qobj = qdict_get(qdict, "integer"); 327 + g_assert(qobj); 328 + qint = qobject_to_qint(qobj); 329 + g_assert(qint); 330 + g_assert_cmpint(qint_get_int(qint), ==, -42); 331 + qobj = qdict_get(qdict, "boolean"); 332 + g_assert(qobj); 333 + qbool = qobject_to_qbool(qobj); 334 + g_assert(qbool); 335 + g_assert(qbool_get_bool(qbool) == true); 336 + qobj = qdict_get(qdict, "string"); 337 + g_assert(qobj); 338 + qstring = qobject_to_qstring(qobj); 339 + g_assert(qstring); 340 + g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); 341 + qobject_decref(res); 342 + } 343 + 301 344 static void test_visitor_in_union_flat(TestInputVisitorData *data, 302 345 const void *unused) 303 346 { ··· 669 712 &in_visitor_data, test_visitor_in_struct_nested); 670 713 input_visitor_test_add("/visitor/input/list", 671 714 &in_visitor_data, test_visitor_in_list); 715 + input_visitor_test_add("/visitor/input/any", 716 + &in_visitor_data, test_visitor_in_any); 672 717 input_visitor_test_add("/visitor/input/union-flat", 673 718 &in_visitor_data, test_visitor_in_union_flat); 674 719 input_visitor_test_add("/visitor/input/alternate",
+53
tests/test-qmp-output-visitor.c
··· 428 428 qapi_free_UserDefTwoList(head); 429 429 } 430 430 431 + static void test_visitor_out_any(TestOutputVisitorData *data, 432 + const void *unused) 433 + { 434 + QObject *qobj; 435 + Error *err = NULL; 436 + QInt *qint; 437 + QBool *qbool; 438 + QString *qstring; 439 + QDict *qdict; 440 + QObject *obj; 441 + 442 + qobj = QOBJECT(qint_from_int(-42)); 443 + visit_type_any(data->ov, &qobj, NULL, &err); 444 + g_assert(!err); 445 + obj = qmp_output_get_qobject(data->qov); 446 + g_assert(obj != NULL); 447 + g_assert(qobject_type(obj) == QTYPE_QINT); 448 + g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, -42); 449 + qobject_decref(obj); 450 + qobject_decref(qobj); 451 + 452 + qdict = qdict_new(); 453 + qdict_put(qdict, "integer", qint_from_int(-42)); 454 + qdict_put(qdict, "boolean", qbool_from_bool(true)); 455 + qdict_put(qdict, "string", qstring_from_str("foo")); 456 + qobj = QOBJECT(qdict); 457 + visit_type_any(data->ov, &qobj, NULL, &err); 458 + g_assert(!err); 459 + obj = qmp_output_get_qobject(data->qov); 460 + g_assert(obj != NULL); 461 + qdict = qobject_to_qdict(obj); 462 + g_assert(qdict); 463 + qobj = qdict_get(qdict, "integer"); 464 + g_assert(qobj); 465 + qint = qobject_to_qint(qobj); 466 + g_assert(qint); 467 + g_assert_cmpint(qint_get_int(qint), ==, -42); 468 + qobj = qdict_get(qdict, "boolean"); 469 + g_assert(qobj); 470 + qbool = qobject_to_qbool(qobj); 471 + g_assert(qbool); 472 + g_assert(qbool_get_bool(qbool) == true); 473 + qobj = qdict_get(qdict, "string"); 474 + g_assert(qobj); 475 + qstring = qobject_to_qstring(qobj); 476 + g_assert(qstring); 477 + g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); 478 + qobject_decref(obj); 479 + qobject_decref(qobj); 480 + } 481 + 431 482 static void test_visitor_out_union_flat(TestOutputVisitorData *data, 432 483 const void *unused) 433 484 { ··· 833 884 &out_visitor_data, test_visitor_out_struct_errors); 834 885 output_visitor_test_add("/visitor/output/list", 835 886 &out_visitor_data, test_visitor_out_list); 887 + output_visitor_test_add("/visitor/output/any", 888 + &out_visitor_data, test_visitor_out_any); 836 889 output_visitor_test_add("/visitor/output/list-qapi-free", 837 890 &out_visitor_data, test_visitor_out_list_qapi_free); 838 891 output_visitor_test_add("/visitor/output/union-flat",