From 006ca09f3027d86346fce707e9295975c6558f42 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 Jun 2017 13:52:24 +0200 Subject: qapi: Separate type QNull from QObject Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Daniel P. Berrange --- include/qapi/qmp/qobject.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index b8ddbca405..3543b552f4 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -93,11 +93,15 @@ static inline QType qobject_type(const QObject *obj) return obj->type; } -extern QObject qnull_; +typedef struct QNull { + QObject base; +} QNull; -static inline QObject *qnull(void) +extern QNull qnull_; + +static inline QNull *qnull(void) { - qobject_incref(&qnull_); + QINCREF(&qnull_); return &qnull_; } -- cgit v1.2.3-55-g7522 From d2f95f4d482374485234790a6fc3cca29ebb7355 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 Jun 2017 18:22:59 +0200 Subject: qapi: Use QNull for a more regular visit_type_null() Make visit_type_null() take an @obj argument like its buddies. This helps keep the next commit simple. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Daniel P. Berrange --- hw/ppc/spapr_drc.c | 4 +++- include/qapi/visitor-impl.h | 3 ++- include/qapi/visitor.h | 8 ++++---- qapi/qapi-clone-visitor.c | 5 +++-- qapi/qapi-dealloc-visitor.c | 6 +++++- qapi/qapi-visit-core.c | 7 ++++--- qapi/qobject-input-visitor.c | 6 +++++- qapi/qobject-output-visitor.c | 3 ++- qapi/string-input-visitor.c | 8 +++++++- qapi/string-output-visitor.c | 3 ++- qapi/trace-events | 2 +- target/ppc/translate_init.c | 5 ++++- tests/check-qnull.c | 9 +++++++-- tests/test-qobject-input-visitor.c | 13 +++++++++---- tests/test-qobject-output-visitor.c | 3 ++- 15 files changed, 60 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 0ffcec6fb2..15bae5c216 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -297,12 +297,14 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj); + QNull *null = NULL; Error *err = NULL; int fdt_offset_next, fdt_offset, fdt_depth; void *fdt; if (!drc->fdt) { - visit_type_null(v, NULL, errp); + visit_type_null(v, NULL, &null, errp); + QDECREF(null); return; } diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index dcd656ab76..8ccb3b6c20 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -103,7 +103,8 @@ struct Visitor Error **errp); /* Must be set to visit explicit null values. */ - void (*type_null)(Visitor *v, const char *name, Error **errp); + void (*type_null)(Visitor *v, const char *name, QNull **obj, + Error **errp); /* Must be set for input visitors to visit structs, optional otherwise. The core takes care of the return type in the public interface. */ diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 74768aabda..fe9faf469f 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -618,10 +618,10 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); * @name expresses the relationship of the null value to its parent * container; see the general description of @name above. * - * Unlike all other visit_type_* functions, no obj parameter is - * needed; rather, this is a witness that an explicit null value is - * expected rather than any other type. + * @obj must be non-NULL. Input visitors set *@obj to the value; + * other visitors ignore *@obj. */ -void visit_type_null(Visitor *v, const char *name, Error **errp); +void visit_type_null(Visitor *v, const char *name, QNull **obj, + Error **errp); #endif diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c index ed16d3a17f..d8b62792bc 100644 --- a/qapi/qapi-clone-visitor.c +++ b/qapi/qapi-clone-visitor.c @@ -127,12 +127,13 @@ static void qapi_clone_type_number(Visitor *v, const char *name, double *obj, /* Value was already cloned by g_memdup() */ } -static void qapi_clone_type_null(Visitor *v, const char *name, Error **errp) +static void qapi_clone_type_null(Visitor *v, const char *name, QNull **obj, + Error **errp) { QapiCloneVisitor *qcv = to_qcv(v); assert(qcv->depth); - /* Nothing to do */ + *obj = qnull(); } static void qapi_clone_free(Visitor *v) diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index fd6f9fb61c..ed70a0158b 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -103,8 +103,12 @@ static void qapi_dealloc_type_anything(Visitor *v, const char *name, } } -static void qapi_dealloc_type_null(Visitor *v, const char *name, Error **errp) +static void qapi_dealloc_type_null(Visitor *v, const char *name, + QNull **obj, Error **errp) { + if (obj) { + QDECREF(*obj); + } } static void qapi_dealloc_free(Visitor *v) diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 935a2c5bc9..ed6d2af462 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -325,10 +325,11 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) error_propagate(errp, err); } -void visit_type_null(Visitor *v, const char *name, Error **errp) +void visit_type_null(Visitor *v, const char *name, QNull **obj, + Error **errp) { - trace_visit_type_null(v, name); - v->type_null(v, name, errp); + trace_visit_type_null(v, name, obj); + v->type_null(v, name, obj, errp); } static void output_type_enum(Visitor *v, const char *name, int *obj, diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 35aff78f2b..ee9e47d911 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -587,11 +587,13 @@ static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, *obj = qobj; } -static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) +static void qobject_input_type_null(Visitor *v, const char *name, + QNull **obj, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); QObject *qobj = qobject_input_get_object(qiv, name, true, errp); + *obj = NULL; if (!qobj) { return; } @@ -599,7 +601,9 @@ static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) if (qobject_type(qobj) != QTYPE_QNULL) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, full_name(qiv, name), "null"); + return; } + *obj = qnull(); } static void qobject_input_type_size_keyval(Visitor *v, const char *name, diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c index 398dcb5cee..d325163e55 100644 --- a/qapi/qobject-output-visitor.c +++ b/qapi/qobject-output-visitor.c @@ -187,7 +187,8 @@ static void qobject_output_type_any(Visitor *v, const char *name, qobject_output_add_obj(qov, name, *obj); } -static void qobject_output_type_null(Visitor *v, const char *name, Error **errp) +static void qobject_output_type_null(Visitor *v, const char *name, + QNull **obj, Error **errp) { QObjectOutputVisitor *qov = to_qov(v); qobject_output_add(qov, name, qnull()); diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 63ae115b2a..67a0a4a58b 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -326,14 +326,20 @@ static void parse_type_number(Visitor *v, const char *name, double *obj, *obj = val; } -static void parse_type_null(Visitor *v, const char *name, Error **errp) +static void parse_type_null(Visitor *v, const char *name, QNull **obj, + Error **errp) { StringInputVisitor *siv = to_siv(v); + *obj = NULL; + if (!siv->string || siv->string[0]) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "null"); + return; } + + *obj = qnull(); } static void string_input_free(Visitor *v) diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index af649e1d6e..7ab64468d9 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -256,7 +256,8 @@ static void print_type_number(Visitor *v, const char *name, double *obj, string_output_set(sov, g_strdup_printf("%f", *obj)); } -static void print_type_null(Visitor *v, const char *name, Error **errp) +static void print_type_null(Visitor *v, const char *name, QNull **obj, + Error **errp) { StringOutputVisitor *sov = to_sov(v); char *out; diff --git a/qapi/trace-events b/qapi/trace-events index 3b57abaa37..9e9008a1dc 100644 --- a/qapi/trace-events +++ b/qapi/trace-events @@ -31,4 +31,4 @@ 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" +visit_type_null(void *v, const char *name, void *obj) "v=%p name=%s obj=%p" diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index b325c2cce6..01723bdfec 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -8428,11 +8428,14 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { + QNull *null = NULL; + if (!qtest_enabled()) { error_report("CPU 'compat' property is deprecated and has no effect; " "use max-cpu-compat machine property instead"); } - visit_type_null(v, name, NULL); + visit_type_null(v, name, &null, NULL); + QDECREF(null); } static const PropertyInfo ppc_compat_deprecated_propinfo = { diff --git a/tests/check-qnull.c b/tests/check-qnull.c index 1ab7c983a5..5c6eb0adc8 100644 --- a/tests/check-qnull.c +++ b/tests/check-qnull.c @@ -38,6 +38,7 @@ static void qnull_visit_test(void) { QObject *obj; Visitor *v; + QNull *null; /* * Most tests of interactions between QObject and visitors are in @@ -49,13 +50,17 @@ static void qnull_visit_test(void) obj = QOBJECT(qnull()); v = qobject_input_visitor_new(obj); qobject_decref(obj); - visit_type_null(v, NULL, &error_abort); + visit_type_null(v, NULL, &null, &error_abort); + g_assert(obj == QOBJECT(&qnull_)); + QDECREF(null); visit_free(v); + null = NULL; v = qobject_output_visitor_new(&obj); - visit_type_null(v, NULL, &error_abort); + visit_type_null(v, NULL, &null, &error_abort); visit_complete(v, &obj); g_assert(obj == QOBJECT(&qnull_)); + QDECREF(null); qobject_decref(obj); visit_free(v); diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c index 34bab8a913..f98caf9818 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -510,6 +510,7 @@ static void test_visitor_in_null(TestInputVisitorData *data, { Visitor *v; Error *err = NULL; + QNull *null; char *tmp; /* @@ -524,12 +525,15 @@ static void test_visitor_in_null(TestInputVisitorData *data, v = visitor_input_test_init_full(data, false, "{ 'a': null, 'b': '' }"); visit_start_struct(v, NULL, NULL, 0, &error_abort); - visit_type_null(v, "a", &error_abort); - visit_type_null(v, "b", &err); + visit_type_null(v, "a", &null, &error_abort); + g_assert(qobject_type(QOBJECT(null)) == QTYPE_QNULL); + QDECREF(null); + visit_type_null(v, "b", &null, &err); error_free_or_abort(&err); + g_assert(!null); visit_type_str(v, "c", &tmp, &err); - g_assert(!tmp); error_free_or_abort(&err); + g_assert(!tmp); visit_check_struct(v, &error_abort); visit_end_struct(v, NULL); } @@ -1087,6 +1091,7 @@ static void test_visitor_in_fail_struct_missing(TestInputVisitorData *data, Error *err = NULL; Visitor *v; QObject *any; + QNull *null; GenericAlternate *alt; bool present; int en; @@ -1120,7 +1125,7 @@ static void test_visitor_in_fail_struct_missing(TestInputVisitorData *data, error_free_or_abort(&err); visit_type_any(v, "any", &any, &err); error_free_or_abort(&err); - visit_type_null(v, "null", &err); + visit_type_null(v, "null", &null, &err); error_free_or_abort(&err); visit_start_list(v, "sub", NULL, 0, &error_abort); visit_start_struct(v, NULL, NULL, 0, &error_abort); diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c index 749c54065f..8f1fcd49cb 100644 --- a/tests/test-qobject-output-visitor.c +++ b/tests/test-qobject-output-visitor.c @@ -445,11 +445,12 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, static void test_visitor_out_null(TestOutputVisitorData *data, const void *unused) { + QNull *null = NULL; QDict *qdict; QObject *nil; visit_start_struct(data->ov, NULL, NULL, 0, &error_abort); - visit_type_null(data->ov, "a", &error_abort); + visit_type_null(data->ov, "a", &null, &error_abort); visit_check_struct(data->ov, &error_abort); visit_end_struct(data->ov, NULL); qdict = qobject_to_qdict(visitor_get(data)); -- cgit v1.2.3-55-g7522 From 4d2d5c41a9e8ee201cda8be8701f7f9fc92e71aa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 26 Jun 2017 19:25:14 +0200 Subject: qapi: Introduce a first class 'null' type I expect the 'null' type to be useful mostly for members of alternate types. Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrange Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- docs/devel/qapi-code-gen.txt | 10 ++++++---- include/qapi/qmp/qobject.h | 4 ++-- include/qemu/typedefs.h | 1 + scripts/qapi.py | 5 ++++- tests/qapi-schema/qapi-schema-test.json | 3 ++- tests/qapi-schema/qapi-schema-test.out | 1 + tests/test-qobject-input-visitor.c | 5 +++++ tests/test-qobject-output-visitor.c | 10 ++++++++++ 8 files changed, 31 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 52e3874efe..9903ac4c19 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -282,6 +282,7 @@ The following types are predefined, and map to C as follows: size uint64_t like uint64_t, except StringInputVisitor accepts size suffixes bool bool JSON true or false + null QNull * JSON null any QObject * any JSON value QType QType JSON string matching enum QType values @@ -536,10 +537,11 @@ can only express a choice between types represented differently in JSON. If a branch is typed as the 'bool' built-in, the alternate accepts true and false; if it is typed as any of the various numeric built-ins, it accepts a JSON number; if it is typed as a 'str' -built-in or named enum type, it accepts a JSON string; and if it is -typed as a complex type (struct or union), it accepts a JSON object. -Two different complex types, for instance, aren't permitted, because -both are represented as a JSON object. +built-in or named enum type, it accepts a JSON string; if it is typed +as the 'null' built-in, it accepts JSON null; and if it is typed as a +complex type (struct or union), it accepts a JSON object. Two +different complex types, for instance, aren't permitted, because both +are represented as a JSON object. The example alternate declaration above allows using both of the following example objects: diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 3543b552f4..eab29edd12 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -93,9 +93,9 @@ static inline QType qobject_type(const QObject *obj) return obj->type; } -typedef struct QNull { +struct QNull { QObject base; -} QNull; +}; extern QNull qnull_; diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 7b0d4e7e05..39bc8351a3 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -89,6 +89,7 @@ typedef struct QEMUSGList QEMUSGList; typedef struct QEMUTimer QEMUTimer; typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QObject QObject; +typedef struct QNull QNull; typedef struct RAMBlock RAMBlock; typedef struct Range Range; typedef struct SerialState SerialState; diff --git a/scripts/qapi.py b/scripts/qapi.py index 84e2eb441b..8aa2775f12 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -20,6 +20,7 @@ import sys from ordereddict import OrderedDict builtin_types = { + 'null': 'QTYPE_QNULL', 'str': 'QTYPE_QSTRING', 'int': 'QTYPE_QNUM', 'number': 'QTYPE_QNUM', @@ -1056,6 +1057,7 @@ class QAPISchemaType(QAPISchemaEntity): def alternate_qtype(self): json2qtype = { + 'null': 'QTYPE_QNULL', 'string': 'QTYPE_QSTRING', 'number': 'QTYPE_QNUM', 'int': 'QTYPE_QNUM', @@ -1515,7 +1517,8 @@ class QAPISchema(object): ('uint64', 'int', 'uint64_t'), ('size', 'int', 'uint64_t'), ('bool', 'boolean', 'bool'), - ('any', 'value', 'QObject' + pointer_suffix)]: + ('any', 'value', 'QObject' + pointer_suffix), + ('null', 'null', 'QNull' + pointer_suffix)]: self._def_builtin_type(*t) self.the_empty_object_type = QAPISchemaObjectType( 'q_empty', None, None, None, [], None) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 91ffb2648c..c72dbd8050 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -93,7 +93,8 @@ { 'struct': 'WrapAlternate', 'data': { 'alt': 'UserDefAlternate' } } { 'alternate': 'UserDefAlternate', - 'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int' } } + 'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int', + 'n': 'null' } } { 'struct': 'UserDefC', 'data': { 'string1': 'str', 'string2': 'str' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index b88b8aae6f..3b1e9082d3 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -64,6 +64,7 @@ alternate UserDefAlternate case udfu: UserDefFlatUnion case e: EnumOne case i: int + case n: null object UserDefB member intb: int optional=False member a-b: bool optional=True diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c index f98caf9818..f4518441d3 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -583,6 +583,11 @@ static void test_visitor_in_alternate(TestInputVisitorData *data, g_assert_cmpint(tmp->u.e, ==, ENUM_ONE_VALUE1); qapi_free_UserDefAlternate(tmp); + v = visitor_input_test_init(data, "null"); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->type, ==, QTYPE_QNULL); + qapi_free_UserDefAlternate(tmp); + v = visitor_input_test_init(data, "{'integer':1, 'string':'str', " "'enum1':'value1', 'boolean':true}"); visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c index 8f1fcd49cb..7eb162059c 100644 --- a/tests/test-qobject-output-visitor.c +++ b/tests/test-qobject-output-visitor.c @@ -422,6 +422,16 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, qapi_free_UserDefAlternate(tmp); + visitor_reset(data); + tmp = g_new0(UserDefAlternate, 1); + tmp->type = QTYPE_QNULL; + tmp->u.n = qnull(); + + visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); + g_assert_cmpint(qobject_type(visitor_get(data)), ==, QTYPE_QNULL); + + qapi_free_UserDefAlternate(tmp); + visitor_reset(data); tmp = g_new0(UserDefAlternate, 1); tmp->type = QTYPE_QDICT; -- cgit v1.2.3-55-g7522