diff options
37 files changed, 958 insertions, 476 deletions
diff --git a/Makefile.objs b/Makefile.objs index 69fdd48679..82e8a1e10a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -162,3 +162,4 @@ trace-events-y += target-s390x/trace-events trace-events-y += target-ppc/trace-events trace-events-y += qom/trace-events trace-events-y += linux-user/trace-events +trace-events-y += qapi/trace-events diff --git a/block/qapi.c b/block/qapi.c index 50d30907a2..a62e862f3c 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -29,7 +29,7 @@ #include "block/write-threshold.h" #include "qmp-commands.h" #include "qapi-visit.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/qmp/types.h" #include "sysemu/block-backend.h" #include "qemu/cutils.h" @@ -691,7 +691,7 @@ void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f, ImageInfoSpecific *info_spec) { QObject *obj, *data; - Visitor *v = qmp_output_visitor_new(&obj); + Visitor *v = qobject_output_visitor_new(&obj); visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort); visit_complete(v, &obj); diff --git a/blockdev.c b/blockdev.c index 07ec733905..d11a74f837 100644 --- a/blockdev.c +++ b/blockdev.c @@ -43,7 +43,7 @@ #include "qapi/qmp/types.h" #include "qapi-visit.h" #include "qapi/qmp/qerror.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/util.h" #include "sysemu/sysemu.h" #include "block/block_int.h" @@ -3776,7 +3776,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) { BlockDriverState *bs; QObject *obj; - Visitor *v = qmp_output_visitor_new(&obj); + Visitor *v = qobject_output_visitor_new(&obj); QDict *qdict; Error *local_err = NULL; diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 5d4c2cdd7e..2841c5144a 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -1005,7 +1005,7 @@ Example: Error *err = NULL; Visitor *v; - v = qmp_output_visitor_new(ret_out); + v = qobject_output_visitor_new(ret_out); visit_type_UserDefOne(v, "unused", &ret_in, &err); if (!err) { visit_complete(v, ret_out); @@ -1024,7 +1024,7 @@ Example: Visitor *v; UserDefOneList *arg1 = NULL; - v = qmp_input_visitor_new(QOBJECT(args), true); + v = qobject_input_visitor_new(QOBJECT(args), true); visit_start_struct(v, NULL, NULL, 0, &err); if (err) { goto out; diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 71b8eb0416..fe9a4c5c60 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -73,6 +73,7 @@ void qdict_flatten(QDict *qdict); void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); void qdict_array_split(QDict *src, QList **dst); int qdict_array_entries(QDict *src, const char *subqdict); +QObject *qdict_crumple(const QDict *src, Error **errp); void qdict_join(QDict *dest, QDict *src, bool overwrite); diff --git a/include/qapi/qmp-input-visitor.h b/include/qapi/qobject-input-visitor.h index f3ff5f3e98..cde328da9f 100644 --- a/include/qapi/qmp-input-visitor.h +++ b/include/qapi/qobject-input-visitor.h @@ -11,20 +11,20 @@ * */ -#ifndef QMP_INPUT_VISITOR_H -#define QMP_INPUT_VISITOR_H +#ifndef QOBJECT_INPUT_VISITOR_H +#define QOBJECT_INPUT_VISITOR_H #include "qapi/visitor.h" #include "qapi/qmp/qobject.h" -typedef struct QmpInputVisitor QmpInputVisitor; +typedef struct QObjectInputVisitor QObjectInputVisitor; /* - * Return a new input visitor that converts QMP to QAPI. + * Return a new input visitor that converts a QObject to a QAPI object. * * Set @strict to reject a parse that doesn't consume all keys of a * dictionary; otherwise excess input is ignored. */ -Visitor *qmp_input_visitor_new(QObject *obj, bool strict); +Visitor *qobject_input_visitor_new(QObject *obj, bool strict); #endif diff --git a/include/qapi/qmp-output-visitor.h b/include/qapi/qobject-output-visitor.h index 040fdda142..8241877bd7 100644 --- a/include/qapi/qmp-output-visitor.h +++ b/include/qapi/qobject-output-visitor.h @@ -11,20 +11,20 @@ * */ -#ifndef QMP_OUTPUT_VISITOR_H -#define QMP_OUTPUT_VISITOR_H +#ifndef QOBJECT_OUTPUT_VISITOR_H +#define QOBJECT_OUTPUT_VISITOR_H #include "qapi/visitor.h" #include "qapi/qmp/qobject.h" -typedef struct QmpOutputVisitor QmpOutputVisitor; +typedef struct QObjectOutputVisitor QObjectOutputVisitor; /* - * Create a new QMP output visitor. + * Create a new QObject output visitor. * * If everything else succeeds, pass @result to visit_complete() to * collect the result of the visit. */ -Visitor *qmp_output_visitor_new(QObject **result); +Visitor *qobject_output_visitor_new(QObject **result); #endif diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 6c77a913db..9bb6cba237 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -25,14 +25,14 @@ * for doing work at each node of a QAPI graph; it can also be used * for a virtual walk, where there is no actual QAPI C struct. * - * There are four kinds of visitor classes: input visitors (QMP, + * There are four kinds of visitor classes: input visitors (QObject, * string, and QemuOpts) parse an external representation and build - * the corresponding QAPI graph, output visitors (QMP and string) take + * the corresponding QAPI graph, output visitors (QObject and string) take * a completed QAPI graph and generate an external representation, the * dealloc visitor can take a QAPI graph (possibly partially * constructed) and recursively free its resources, and the clone * visitor performs a deep clone of one QAPI object to another. While - * the dealloc and QMP input/output visitors are general, the string, + * the dealloc and QObject input/output visitors are general, the string, * QemuOpts, and clone visitors have some implementation limitations; * see the documentation for each visitor for more details on what it * supports. Also, see visitor-impl.h for the callback contracts @@ -950,7 +950,7 @@ EventInfoList *qmp_query_events(Error **errp) * directly into QObject instead of first parsing it with * visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it * to QObject with generated output marshallers, every time. Instead, - * we do it in test-qmp-input-visitor.c, just to make sure + * we do it in test-qobject-input-visitor.c, just to make sure * qapi-introspect.py's output actually conforms to the schema. */ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, diff --git a/qapi-schema.json b/qapi-schema.json index 5a8ec38e10..d6a43a108c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -737,6 +737,7 @@ '*tls-hostname': 'str', '*max-bandwidth': 'int', '*downtime-limit': 'int'} } + ## # @query-migrate-parameters # diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index 7ea4aebb00..33906ff321 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -1,5 +1,5 @@ -util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o -util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qobject-input-visitor.o +util-obj-y += qobject-output-visitor.o qmp-registry.o qmp-dispatch.o util-obj-y += string-input-visitor.o string-output-visitor.o util-obj-y += opts-visitor.o qapi-clone-visitor.o util-obj-y += qmp-event.o diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c index 0bb8216372..34086cbfc0 100644 --- a/qapi/qapi-clone-visitor.c +++ b/qapi/qapi-clone-visitor.c @@ -110,7 +110,7 @@ static void qapi_clone_type_str(Visitor *v, const char *name, char **obj, assert(qcv->depth); /* * Pointer was already cloned by g_memdup; create fresh copy. - * Note that as long as qmp-output-visitor accepts NULL instead of + * Note that as long as qobject-output-visitor accepts NULL instead of * "", then we must do likewise. However, we want to obey the * input visitor semantics of never producing NULL when the empty * string is intended. diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 55f5876dc0..63bd97b341 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -19,10 +19,12 @@ #include "qapi/qmp/qerror.h" #include "qapi/visitor.h" #include "qapi/visitor-impl.h" +#include "trace.h" void visit_complete(Visitor *v, void *opaque) { assert(v->type != VISITOR_OUTPUT || v->complete); + trace_visit_complete(v, opaque); if (v->complete) { v->complete(v, opaque); } @@ -30,6 +32,7 @@ void visit_complete(Visitor *v, void *opaque) void visit_free(Visitor *v) { + trace_visit_free(v); if (v) { v->free(v); } @@ -40,6 +43,7 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, { Error *err = NULL; + trace_visit_start_struct(v, name, obj, size); if (obj) { assert(size); assert(!(v->type & VISITOR_OUTPUT) || *obj); @@ -53,6 +57,7 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, void visit_check_struct(Visitor *v, Error **errp) { + trace_visit_check_struct(v); if (v->check_struct) { v->check_struct(v, errp); } @@ -60,6 +65,7 @@ void visit_check_struct(Visitor *v, Error **errp) void visit_end_struct(Visitor *v, void **obj) { + trace_visit_end_struct(v, obj); v->end_struct(v, obj); } @@ -69,6 +75,7 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list, Error *err = NULL; assert(!list || size >= sizeof(GenericList)); + trace_visit_start_list(v, name, list, size); v->start_list(v, name, list, size, &err); if (list && (v->type & VISITOR_INPUT)) { assert(!(err && *list)); @@ -79,11 +86,13 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list, GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) { assert(tail && size >= sizeof(GenericList)); + trace_visit_next_list(v, tail, size); return v->next_list(v, tail, size); } void visit_end_list(Visitor *v, void **obj) { + trace_visit_end_list(v, obj); v->end_list(v, obj); } @@ -95,6 +104,7 @@ void visit_start_alternate(Visitor *v, const char *name, assert(obj && size >= sizeof(GenericAlternate)); assert(!(v->type & VISITOR_OUTPUT) || *obj); + trace_visit_start_alternate(v, name, obj, size, promote_int); if (v->start_alternate) { v->start_alternate(v, name, obj, size, promote_int, &err); } @@ -106,6 +116,7 @@ void visit_start_alternate(Visitor *v, const char *name, void visit_end_alternate(Visitor *v, void **obj) { + trace_visit_end_alternate(v, obj); if (v->end_alternate) { v->end_alternate(v, obj); } @@ -113,6 +124,7 @@ void visit_end_alternate(Visitor *v, void **obj) bool visit_optional(Visitor *v, const char *name, bool *present) { + trace_visit_optional(v, name, present); if (v->optional) { v->optional(v, name, present); } @@ -127,6 +139,7 @@ bool visit_is_input(Visitor *v) void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); + trace_visit_type_int(v, name, obj); v->type_int64(v, name, obj, errp); } @@ -150,7 +163,10 @@ static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, Error **errp) { - uint64_t value = *obj; + uint64_t value; + + trace_visit_type_uint8(v, name, obj); + value = *obj; visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); *obj = value; } @@ -158,7 +174,10 @@ void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, Error **errp) { - uint64_t value = *obj; + uint64_t value; + + trace_visit_type_uint16(v, name, obj); + value = *obj; visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); *obj = value; } @@ -166,7 +185,10 @@ void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, Error **errp) { - uint64_t value = *obj; + uint64_t value; + + trace_visit_type_uint32(v, name, obj); + value = *obj; visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); *obj = value; } @@ -175,6 +197,7 @@ void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { assert(obj); + trace_visit_type_uint64(v, name, obj); v->type_uint64(v, name, obj, errp); } @@ -198,7 +221,10 @@ static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) { - int64_t value = *obj; + int64_t value; + + trace_visit_type_int8(v, name, obj); + value = *obj; visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); *obj = value; } @@ -206,7 +232,10 @@ void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) void visit_type_int16(Visitor *v, const char *name, int16_t *obj, Error **errp) { - int64_t value = *obj; + int64_t value; + + trace_visit_type_int16(v, name, obj); + value = *obj; visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp); *obj = value; } @@ -214,7 +243,10 @@ void visit_type_int16(Visitor *v, const char *name, int16_t *obj, void visit_type_int32(Visitor *v, const char *name, int32_t *obj, Error **errp) { - int64_t value = *obj; + int64_t value; + + trace_visit_type_int32(v, name, obj); + value = *obj; visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp); *obj = value; } @@ -223,6 +255,7 @@ void visit_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { assert(obj); + trace_visit_type_int64(v, name, obj); v->type_int64(v, name, obj, errp); } @@ -230,6 +263,7 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { assert(obj); + trace_visit_type_size(v, name, obj); if (v->type_size) { v->type_size(v, name, obj, errp); } else { @@ -240,6 +274,7 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { assert(obj); + trace_visit_type_bool(v, name, obj); v->type_bool(v, name, obj, errp); } @@ -252,6 +287,7 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) * can enable: assert(!(v->type & VISITOR_OUTPUT) || *obj); */ + trace_visit_type_str(v, name, obj); v->type_str(v, name, obj, &err); if (v->type & VISITOR_INPUT) { assert(!err != !*obj); @@ -263,6 +299,7 @@ void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp) { assert(obj); + trace_visit_type_number(v, name, obj); v->type_number(v, name, obj, errp); } @@ -272,6 +309,7 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) assert(obj); assert(v->type != VISITOR_OUTPUT || *obj); + trace_visit_type_any(v, name, obj); v->type_any(v, name, obj, &err); if (v->type == VISITOR_INPUT) { assert(!err != !*obj); @@ -281,6 +319,7 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) void visit_type_null(Visitor *v, const char *name, Error **errp) { + trace_visit_type_null(v, name); v->type_null(v, name, errp); } diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c deleted file mode 100644 index 9e3b67ce13..0000000000 --- a/qapi/qmp-output-visitor.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Core Definitions for QAPI/QMP Command Registry - * - * Copyright (C) 2012-2016 Red Hat, Inc. - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/visitor-impl.h" -#include "qemu/queue.h" -#include "qemu-common.h" -#include "qapi/qmp/types.h" - -typedef struct QStackEntry -{ - QObject *value; - void *qapi; /* sanity check that caller uses same pointer */ - QSLIST_ENTRY(QStackEntry) node; -} QStackEntry; - -struct QmpOutputVisitor -{ - Visitor visitor; - QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ - QObject *root; /* Root of the output visit */ - QObject **result; /* User's storage location for result */ -}; - -#define qmp_output_add(qov, name, value) \ - qmp_output_add_obj(qov, name, QOBJECT(value)) -#define qmp_output_push(qov, value, qapi) \ - qmp_output_push_obj(qov, QOBJECT(value), qapi) - -static QmpOutputVisitor *to_qov(Visitor *v) -{ - return container_of(v, QmpOutputVisitor, visitor); -} - -/* Push @value onto the stack of current QObjects being built */ -static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value, - void *qapi) -{ - QStackEntry *e = g_malloc0(sizeof(*e)); - - assert(qov->root); - assert(value); - e->value = value; - e->qapi = qapi; - QSLIST_INSERT_HEAD(&qov->stack, e, node); -} - -/* Pop a value off the stack of QObjects being built, and return it. */ -static QObject *qmp_output_pop(QmpOutputVisitor *qov, void *qapi) -{ - QStackEntry *e = QSLIST_FIRST(&qov->stack); - QObject *value; - - assert(e); - assert(e->qapi == qapi); - QSLIST_REMOVE_HEAD(&qov->stack, node); - value = e->value; - assert(value); - g_free(e); - return value; -} - -/* Add @value to the current QObject being built. - * If the stack is visiting a dictionary or list, @value is now owned - * by that container. Otherwise, @value is now the root. */ -static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, - QObject *value) -{ - QStackEntry *e = QSLIST_FIRST(&qov->stack); - QObject *cur = e ? e->value : NULL; - - if (!cur) { - /* Don't allow reuse of visitor on more than one root */ - assert(!qov->root); - qov->root = value; - } else { - switch (qobject_type(cur)) { - case QTYPE_QDICT: - assert(name); - qdict_put_obj(qobject_to_qdict(cur), name, value); - break; - case QTYPE_QLIST: - assert(!name); - qlist_append_obj(qobject_to_qlist(cur), value); - break; - default: - g_assert_not_reached(); - } - } -} - -static void qmp_output_start_struct(Visitor *v, const char *name, void **obj, - size_t unused, Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - QDict *dict = qdict_new(); - - qmp_output_add(qov, name, dict); - qmp_output_push(qov, dict, obj); -} - -static void qmp_output_end_struct(Visitor *v, void **obj) -{ - QmpOutputVisitor *qov = to_qov(v); - QObject *value = qmp_output_pop(qov, obj); - assert(qobject_type(value) == QTYPE_QDICT); -} - -static void qmp_output_start_list(Visitor *v, const char *name, - GenericList **listp, size_t size, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - QList *list = qlist_new(); - - qmp_output_add(qov, name, list); - qmp_output_push(qov, list, listp); -} - -static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail, - size_t size) -{ - return tail->next; -} - -static void qmp_output_end_list(Visitor *v, void **obj) -{ - QmpOutputVisitor *qov = to_qov(v); - QObject *value = qmp_output_pop(qov, obj); - assert(qobject_type(value) == QTYPE_QLIST); -} - -static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qint_from_int(*obj)); -} - -static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj, - Error **errp) -{ - /* FIXME: QMP outputs values larger than INT64_MAX as negative */ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qint_from_int(*obj)); -} - -static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qbool_from_bool(*obj)); -} - -static void qmp_output_type_str(Visitor *v, const char *name, char **obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - if (*obj) { - qmp_output_add(qov, name, qstring_from_str(*obj)); - } else { - qmp_output_add(qov, name, qstring_from_str("")); - } -} - -static void qmp_output_type_number(Visitor *v, const char *name, double *obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add(qov, name, qfloat_from_double(*obj)); -} - -static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj, - Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qobject_incref(*obj); - qmp_output_add_obj(qov, name, *obj); -} - -static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) -{ - QmpOutputVisitor *qov = to_qov(v); - qmp_output_add_obj(qov, name, qnull()); -} - -/* Finish building, and return the root object. - * The root object is never null. The caller becomes the object's - * owner, and should use qobject_decref() when done with it. */ -static void qmp_output_complete(Visitor *v, void *opaque) -{ - QmpOutputVisitor *qov = to_qov(v); - - /* A visit must have occurred, with each start paired with end. */ - assert(qov->root && QSLIST_EMPTY(&qov->stack)); - assert(opaque == qov->result); - - qobject_incref(qov->root); - *qov->result = qov->root; - qov->result = NULL; -} - -static void qmp_output_free(Visitor *v) -{ - QmpOutputVisitor *qov = to_qov(v); - QStackEntry *e; - - while (!QSLIST_EMPTY(&qov->stack)) { - e = QSLIST_FIRST(&qov->stack); - QSLIST_REMOVE_HEAD(&qov->stack, node); - g_free(e); - } - - qobject_decref(qov->root); - g_free(qov); -} - -Visitor *qmp_output_visitor_new(QObject **result) -{ - QmpOutputVisitor *v; - - v = g_malloc0(sizeof(*v)); - - v->visitor.type = VISITOR_OUTPUT; - v->visitor.start_struct = qmp_output_start_struct; - v->visitor.end_struct = qmp_output_end_struct; - v->visitor.start_list = qmp_output_start_list; - v->visitor.next_list = qmp_output_next_list; - v->visitor.end_list = qmp_output_end_list; - v->visitor.type_int64 = qmp_output_type_int64; - v->visitor.type_uint64 = qmp_output_type_uint64; - v->visitor.type_bool = qmp_output_type_bool; - v->visitor.type_str = qmp_output_type_str; - v->visitor.type_number = qmp_output_type_number; - v->visitor.type_any = qmp_output_type_any; - v->visitor.type_null = qmp_output_type_null; - v->visitor.complete = qmp_output_complete; - v->visitor.free = qmp_output_free; - - *result = NULL; - v->result = result; - - return &v->visitor; -} diff --git a/qapi/qmp-input-visitor.c b/qapi/qobject-input-visitor.c index 37a8e1f931..0063327b3b 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "qapi/visitor-impl.h" #include "qemu/queue.h" #include "qemu-common.h" @@ -34,7 +34,7 @@ typedef struct StackObject QSLIST_ENTRY(StackObject) node; } StackObject; -struct QmpInputVisitor +struct QObjectInputVisitor { Visitor visitor; @@ -49,14 +49,14 @@ struct QmpInputVisitor bool strict; }; -static QmpInputVisitor *to_qiv(Visitor *v) +static QObjectInputVisitor *to_qiv(Visitor *v) { - return container_of(v, QmpInputVisitor, visitor); + return container_of(v, QObjectInputVisitor, visitor); } -static QObject *qmp_input_get_object(QmpInputVisitor *qiv, - const char *name, - bool consume, Error **errp) +static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, + const char *name, + bool consume, Error **errp) { StackObject *tos; QObject *qobj; @@ -102,8 +102,9 @@ static void qdict_add_key(const char *key, QObject *obj, void *opaque) g_hash_table_insert(h, (gpointer) key, NULL); } -static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, - void *qapi, Error **errp) +static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, + QObject *obj, void *qapi, + Error **errp) { GHashTable *h; StackObject *tos = g_new0(StackObject, 1); @@ -125,9 +126,9 @@ static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, } -static void qmp_input_check_struct(Visitor *v, Error **errp) +static void qobject_input_check_struct(Visitor *v, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); assert(tos && !tos->entry); @@ -145,7 +146,7 @@ static void qmp_input_check_struct(Visitor *v, Error **errp) } } -static void qmp_input_stack_object_free(StackObject *tos) +static void qobject_input_stack_object_free(StackObject *tos) { if (tos->h) { g_hash_table_unref(tos->h); @@ -154,21 +155,21 @@ static void qmp_input_stack_object_free(StackObject *tos) g_free(tos); } -static void qmp_input_pop(Visitor *v, void **obj) +static void qobject_input_pop(Visitor *v, void **obj) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); assert(tos && tos->qapi == obj); QSLIST_REMOVE_HEAD(&qiv->stack, node); - qmp_input_stack_object_free(tos); + qobject_input_stack_object_free(tos); } -static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, - size_t size, Error **errp) +static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, + size_t size, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); Error *err = NULL; if (obj) { @@ -183,7 +184,7 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, return; } - qmp_input_push(qiv, qobj, obj, &err); + qobject_input_push(qiv, qobj, obj, &err); if (err) { error_propagate(errp, err); return; @@ -195,11 +196,12 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, } -static void qmp_input_start_list(Visitor *v, const char *name, - GenericList **list, size_t size, Error **errp) +static void qobject_input_start_list(Visitor *v, const char *name, + GenericList **list, size_t size, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); const QListEntry *entry; if (!qobj) { @@ -214,7 +216,7 @@ static void qmp_input_start_list(Visitor *v, const char *name, return; } - entry = qmp_input_push(qiv, qobj, list, errp); + entry = qobject_input_push(qiv, qobj, list, errp); if (list) { if (entry) { *list = g_malloc0(size); @@ -224,10 +226,10 @@ static void qmp_input_start_list(Visitor *v, const char *name, } } -static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail, - size_t size) +static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, + size_t size) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); StackObject *so = QSLIST_FIRST(&qiv->stack); if (!so->entry) { @@ -238,12 +240,12 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail, } -static void qmp_input_start_alternate(Visitor *v, const char *name, - GenericAlternate **obj, size_t size, - bool promote_int, Error **errp) +static void qobject_input_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, false, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, false, errp); if (!qobj) { *obj = NULL; @@ -256,11 +258,11 @@ static void qmp_input_start_alternate(Visitor *v, const char *name, } } -static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj, - Error **errp) +static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); QInt *qint; if (!qobj) { @@ -276,12 +278,12 @@ static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj, *obj = qint_get_int(qint); } -static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, - Error **errp) +static void qobject_input_type_uint64(Visitor *v, const char *name, + uint64_t *obj, Error **errp) { /* FIXME: qobject_to_qint mishandles values over INT64_MAX */ - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); QInt *qint; if (!qobj) { @@ -297,11 +299,11 @@ static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, *obj = qint_get_int(qint); } -static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj, - Error **errp) +static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); QBool *qbool; if (!qobj) { @@ -317,11 +319,11 @@ static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj, *obj = qbool_get_bool(qbool); } -static void qmp_input_type_str(Visitor *v, const char *name, char **obj, - Error **errp) +static void qobject_input_type_str(Visitor *v, const char *name, char **obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); QString *qstr; *obj = NULL; @@ -338,11 +340,11 @@ static void qmp_input_type_str(Visitor *v, const char *name, char **obj, *obj = g_strdup(qstring_get_str(qstr)); } -static void qmp_input_type_number(Visitor *v, const char *name, double *obj, - Error **errp) +static void qobject_input_type_number(Visitor *v, const char *name, double *obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); QInt *qint; QFloat *qfloat; @@ -365,11 +367,11 @@ static void qmp_input_type_number(Visitor *v, const char *name, double *obj, "number"); } -static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, - Error **errp) +static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, + Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); *obj = NULL; if (!qobj) { @@ -380,10 +382,10 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, *obj = qobj; } -static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) +static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, true, errp); if (!qobj) { return; @@ -395,10 +397,10 @@ static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) } } -static void qmp_input_optional(Visitor *v, const char *name, bool *present) +static void qobject_input_optional(Visitor *v, const char *name, bool *present) { - QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, false, NULL); + QObjectInputVisitor *qiv = to_qiv(v); + QObject *qobj = qobject_input_get_object(qiv, name, false, NULL); if (!qobj) { *present = false; @@ -408,44 +410,44 @@ static void qmp_input_optional(Visitor *v, const char *name, bool *present) *present = true; } -static void qmp_input_free(Visitor *v) +static void qobject_input_free(Visitor *v) { - QmpInputVisitor *qiv = to_qiv(v); + QObjectInputVisitor *qiv = to_qiv(v); while (!QSLIST_EMPTY(&qiv->stack)) { StackObject *tos = QSLIST_FIRST(&qiv->stack); QSLIST_REMOVE_HEAD(&qiv->stack, node); - qmp_input_stack_object_free(tos); + qobject_input_stack_object_free(tos); } qobject_decref(qiv->root); g_free(qiv); } -Visitor *qmp_input_visitor_new(QObject *obj, bool strict) +Visitor *qobject_input_visitor_new(QObject *obj, bool strict) { - QmpInputVisitor *v; + QObjectInputVisitor *v; assert(obj); v = g_malloc0(sizeof(*v)); v->visitor.type = VISITOR_INPUT; - v->visitor.start_struct = qmp_input_start_struct; - v->visitor.check_struct = qmp_input_check_struct; - v->visitor.end_struct = qmp_input_pop; - v->visitor.start_list = qmp_input_start_list; - v->visitor.next_list = qmp_input_next_list; - v->visitor.end_list = qmp_input_pop; - v->visitor.start_alternate = qmp_input_start_alternate; - v->visitor.type_int64 = qmp_input_type_int64; - v->visitor.type_uint64 = qmp_input_type_uint64; - v->visitor.type_bool = qmp_input_type_bool; - v->visitor.type_str = qmp_input_type_str; - v->visitor.type_number = qmp_input_type_number; - v->visitor.type_any = qmp_input_type_any; - v->visitor.type_null = qmp_input_type_null; - v->visitor.optional = qmp_input_optional; - v->visitor.free = qmp_input_free; + v->visitor.start_struct = qobject_input_start_struct; + v->visitor.check_struct = qobject_input_check_struct; + v->visitor.end_struct = qobject_input_pop; + v->visitor.start_list = qobject_input_start_list; + v->visitor.next_list = qobject_input_next_list; + v->visitor.end_list = qobject_input_pop; + v->visitor.start_alternate = qobject_input_start_alternate; + v->visitor.type_int64 = qobject_input_type_int64; + v->visitor.type_uint64 = qobject_input_type_uint64; + v->visitor.type_bool = qobject_input_type_bool; + v->visitor.type_str = qobject_input_type_str; + v->visitor.type_number = qobject_input_type_number; + v->visitor.type_any = qobject_input_type_any; + v->visitor.type_null = qobject_input_type_null; + v->visitor.optional = qobject_input_optional; + v->visitor.free = qobject_input_free; v->strict = strict; v->root = obj; diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c new file mode 100644 index 0000000000..871127079d --- /dev/null +++ b/qapi/qobject-output-visitor.c @@ -0,0 +1,254 @@ +/* + * Core Definitions for QAPI/QMP Command Registry + * + * Copyright (C) 2012-2016 Red Hat, Inc. + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/qobject-output-visitor.h" +#include "qapi/visitor-impl.h" +#include "qemu/queue.h" +#include "qemu-common.h" +#include "qapi/qmp/types.h" + +typedef struct QStackEntry { + QObject *value; + void *qapi; /* sanity check that caller uses same pointer */ + QSLIST_ENTRY(QStackEntry) node; +} QStackEntry; + +struct QObjectOutputVisitor { + Visitor visitor; + QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ + QObject *root; /* Root of the output visit */ + QObject **result; /* User's storage location for result */ +}; + +#define qobject_output_add(qov, name, value) \ + qobject_output_add_obj(qov, name, QOBJECT(value)) +#define qobject_output_push(qov, value, qapi) \ + qobject_output_push_obj(qov, QOBJECT(value), qapi) + +static QObjectOutputVisitor *to_qov(Visitor *v) +{ + return container_of(v, QObjectOutputVisitor, visitor); +} + +/* Push @value onto the stack of current QObjects being built */ +static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value, + void *qapi) +{ + QStackEntry *e = g_malloc0(sizeof(*e)); + + assert(qov->root); + assert(value); + e->value = value; + e->qapi = qapi; + QSLIST_INSERT_HEAD(&qov->stack, e, node); +} + +/* Pop a value off the stack of QObjects being built, and return it. */ +static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi) +{ + QStackEntry *e = QSLIST_FIRST(&qov->stack); + QObject *value; + + assert(e); + assert(e->qapi == qapi); + QSLIST_REMOVE_HEAD(&qov->stack, node); + value = e->value; + assert(value); + g_free(e); + return value; +} + +/* Add @value to the current QObject being built. + * If the stack is visiting a dictionary or list, @value is now owned + * by that container. Otherwise, @value is now the root. */ +static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name, + QObject *value) +{ + QStackEntry *e = QSLIST_FIRST(&qov->stack); + QObject *cur = e ? e->value : NULL; + + if (!cur) { + /* Don't allow reuse of visitor on more than one root */ + assert(!qov->root); + qov->root = value; + } else { + switch (qobject_type(cur)) { + case QTYPE_QDICT: + assert(name); + qdict_put_obj(qobject_to_qdict(cur), name, value); + break; + case QTYPE_QLIST: + assert(!name); + qlist_append_obj(qobject_to_qlist(cur), value); + break; + default: + g_assert_not_reached(); + } + } +} + +static void qobject_output_start_struct(Visitor *v, const char *name, + void **obj, size_t unused, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + QDict *dict = qdict_new(); + + qobject_output_add(qov, name, dict); + qobject_output_push(qov, dict, obj); +} + +static void qobject_output_end_struct(Visitor *v, void **obj) +{ + QObjectOutputVisitor *qov = to_qov(v); + QObject *value = qobject_output_pop(qov, obj); + assert(qobject_type(value) == QTYPE_QDICT); +} + +static void qobject_output_start_list(Visitor *v, const char *name, + GenericList **listp, size_t size, + Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + QList *list = qlist_new(); + + qobject_output_add(qov, name, list); + qobject_output_push(qov, list, listp); +} + +static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail, + size_t size) +{ + return tail->next; +} + +static void qobject_output_end_list(Visitor *v, void **obj) +{ + QObjectOutputVisitor *qov = to_qov(v); + QObject *value = qobject_output_pop(qov, obj); + assert(qobject_type(value) == QTYPE_QLIST); +} + +static void qobject_output_type_int64(Visitor *v, const char *name, + int64_t *obj, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qint_from_int(*obj)); +} + +static void qobject_output_type_uint64(Visitor *v, const char *name, + uint64_t *obj, Error **errp) +{ + /* FIXME values larger than INT64_MAX become negative */ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qint_from_int(*obj)); +} + +static void qobject_output_type_bool(Visitor *v, const char *name, bool *obj, + Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qbool_from_bool(*obj)); +} + +static void qobject_output_type_str(Visitor *v, const char *name, char **obj, + Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + if (*obj) { + qobject_output_add(qov, name, qstring_from_str(*obj)); + } else { + qobject_output_add(qov, name, qstring_from_str("")); + } +} + +static void qobject_output_type_number(Visitor *v, const char *name, + double *obj, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add(qov, name, qfloat_from_double(*obj)); +} + +static void qobject_output_type_any(Visitor *v, const char *name, + QObject **obj, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_incref(*obj); + qobject_output_add_obj(qov, name, *obj); +} + +static void qobject_output_type_null(Visitor *v, const char *name, Error **errp) +{ + QObjectOutputVisitor *qov = to_qov(v); + qobject_output_add_obj(qov, name, qnull()); +} + +/* Finish building, and return the root object. + * The root object is never null. The caller becomes the object's + * owner, and should use qobject_decref() when done with it. */ +static void qobject_output_complete(Visitor *v, void *opaque) +{ + QObjectOutputVisitor *qov = to_qov(v); + + /* A visit must have occurred, with each start paired with end. */ + assert(qov->root && QSLIST_EMPTY(&qov->stack)); + assert(opaque == qov->result); + + qobject_incref(qov->root); + *qov->result = qov->root; + qov->result = NULL; +} + +static void qobject_output_free(Visitor *v) +{ + QObjectOutputVisitor *qov = to_qov(v); + QStackEntry *e; + + while (!QSLIST_EMPTY(&qov->stack)) { + e = QSLIST_FIRST(&qov->stack); + QSLIST_REMOVE_HEAD(&qov->stack, node); + g_free(e); + } + + qobject_decref(qov->root); + g_free(qov); +} + +Visitor *qobject_output_visitor_new(QObject **result) +{ + QObjectOutputVisitor *v; + + v = g_malloc0(sizeof(*v)); + + v->visitor.type = VISITOR_OUTPUT; + v->visitor.start_struct = qobject_output_start_struct; + v->visitor.end_struct = qobject_output_end_struct; + v->visitor.start_list = qobject_output_start_list; + v->visitor.next_list = qobject_output_next_list; + v->visitor.end_list = qobject_output_end_list; + v->visitor.type_int64 = qobject_output_type_int64; + v->visitor.type_uint64 = qobject_output_type_uint64; + v->visitor.type_bool = qobject_output_type_bool; + v->visitor.type_str = qobject_output_type_str; + v->visitor.type_number = qobject_output_type_number; + v->visitor.type_any = qobject_output_type_any; + v->visitor.type_null = qobject_output_type_null; + v->visitor.complete = qobject_output_complete; + v->visitor.free = qobject_output_free; + + *result = NULL; + v->result = result; + + return &v->visitor; +} diff --git a/qapi/trace-events b/qapi/trace-events new file mode 100644 index 0000000000..2c5d3bc7d7 --- /dev/null +++ b/qapi/trace-events @@ -0,0 +1,33 @@ +# qapi-visit-core.c +visit_free(void *v) "v=%p" +visit_complete(void *v, void *opaque) "v=%p opaque=%p" + +visit_start_struct(void *v, const char *name, void *obj, size_t size) "v=%p name=%s obj=%p size=%zu" +visit_check_struct(void *v) "v=%p" +visit_end_struct(void *v, void *obj) "v=%p obj=%p" + +visit_start_list(void *v, const char *name, void *obj, size_t size) "v=%p name=%s obj=%p size=%zu" +visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu" +visit_end_list(void *v, void *obj) "v=%p obj=%p" + +visit_start_alternate(void *v, const char *name, void *obj, size_t size, bool promote_int) "v=%p name=%s obj=%p size=%zu promote_int=%d" +visit_end_alternate(void *v, void *obj) "v=%p obj=%p" + +visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p" + +visit_type_enum(void *v, const char *name, int *obj) "v=%p name=%s obj=%p" +visit_type_int(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p" +visit_type_uint8(void *v, const char *name, uint8_t *obj) "v=%p name=%s obj=%p" +visit_type_uint16(void *v, const char *name, uint16_t *obj) "v=%p name=%s obj=%p" +visit_type_uint32(void *v, const char *name, uint32_t *obj) "v=%p name=%s obj=%p" +visit_type_uint64(void *v, const char *name, uint64_t *obj) "v=%p name=%s obj=%p" +visit_type_int8(void *v, const char *name, int8_t *obj) "v=%p name=%s obj=%p" +visit_type_int16(void *v, const char *name, int16_t *obj) "v=%p name=%s obj=%p" +visit_type_int32(void *v, const char *name, int32_t *obj) "v=%p name=%s obj=%p" +visit_type_int64(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p" +visit_type_size(void *v, const char *name, uint64_t *obj) "v=%p name=%s obj=%p" +visit_type_bool(void *v, const char *name, bool *obj) "v=%p name=%s obj=%p" +visit_type_str(void *v, const char *name, char **obj) "v=%p name=%s obj=%p" +visit_type_number(void *v, const char *name, double *obj) "v=%p name=%s obj=%p" +visit_type_any(void *v, const char *name, void *obj) "v=%p name=%s obj=%p" +visit_type_null(void *v, const char *name) "v=%p name=%s" diff --git a/qemu-img.c b/qemu-img.c index ab395a9b1a..afcd51ff18 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -25,7 +25,7 @@ #include "qemu-version.h" #include "qapi/error.h" #include "qapi-visit.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" #include "qemu/cutils.h" @@ -500,7 +500,7 @@ static void dump_json_image_check(ImageCheck *check, bool quiet) { QString *str; QObject *obj; - Visitor *v = qmp_output_visitor_new(&obj); + Visitor *v = qobject_output_visitor_new(&obj); visit_type_ImageCheck(v, NULL, &check, &error_abort); visit_complete(v, &obj); @@ -2193,7 +2193,7 @@ static void dump_json_image_info_list(ImageInfoList *list) { QString *str; QObject *obj; - Visitor *v = qmp_output_visitor_new(&obj); + Visitor *v = qobject_output_visitor_new(&obj); visit_type_ImageInfoList(v, NULL, &list, &error_abort); visit_complete(v, &obj); @@ -2209,7 +2209,7 @@ static void dump_json_image_info(ImageInfo *info) { QString *str; QObject *obj; - Visitor *v = qmp_output_visitor_new(&obj); + Visitor *v = qobject_output_visitor_new(&obj); visit_type_ImageInfo(v, NULL, &info, &error_abort); visit_complete(v, &obj); @@ -31,7 +31,7 @@ #include "qom/qom-qobject.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qobject.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "hw/boards.h" #include "qom/object_interfaces.h" #include "hw/mem/pc-dimm.h" @@ -675,7 +675,7 @@ void qmp_object_add(const char *type, const char *id, pdict = qdict_new(); } - v = qmp_input_visitor_new(QOBJECT(pdict), true); + v = qobject_input_visitor_new(QOBJECT(pdict), true); obj = user_creatable_add_type(type, id, pdict, v, errp); visit_free(v); if (obj) { diff --git a/qobject/qdict.c b/qobject/qdict.c index 60f158c3b7..197b0fbd47 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -17,6 +17,7 @@ #include "qapi/qmp/qbool.h" #include "qapi/qmp/qstring.h" #include "qapi/qmp/qobject.h" +#include "qapi/error.h" #include "qemu/queue.h" #include "qemu-common.h" #include "qemu/cutils.h" @@ -684,6 +685,282 @@ void qdict_array_split(QDict *src, QList **dst) } /** + * qdict_split_flat_key: + * @key: the key string to split + * @prefix: non-NULL pointer to hold extracted prefix + * @suffix: non-NULL pointer to remaining suffix + * + * Given a flattened key such as 'foo.0.bar', split it into two parts + * at the first '.' separator. Allows double dot ('..') to escape the + * normal separator. + * + * e.g. + * 'foo.0.bar' -> prefix='foo' and suffix='0.bar' + * 'foo..0.bar' -> prefix='foo.0' and suffix='bar' + * + * The '..' sequence will be unescaped in the returned 'prefix' + * string. The 'suffix' string will be left in escaped format, so it + * can be fed back into the qdict_split_flat_key() key as the input + * later. + * + * The caller is responsible for freeing the string returned in @prefix + * using g_free(). + */ +static void qdict_split_flat_key(const char *key, char **prefix, + const char **suffix) +{ + const char *separator; + size_t i, j; + + /* Find first '.' separator, but if there is a pair '..' + * that acts as an escape, so skip over '..' */ + separator = NULL; + do { + if (separator) { + separator += 2; + } else { + separator = key; + } + separator = strchr(separator, '.'); + } while (separator && separator[1] == '.'); + + if (separator) { + *prefix = g_strndup(key, separator - key); + *suffix = separator + 1; + } else { + *prefix = g_strdup(key); + *suffix = NULL; + } + + /* Unescape the '..' sequence into '.' */ + for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) { + if ((*prefix)[i] == '.') { + assert((*prefix)[i + 1] == '.'); + i++; + } + (*prefix)[j] = (*prefix)[i]; + } + (*prefix)[j] = '\0'; +} + +/** + * qdict_is_list: + * @maybe_list: dict to check if keys represent list elements. + * + * Determine whether all keys in @maybe_list are valid list elements. + * If @maybe_list is non-zero in length and all the keys look like + * valid list indexes, this will return 1. If @maybe_list is zero + * length or all keys are non-numeric then it will return 0 to indicate + * it is a normal qdict. If there is a mix of numeric and non-numeric + * keys, or the list indexes are non-contiguous, an error is reported. + * + * Returns: 1 if a valid list, 0 if a dict, -1 on error + */ +static int qdict_is_list(QDict *maybe_list, Error **errp) +{ + const QDictEntry *ent; + ssize_t len = 0; + ssize_t max = -1; + int is_list = -1; + int64_t val; + + for (ent = qdict_first(maybe_list); ent != NULL; + ent = qdict_next(maybe_list, ent)) { + + if (qemu_strtoll(ent->key, NULL, 10, &val) == 0) { + if (is_list == -1) { + is_list = 1; + } else if (!is_list) { + error_setg(errp, + "Cannot mix list and non-list keys"); + return -1; + } + len++; + if (val > max) { + max = val; + } + } else { + if (is_list == -1) { + is_list = 0; + } else if (is_list) { + error_setg(errp, + "Cannot mix list and non-list keys"); + return -1; + } + } + } + + if (is_list == -1) { + assert(!qdict_size(maybe_list)); + is_list = 0; + } + + /* NB this isn't a perfect check - e.g. it won't catch + * a list containing '1', '+1', '01', '3', but that + * does not matter - we've still proved that the + * input is a list. It is up the caller to do a + * stricter check if desired */ + if (len != (max + 1)) { + error_setg(errp, "List indices are not contiguous, " + "saw %zd elements but %zd largest index", + len, max); + return -1; + } + + return is_list; +} + +/** + * qdict_crumple: + * @src: the original flat dictionary (only scalar values) to crumple + * + * Takes a flat dictionary whose keys use '.' separator to indicate + * nesting, and values are scalars, and crumples it into a nested + * structure. + * + * To include a literal '.' in a key name, it must be escaped as '..' + * + * For example, an input of: + * + * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', + * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } + * + * will result in an output of: + * + * { + * 'foo': [ + * { 'bar': 'one', 'wizz': '1' }, + * { 'bar': 'two', 'wizz': '2' } + * ], + * } + * + * The following scenarios in the input dict will result in an + * error being returned: + * + * - Any values in @src are non-scalar types + * - If keys in @src imply that a particular level is both a + * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". + * - If keys in @src imply that a particular level is a list, + * but the indices are non-contiguous. e.g. "foo.0.bar" and + * "foo.2.bar" without any "foo.1.bar" present. + * - If keys in @src represent list indexes, but are not in + * the "%zu" format. e.g. "foo.+0.bar" + * + * Returns: either a QDict or QList for the nested data structure, or NULL + * on error + */ +QObject *qdict_crumple(const QDict *src, Error **errp) +{ + const QDictEntry *ent; + QDict *two_level, *multi_level = NULL; + QObject *dst = NULL, *child; + size_t i; + char *prefix = NULL; + const char *suffix = NULL; + int is_list; + + two_level = qdict_new(); + + /* Step 1: split our totally flat dict into a two level dict */ + for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { + if (qobject_type(ent->value) == QTYPE_QDICT || + qobject_type(ent->value) == QTYPE_QLIST) { + error_setg(errp, "Value %s is not a scalar", + ent->key); + goto error; + } + + qdict_split_flat_key(ent->key, &prefix, &suffix); + + child = qdict_get(two_level, prefix); + if (suffix) { + if (child) { + if (qobject_type(child) != QTYPE_QDICT) { + error_setg(errp, "Key %s prefix is already set as a scalar", + prefix); + goto error; + } + } else { + child = QOBJECT(qdict_new()); + qdict_put_obj(two_level, prefix, child); + } + qobject_incref(ent->value); + qdict_put_obj(qobject_to_qdict(child), suffix, ent->value); + } else { + if (child) { + error_setg(errp, "Key %s prefix is already set as a dict", + prefix); + goto error; + } + qobject_incref(ent->value); + qdict_put_obj(two_level, prefix, ent->value); + } + + g_free(prefix); + prefix = NULL; + } + + /* Step 2: optionally process the two level dict recursively + * into a multi-level dict */ + multi_level = qdict_new(); + for (ent = qdict_first(two_level); ent != NULL; + ent = qdict_next(two_level, ent)) { + + if (qobject_type(ent->value) == QTYPE_QDICT) { + child = qdict_crumple(qobject_to_qdict(ent->value), errp); + if (!child) { + goto error; + } + + qdict_put_obj(multi_level, ent->key, child); + } else { + qobject_incref(ent->value); + qdict_put_obj(multi_level, ent->key, ent->value); + } + } + QDECREF(two_level); + two_level = NULL; + + /* Step 3: detect if we need to turn our dict into list */ + is_list = qdict_is_list(multi_level, errp); + if (is_list < 0) { + goto error; + } + + if (is_list) { + dst = QOBJECT(qlist_new()); + + for (i = 0; i < qdict_size(multi_level); i++) { + char *key = g_strdup_printf("%zu", i); + + child = qdict_get(multi_level, key); + g_free(key); + + if (!child) { + error_setg(errp, "Missing list index %zu", i); + goto error; + } + + qobject_incref(child); + qlist_append_obj(qobject_to_qlist(dst), child); + } + QDECREF(multi_level); + multi_level = NULL; + } else { + dst = QOBJECT(multi_level); + } + + return dst; + + error: + g_free(prefix); + QDECREF(multi_level); + QDECREF(two_level); + qobject_decref(dst); + return NULL; +} + +/** * qdict_array_entries(): Returns the number of direct array entries if the * sub-QDict of src specified by the prefix in subqdict (or src itself for * prefix == "") is valid as an array, i.e. the length of the created list if diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index bf598468ab..ded4d84c85 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -3,7 +3,7 @@ #include "qom/object_interfaces.h" #include "qemu/module.h" #include "qapi-visit.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/opts-visitor.h" void user_creatable_complete(Object *obj, Error **errp) diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c index c225abcbad..447e4a0560 100644 --- a/qom/qom-qobject.c +++ b/qom/qom-qobject.c @@ -15,15 +15,15 @@ #include "qom/object.h" #include "qom/qom-qobject.h" #include "qapi/visitor.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qobject-output-visitor.h" void object_property_set_qobject(Object *obj, QObject *value, const char *name, Error **errp) { Visitor *v; /* TODO: Should we reject, rather than ignore, excess input? */ - v = qmp_input_visitor_new(value, false); + v = qobject_input_visitor_new(value, false); object_property_set(obj, v, name, errp); visit_free(v); } @@ -35,7 +35,7 @@ QObject *object_property_get_qobject(Object *obj, const char *name, Error *local_err = NULL; Visitor *v; - v = qmp_output_visitor_new(&ret); + v = qobject_output_visitor_new(&ret); object_property_get(obj, v, name, &local_err); if (!local_err) { visit_complete(v, &ret); diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 2f603b0c0e..09e8467d90 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -68,7 +68,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error *err = NULL; Visitor *v; - v = qmp_output_visitor_new(ret_out); + v = qobject_output_visitor_new(ret_out); visit_type_%(c_name)s(v, "unused", &ret_in, &err); if (!err) { visit_complete(v, ret_out); @@ -130,7 +130,7 @@ def gen_marshal(name, arg_type, boxed, ret_type): push_indent() ret += mcgen(''' - v = qmp_input_visitor_new(QOBJECT(args), true); + v = qobject_input_visitor_new(QOBJECT(args), true); visit_start_struct(v, NULL, NULL, 0, &err); if (err) { goto out; @@ -293,8 +293,8 @@ fdef.write(mcgen(''' #include "qapi/qmp/types.h" #include "qapi/qmp/dispatch.h" #include "qapi/visitor.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-output-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "qapi/dealloc-visitor.h" #include "%(prefix)sqapi-types.h" #include "%(prefix)sqapi-visit.h" diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 38d82111ad..f4eb7f85b1 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -98,7 +98,7 @@ def gen_event_send(name, arg_type, boxed): if arg_type and not arg_type.is_empty(): ret += mcgen(''' - v = qmp_output_visitor_new(&obj); + v = qobject_output_visitor_new(&obj); ''') if not arg_type.is_implicit(): ret += mcgen(''' @@ -209,7 +209,7 @@ fdef.write(mcgen(''' #include "qemu-common.h" #include "%(prefix)sqapi-event.h" #include "%(prefix)sqapi-visit.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/qmp-event.h" ''', diff --git a/target-s390x/cpu_models.c b/target-s390x/cpu_models.c index 3ff6a702f9..c1e729df5e 100644 --- a/target-s390x/cpu_models.c +++ b/target-s390x/cpu_models.c @@ -17,7 +17,7 @@ #include "qapi/visitor.h" #include "qemu/error-report.h" #include "qapi/qmp/qerror.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "qapi/qmp/qbool.h" #ifndef CONFIG_USER_ONLY #include "sysemu/arch_init.h" @@ -345,7 +345,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info, } if (qdict) { - visitor = qmp_input_visitor_new(info->props, true); + visitor = qobject_input_visitor_new(info->props, true); visit_start_struct(visitor, NULL, NULL, 0, errp); if (*errp) { object_unref(obj); diff --git a/tests/.gitignore b/tests/.gitignore index 9f3d2ee038..4aec8bc5fa 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -59,11 +59,11 @@ test-qht-par test-qmp-commands test-qmp-commands.h test-qmp-event -test-qmp-input-strict -test-qmp-input-visitor +test-qobject-input-strict +test-qobject-input-visitor test-qmp-introspect.[ch] test-qmp-marshal.c -test-qmp-output-visitor +test-qobject-output-visitor test-rcu-list test-replication test-rfifolock diff --git a/tests/Makefile.include b/tests/Makefile.include index 73931d1034..cd058efc14 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -22,13 +22,13 @@ check-unit-y += tests/check-qnull$(EXESUF) gcov-files-check-qnull-y = qobject/qnull.c check-unit-y += tests/check-qjson$(EXESUF) gcov-files-check-qjson-y = qobject/qjson.c -check-unit-y += tests/test-qmp-output-visitor$(EXESUF) -gcov-files-test-qmp-output-visitor-y = qapi/qmp-output-visitor.c +check-unit-y += tests/test-qobject-output-visitor$(EXESUF) +gcov-files-test-qobject-output-visitor-y = qapi/qobject-output-visitor.c check-unit-y += tests/test-clone-visitor$(EXESUF) gcov-files-test-clone-visitor-y = qapi/qapi-clone-visitor.c -check-unit-y += tests/test-qmp-input-visitor$(EXESUF) -gcov-files-test-qmp-input-visitor-y = qapi/qmp-input-visitor.c -check-unit-y += tests/test-qmp-input-strict$(EXESUF) +check-unit-y += tests/test-qobject-input-visitor$(EXESUF) +gcov-files-test-qobject-input-visitor-y = qapi/qobject-input-visitor.c +check-unit-y += tests/test-qobject-input-strict$(EXESUF) check-unit-y += tests/test-qmp-commands$(EXESUF) gcov-files-test-qmp-commands-y = qapi/qmp-dispatch.c check-unit-y += tests/test-string-input-visitor$(EXESUF) @@ -452,9 +452,9 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/check-qlist.o tests/check-qfloat.o tests/check-qnull.o \ tests/check-qjson.o \ tests/test-coroutine.o tests/test-string-output-visitor.o \ - tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \ + tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \ tests/test-clone-visitor.o \ - tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ + tests/test-qobject-input-visitor.o tests/test-qobject-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o \ tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \ tests/test-opts-visitor.o tests/test-qmp-event.o \ @@ -558,10 +558,10 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-int tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) -tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) +tests/test-qobject-output-visitor$(EXESUF): tests/test-qobject-output-visitor.o $(test-qapi-obj-y) tests/test-clone-visitor$(EXESUF): tests/test-clone-visitor.o $(test-qapi-obj-y) -tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) -tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) +tests/test-qobject-input-visitor$(EXESUF): tests/test-qobject-input-visitor.o $(test-qapi-obj-y) +tests/test-qobject-input-strict$(EXESUF): tests/test-qobject-input-strict.o $(test-qapi-obj-y) tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) diff --git a/tests/check-qdict.c b/tests/check-qdict.c index 42da1e65a5..07b1c798d8 100644 --- a/tests/check-qdict.c +++ b/tests/check-qdict.c @@ -14,6 +14,7 @@ #include "qapi/qmp/qint.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" +#include "qapi/error.h" #include "qemu-common.h" /* @@ -412,7 +413,6 @@ static void qdict_array_split_test(void) QDECREF(test_dict); - /* * Test the split of * @@ -518,7 +518,6 @@ static void qdict_join_test(void) dict1 = qdict_new(); dict2 = qdict_new(); - /* Test everything once without overwrite and once with */ do { @@ -528,7 +527,6 @@ static void qdict_join_test(void) g_assert(qdict_size(dict1) == 0); g_assert(qdict_size(dict2) == 0); - /* First iteration: Test movement */ /* Second iteration: Test empty source and non-empty destination */ qdict_put(dict2, "foo", qint_from_int(42)); @@ -542,7 +540,6 @@ static void qdict_join_test(void) g_assert(qdict_get_int(dict1, "foo") == 42); } - /* Test non-empty source and destination without conflict */ qdict_put(dict2, "bar", qint_from_int(23)); @@ -554,7 +551,6 @@ static void qdict_join_test(void) g_assert(qdict_get_int(dict1, "foo") == 42); g_assert(qdict_get_int(dict1, "bar") == 23); - /* Test conflict */ qdict_put(dict2, "foo", qint_from_int(84)); @@ -570,7 +566,6 @@ static void qdict_join_test(void) g_assert(qdict_get_int(dict2, "foo") == 84); } - /* Check the references */ g_assert(qdict_get(dict1, "foo")->refcnt == 1); g_assert(qdict_get(dict1, "bar")->refcnt == 1); @@ -579,7 +574,6 @@ static void qdict_join_test(void) g_assert(qdict_get(dict2, "foo")->refcnt == 1); } - /* Clean up */ qdict_del(dict1, "foo"); qdict_del(dict1, "bar"); @@ -590,11 +584,152 @@ static void qdict_join_test(void) } while (overwrite ^= true); - QDECREF(dict1); QDECREF(dict2); } +static void qdict_crumple_test_recursive(void) +{ + QDict *src, *dst, *rule, *vnc, *acl, *listen; + QObject *child, *res; + QList *rules; + + src = qdict_new(); + qdict_put(src, "vnc.listen.addr", qstring_from_str("127.0.0.1")); + qdict_put(src, "vnc.listen.port", qstring_from_str("5901")); + qdict_put(src, "vnc.acl.rules.0.match", qstring_from_str("fred")); + qdict_put(src, "vnc.acl.rules.0.policy", qstring_from_str("allow")); + qdict_put(src, "vnc.acl.rules.1.match", qstring_from_str("bob")); + qdict_put(src, "vnc.acl.rules.1.policy", qstring_from_str("deny")); + qdict_put(src, "vnc.acl.default", qstring_from_str("deny")); + qdict_put(src, "vnc.acl..name", qstring_from_str("acl0")); + qdict_put(src, "vnc.acl.rule..name", qstring_from_str("acl0")); + + res = qdict_crumple(src, &error_abort); + + g_assert_cmpint(qobject_type(res), ==, QTYPE_QDICT); + + dst = qobject_to_qdict(res); + + g_assert_cmpint(qdict_size(dst), ==, 1); + + child = qdict_get(dst, "vnc"); + g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT); + vnc = qobject_to_qdict(child); + + child = qdict_get(vnc, "listen"); + g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT); + listen = qobject_to_qdict(child); + g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr")); + g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port")); + + child = qdict_get(vnc, "acl"); + g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT); + acl = qobject_to_qdict(child); + + child = qdict_get(acl, "rules"); + g_assert_cmpint(qobject_type(child), ==, QTYPE_QLIST); + rules = qobject_to_qlist(child); + g_assert_cmpint(qlist_size(rules), ==, 2); + + rule = qobject_to_qdict(qlist_pop(rules)); + g_assert_cmpint(qdict_size(rule), ==, 2); + g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); + g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); + QDECREF(rule); + + rule = qobject_to_qdict(qlist_pop(rules)); + g_assert_cmpint(qdict_size(rule), ==, 2); + g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); + g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); + QDECREF(rule); + + /* With recursive crumpling, we should see all names unescaped */ + g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); + child = qdict_get(vnc, "acl"); + g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT); + acl = qdict_get_qdict(vnc, "acl"); + g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); + + QDECREF(src); + QDECREF(dst); +} + +static void qdict_crumple_test_empty(void) +{ + QDict *src, *dst; + + src = qdict_new(); + + dst = (QDict *)qdict_crumple(src, &error_abort); + + g_assert_cmpint(qdict_size(dst), ==, 0); + + QDECREF(src); + QDECREF(dst); +} + +static void qdict_crumple_test_bad_inputs(void) +{ + QDict *src; + Error *error = NULL; + + src = qdict_new(); + /* rule.0 can't be both a string and a dict */ + qdict_put(src, "rule.0", qstring_from_str("fred")); + qdict_put(src, "rule.0.policy", qstring_from_str("allow")); + + g_assert(qdict_crumple(src, &error) == NULL); + g_assert(error != NULL); + error_free(error); + error = NULL; + QDECREF(src); + + src = qdict_new(); + /* rule can't be both a list and a dict */ + qdict_put(src, "rule.0", qstring_from_str("fred")); + qdict_put(src, "rule.a", qstring_from_str("allow")); + + g_assert(qdict_crumple(src, &error) == NULL); + g_assert(error != NULL); + error_free(error); + error = NULL; + QDECREF(src); + + src = qdict_new(); + /* The input should be flat, ie no dicts or lists */ + qdict_put(src, "rule.a", qdict_new()); + qdict_put(src, "rule.b", qstring_from_str("allow")); + + g_assert(qdict_crumple(src, &error) == NULL); + g_assert(error != NULL); + error_free(error); + error = NULL; + QDECREF(src); + + src = qdict_new(); + /* List indexes must not have gaps */ + qdict_put(src, "rule.0", qstring_from_str("deny")); + qdict_put(src, "rule.3", qstring_from_str("allow")); + + g_assert(qdict_crumple(src, &error) == NULL); + g_assert(error != NULL); + error_free(error); + error = NULL; + QDECREF(src); + + src = qdict_new(); + /* List indexes must be in %zu format */ + qdict_put(src, "rule.0", qstring_from_str("deny")); + qdict_put(src, "rule.+1", qstring_from_str("allow")); + + g_assert(qdict_crumple(src, &error) == NULL); + g_assert(error != NULL); + error_free(error); + error = NULL; + QDECREF(src); +} + /* * Errors test-cases */ @@ -742,6 +877,13 @@ int main(int argc, char **argv) g_test_add_func("/errors/put_exists", qdict_put_exists_test); g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test); + g_test_add_func("/public/crumple/recursive", + qdict_crumple_test_recursive); + g_test_add_func("/public/crumple/empty", + qdict_crumple_test_empty); + g_test_add_func("/public/crumple/bad_inputs", + qdict_crumple_test_bad_inputs); + /* The Big one */ if (g_test_slow()) { g_test_add_func("/stress/test", qdict_stress_test); diff --git a/tests/check-qnull.c b/tests/check-qnull.c index dc906b116e..b50bb8a81a 100644 --- a/tests/check-qnull.c +++ b/tests/check-qnull.c @@ -10,8 +10,8 @@ #include "qapi/qmp/qobject.h" #include "qemu-common.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/error.h" /* @@ -47,12 +47,12 @@ static void qnull_visit_test(void) g_assert(qnull_.refcnt == 1); obj = qnull(); - v = qmp_input_visitor_new(obj, true); + v = qobject_input_visitor_new(obj, true); qobject_decref(obj); visit_type_null(v, NULL, &error_abort); visit_free(v); - v = qmp_output_visitor_new(&obj); + v = qobject_output_visitor_new(&obj); visit_type_null(v, NULL, &error_abort); visit_complete(v, &obj); g_assert(obj == &qnull_); diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 81cbe545c4..ff944811e8 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -4,7 +4,7 @@ #include "test-qmp-commands.h" #include "qapi/qmp/dispatch.h" #include "qemu/module.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "tests/test-qapi-types.h" #include "tests/test-qapi-visit.h" @@ -244,7 +244,7 @@ static void test_dealloc_partial(void) ud2_dict = qdict_new(); qdict_put_obj(ud2_dict, "string0", QOBJECT(qstring_from_str(text))); - v = qmp_input_visitor_new(QOBJECT(ud2_dict), true); + v = qobject_input_visitor_new(QOBJECT(ud2_dict), true); visit_type_UserDefTwo(v, NULL, &ud2, &err); visit_free(v); QDECREF(ud2_dict); diff --git a/tests/test-qmp-input-strict.c b/tests/test-qobject-input-strict.c index d87f8b89a7..4087ea3dd3 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qobject-input-strict.c @@ -1,5 +1,5 @@ /* - * QMP Input Visitor unit-tests (strict mode). + * QObject Input Visitor unit-tests (strict mode). * * Copyright (C) 2011-2012, 2015 Red Hat Inc. * @@ -15,7 +15,7 @@ #include "qemu-common.h" #include "qapi/error.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" #include "qapi/qmp/types.h" @@ -53,7 +53,7 @@ static Visitor *validate_test_init_internal(TestInputVisitorData *data, data->obj = qobject_from_jsonv(json_string, ap); g_assert(data->obj); - data->qiv = qmp_input_visitor_new(data->obj, true); + data->qiv = qobject_input_visitor_new(data->obj, true); g_assert(data->qiv); return data->qiv; } diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qobject-input-visitor.c index f583dce3ed..26c5012df3 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -1,5 +1,5 @@ /* - * QMP Input Visitor unit-tests. + * QObject Input Visitor unit-tests. * * Copyright (C) 2011-2016 Red Hat Inc. * @@ -14,7 +14,7 @@ #include "qemu-common.h" #include "qapi/error.h" -#include "qapi/qmp-input-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" #include "qapi/qmp/types.h" @@ -49,7 +49,7 @@ static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data, data->obj = qobject_from_jsonv(json_string, ap); g_assert(data->obj); - data->qiv = qmp_input_visitor_new(data->obj, false); + data->qiv = qobject_input_visitor_new(data->obj, false); g_assert(data->qiv); return data->qiv; } @@ -747,10 +747,11 @@ static void test_visitor_in_native_list_number(TestInputVisitorData *data, } static void input_visitor_test_add(const char *testpath, - TestInputVisitorData *data, - void (*test_func)(TestInputVisitorData *data, const void *user_data)) + const void *user_data, + void (*test_func)(TestInputVisitorData *data, + const void *user_data)) { - g_test_add(testpath, TestInputVisitorData, data, NULL, test_func, + g_test_add(testpath, TestInputVisitorData, user_data, NULL, test_func, visitor_input_teardown); } @@ -833,77 +834,64 @@ static void test_visitor_in_wrong_type(TestInputVisitorData *data, int main(int argc, char **argv) { - TestInputVisitorData in_visitor_data; - g_test_init(&argc, &argv, NULL); input_visitor_test_add("/visitor/input/int", - &in_visitor_data, test_visitor_in_int); + NULL, test_visitor_in_int); input_visitor_test_add("/visitor/input/int_overflow", - &in_visitor_data, test_visitor_in_int_overflow); + NULL, test_visitor_in_int_overflow); input_visitor_test_add("/visitor/input/bool", - &in_visitor_data, test_visitor_in_bool); + NULL, test_visitor_in_bool); input_visitor_test_add("/visitor/input/number", - &in_visitor_data, test_visitor_in_number); + NULL, test_visitor_in_number); input_visitor_test_add("/visitor/input/string", - &in_visitor_data, test_visitor_in_string); + NULL, test_visitor_in_string); input_visitor_test_add("/visitor/input/enum", - &in_visitor_data, test_visitor_in_enum); + NULL, test_visitor_in_enum); input_visitor_test_add("/visitor/input/struct", - &in_visitor_data, test_visitor_in_struct); + NULL, test_visitor_in_struct); input_visitor_test_add("/visitor/input/struct-nested", - &in_visitor_data, test_visitor_in_struct_nested); + NULL, test_visitor_in_struct_nested); input_visitor_test_add("/visitor/input/list", - &in_visitor_data, test_visitor_in_list); + NULL, test_visitor_in_list); input_visitor_test_add("/visitor/input/any", - &in_visitor_data, test_visitor_in_any); + NULL, test_visitor_in_any); input_visitor_test_add("/visitor/input/null", - &in_visitor_data, test_visitor_in_null); + NULL, test_visitor_in_null); input_visitor_test_add("/visitor/input/union-flat", - &in_visitor_data, test_visitor_in_union_flat); + NULL, test_visitor_in_union_flat); input_visitor_test_add("/visitor/input/alternate", - &in_visitor_data, test_visitor_in_alternate); + NULL, test_visitor_in_alternate); input_visitor_test_add("/visitor/input/errors", - &in_visitor_data, test_visitor_in_errors); + NULL, test_visitor_in_errors); input_visitor_test_add("/visitor/input/wrong-type", - &in_visitor_data, test_visitor_in_wrong_type); + NULL, test_visitor_in_wrong_type); input_visitor_test_add("/visitor/input/alternate-number", - &in_visitor_data, test_visitor_in_alternate_number); + NULL, test_visitor_in_alternate_number); input_visitor_test_add("/visitor/input/native_list/int", - &in_visitor_data, - test_visitor_in_native_list_int); + NULL, test_visitor_in_native_list_int); input_visitor_test_add("/visitor/input/native_list/int8", - &in_visitor_data, - test_visitor_in_native_list_int8); + NULL, test_visitor_in_native_list_int8); input_visitor_test_add("/visitor/input/native_list/int16", - &in_visitor_data, - test_visitor_in_native_list_int16); + NULL, test_visitor_in_native_list_int16); input_visitor_test_add("/visitor/input/native_list/int32", - &in_visitor_data, - test_visitor_in_native_list_int32); + NULL, test_visitor_in_native_list_int32); input_visitor_test_add("/visitor/input/native_list/int64", - &in_visitor_data, - test_visitor_in_native_list_int64); + NULL, test_visitor_in_native_list_int64); input_visitor_test_add("/visitor/input/native_list/uint8", - &in_visitor_data, - test_visitor_in_native_list_uint8); + NULL, test_visitor_in_native_list_uint8); input_visitor_test_add("/visitor/input/native_list/uint16", - &in_visitor_data, - test_visitor_in_native_list_uint16); + NULL, test_visitor_in_native_list_uint16); input_visitor_test_add("/visitor/input/native_list/uint32", - &in_visitor_data, - test_visitor_in_native_list_uint32); + NULL, test_visitor_in_native_list_uint32); input_visitor_test_add("/visitor/input/native_list/uint64", - &in_visitor_data, - test_visitor_in_native_list_uint64); + NULL, test_visitor_in_native_list_uint64); input_visitor_test_add("/visitor/input/native_list/bool", - &in_visitor_data, test_visitor_in_native_list_bool); + NULL, test_visitor_in_native_list_bool); input_visitor_test_add("/visitor/input/native_list/str", - &in_visitor_data, - test_visitor_in_native_list_string); + NULL, test_visitor_in_native_list_string); input_visitor_test_add("/visitor/input/native_list/number", - &in_visitor_data, - test_visitor_in_native_list_number); + NULL, test_visitor_in_native_list_number); g_test_run(); diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qobject-output-visitor.c index 513d71f0d1..4e2d79c5d1 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qobject-output-visitor.c @@ -1,5 +1,5 @@ /* - * QMP Output Visitor unit-tests. + * QObject Output Visitor unit-tests. * * Copyright (C) 2011-2016 Red Hat Inc. * @@ -14,7 +14,7 @@ #include "qemu-common.h" #include "qapi/error.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" #include "qapi/qmp/types.h" @@ -28,7 +28,7 @@ typedef struct TestOutputVisitorData { static void visitor_output_setup(TestOutputVisitorData *data, const void *unused) { - data->ov = qmp_output_visitor_new(&data->obj); + data->ov = qobject_output_visitor_new(&data->obj); g_assert(data->ov); } diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index a679fbc678..7f10e2582f 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -4,7 +4,7 @@ * Copyright (C) 2012 Red Hat Inc. * * Authors: - * Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-input-visitor) + * Paolo Bonzini <pbonzini@redhat.com> (based on test-qobject-input-visitor) * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 444844a15a..e736db3af8 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -4,7 +4,7 @@ * Copyright (C) 2012 Red Hat Inc. * * Authors: - * Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-output-visitor) + * Paolo Bonzini <pbonzini@redhat.com> (based on test-qobject-output-visitor) * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index dba4670762..66b2b1c564 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -20,8 +20,8 @@ #include "qapi/error.h" #include "qapi/qmp/types.h" #include "qapi/qmp/qjson.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" #include "qapi-types.h" @@ -1022,7 +1022,7 @@ static void qmp_serialize(void *native_in, void **datap, { QmpSerializeData *d = g_malloc0(sizeof(*d)); - d->qov = qmp_output_visitor_new(&d->obj); + d->qov = qobject_output_visitor_new(&d->obj); visit(d->qov, &native_in, errp); *datap = d; } @@ -1040,7 +1040,7 @@ static void qmp_deserialize(void **native_out, void *datap, obj = qobject_from_json(qstring_get_str(output_json)); QDECREF(output_json); - d->qiv = qmp_input_visitor_new(obj, true); + d->qiv = qobject_input_visitor_new(obj, true); qobject_decref(obj_orig); qobject_decref(obj); visit(d->qiv, native_out, errp); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 6db48b3f2e..4cef549d90 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -21,8 +21,8 @@ #include "qapi/error.h" #include "qemu/sockets.h" #include "qemu/main-loop.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/qmp-output-visitor.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qobject-output-visitor.h" #include "qapi-visit.h" #include "qemu/cutils.h" |