From nobody Mon Feb 9 16:19:30 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1487673892499823.7302303468958; Tue, 21 Feb 2017 02:44:52 -0800 (PST) Received: from localhost ([::1]:43580 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cg7wA-0000SO-3D for importer@patchew.org; Tue, 21 Feb 2017 05:44:50 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48984) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cg7uQ-0007qp-Kl for qemu-devel@nongnu.org; Tue, 21 Feb 2017 05:43:04 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cg7uO-0002u3-GZ for qemu-devel@nongnu.org; Tue, 21 Feb 2017 05:43:02 -0500 Received: from mail-wm0-x242.google.com ([2a00:1450:400c:c09::242]:33184) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cg7uO-0002tp-6E for qemu-devel@nongnu.org; Tue, 21 Feb 2017 05:43:00 -0500 Received: by mail-wm0-x242.google.com with SMTP id v77so18936766wmv.0 for ; Tue, 21 Feb 2017 02:43:00 -0800 (PST) Received: from donizetti.lan (94-39-187-56.adsl-ull.clienti.tiscali.it. [94.39.187.56]) by smtp.gmail.com with ESMTPSA id u189sm17046499wmu.1.2017.02.21.02.42.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 21 Feb 2017 02:42:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=ZRV4cHGZr4M2hT+DWXt8qREwXzb/Zyy0bHfyLXu6uFc=; b=rgSBUrDt1oi6/ugO9/a9uYyEr96elD7IJNaKdW4JelGYPaP4DT94+ICk4BvZHOlprc KffhvHcjjwmQNrFeflo2i8I+iKo81C4GaJ5KCPOaWyTfEiYtZJZgV3bOLB/R4H/M0maj WG7UlT+MzA3y9HcbLAwtmUBOMzLuxyFzNIO42BwWm7II1VXh+/kdcONQ1gs+b1ZtVHYm jF4eO0Xo/ZWplPKa6XdjYOCe6Xvp6rZmun/4dKPws+4NXaA1iXFqx38uECdC+qlYUN8U zTWKDwkhYhnM12b4WNMFZ1zxq8nRkI90C4qxqusXI7purjzWhLoecGiQIaiLBJ0ctXT9 BYqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=ZRV4cHGZr4M2hT+DWXt8qREwXzb/Zyy0bHfyLXu6uFc=; b=sEt958zE9t37EHlZ0aZB+ZyKDuPfQGoUEFEBQQQLLk8iyqv2IjE0mZap3+xQDeY6YF eCYPlW8m+L8mwWzVMLC+yLDq7y8qgPbL5/pPllvJTx8cQSgBNLyT3EQprVGI1z2dYvr2 BmcW/P7dPn5Idi+jT5/Qz87ZSnIZc0mJyOqFE9V8fbg9jMB1RcJBL8FZXIUvz0bx0ovM jKGHwcdvWIsIGixZc2KdGrMbOMt4rGRTpCX7NKNsNA4e1g2EKb8Q5ut5aewiYJGA9hOa HLfwLrGHyNPmoY/IXXyLYdbKBuLwlZk2mCOgedfvL7G4XSa9mpSC0iGfvGLtyU+uZ+et Prdg== X-Gm-Message-State: AMke39m4BwrOyDobowgGEaFSe4jI0n9Kd+1+BpQkZF0FjM6dxnwjHlkgebmSFyWt0Pem0A== X-Received: by 10.28.8.213 with SMTP id 204mr14125391wmi.100.1487673778870; Tue, 21 Feb 2017 02:42:58 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Tue, 21 Feb 2017 11:42:54 +0100 Message-Id: <20170221104256.5153-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170221104256.5153-1-pbonzini@redhat.com> References: <20170221104256.5153-1-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::242 Subject: [Qemu-devel] [PATCH 1/3] qom-qobject: introduce object_property_{g, s}et_ptr X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: den@openvz.org, anton.nefedov@virtuozzo.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The functions simplify the handling of QOM properties whose type is a QAPI struct. They go through a QObject just like the other functions that access a QOM property through its C type. Like QAPI_CLONE, the functions are wrapped by macros that take a QAPI type name and use it to build the name of a visitor function. Signed-off-by: Paolo Bonzini --- include/qom/qom-qobject.h | 68 ++++++++++++ qom/qom-qobject.c | 49 +++++++++ tests/Makefile.include | 2 +- tests/check-qom-proplist.c | 185 ++++++++++++++++++++++++++++= +++- tests/qapi-schema/qapi-schema-test.json | 8 ++ 5 files changed, 309 insertions(+), 3 deletions(-) diff --git a/include/qom/qom-qobject.h b/include/qom/qom-qobject.h index 77cd717..ff1d307 100644 --- a/include/qom/qom-qobject.h +++ b/include/qom/qom-qobject.h @@ -39,4 +39,72 @@ struct QObject *object_property_get_qobject(Object *obj,= const char *name, void object_property_set_qobject(Object *obj, struct QObject *qobj, const char *name, struct Error **errp); =20 +/** + * object_property_get_ptr: + * @obj: the object + * @ptr: The C struct that will be written to the property. + * @name: the name of the property + * @visit_type: the visitor function for @ptr's type. + * @errp: returns an error if this function fails + * + * Return: the value of an object's property, unmarshaled into a C object + * through a QAPI type visitor, or NULL if an error occurs. + */ +void *object_property_get_ptr(Object *obj, const char *name, + void (*visit_type)(Visitor *, const char *, + void **, Error **), + Error **errp); + +/** + * OBJECT_PROPERTY_GET_PTR: + * @obj: the object + * @ptr: The C struct that will be written to the property. + * @name: the name of the property + * @type: the name of the C struct type pointed to by @ptr. + * @errp: returns an error if this function fails + * + * Return: the value of an object's property, unmarshaled into a C object + * through a QAPI type visitor, or NULL if an error occurs. + */ +#define OBJECT_PROPERTY_GET_PTR(obj, name, type, errp) = \ + ((type *) = \ + object_property_get_ptr(obj, name, = \ + (void (*)(Visitor *, const char *, void**, = \ + Error **))visit_type_ ## type, = \ + errp)) + +/** + * object_property_set_ptr: + * @obj: the object + * @ptr: The C struct that will be written to the property. + * @name: the name of the property + * @visit_type: the visitor function for @ptr's type. + * @errp: returns an error if this function fails + * + * Sets an object's property to a C object's value, using a QAPI + * type visitor to marshal the C struct into the object. + */ +void object_property_set_ptr(Object *obj, void *ptr, const char *name, + void (*visit_type)(Visitor *, const char *, + void **, Error **), + Error **errp); + +/** + * OBJECT_PROPERTY_SET_PTR: + * @obj: the object + * @ptr: The C struct that will be written to the property. + * @name: the name of the property + * @type: the name of the C struct type pointed to by @ptr. + * @errp: returns an error if this function fails + * + * Sets an object's property to a C object's value, using a QAPI + * type visitor to marshal the C struct into the object. + */ +#define OBJECT_PROPERTY_SET_PTR(obj, ptr, name, type, errp) = \ + object_property_set_ptr(obj, ptr + type_check(type, typeof(*ptr)), = \ + name, = \ + (void (*)(Visitor *, const char *, void**, = \ + Error **))visit_type_ ## type, = \ + errp) + #endif diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c index 447e4a0..09a12e0 100644 --- a/qom/qom-qobject.c +++ b/qom/qom-qobject.c @@ -44,3 +44,52 @@ QObject *object_property_get_qobject(Object *obj, const = char *name, visit_free(v); return ret; } + +void object_property_set_ptr(Object *obj, void *ptr, const char *name, + void (*visit_type)(Visitor *, const char *, v= oid **, Error **), + Error **errp) +{ + Error *local_err =3D NULL; + QObject *ret =3D NULL; + Visitor *v; + v =3D qobject_output_visitor_new(&ret); + visit_type(v, name, &ptr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + visit_free(v); + return; + } + visit_complete(v, &ret); + visit_free(v); + + /* Do not use object_property_set_qobject until we switch it + * to use qobject_input_visitor_new in strict mode. See the + * /qom/proplist/get-set-ptr/contravariant unit test. + */ + v =3D qobject_input_visitor_new(ret, true); + object_property_set(obj, v, name, errp); + visit_free(v); + qobject_decref(ret); +} + +void *object_property_get_ptr(Object *obj, const char *name, + void (*visit_type)(Visitor *, const char *, = void **, Error **), + Error **errp) +{ + QObject *ret; + Visitor *v; + void *ptr =3D NULL; + + ret =3D object_property_get_qobject(obj, name, errp); + if (!ret) { + return NULL; + } + + /* Do not enable strict mode to allow passing covariant + * data types. + */ + v =3D qobject_input_visitor_new(ret, false); + visit_type(v, name, &ptr, errp); + qobject_decref(ret); + return ptr; +} diff --git a/tests/Makefile.include b/tests/Makefile.include index 634394a..9de910b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -515,7 +515,7 @@ tests/check-qfloat$(EXESUF): tests/check-qfloat.o $(tes= t-util-obj-y) tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y) tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y) tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom= -obj-y) -tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-o= bj-y) +tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-o= bj-y) $(test-qapi-obj-y) =20 tests/test-char$(EXESUF): tests/test-char.o qemu-timer.o \ $(test-util-obj-y) $(qtest-obj-y) $(test-block-obj-y) $(chardev-obj-y) diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index a16cefc..e0ad880 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -22,8 +22,11 @@ =20 #include "qapi/error.h" #include "qom/object.h" +#include "qom/qom-qobject.h" #include "qemu/module.h" =20 +#include "test-qapi-types.h" +#include "test-qapi-visit.h" =20 #define TYPE_DUMMY "qemu-dummy" =20 @@ -56,6 +59,8 @@ struct DummyObject { bool bv; DummyAnimal av; char *sv; + + UserDefOne *qv; }; =20 struct DummyObjectClass { @@ -120,12 +125,42 @@ static char *dummy_get_sv(Object *obj, =20 static void dummy_init(Object *obj) { + DummyObject *dobj =3D DUMMY_OBJECT(obj); + object_property_add_bool(obj, "bv", dummy_get_bv, dummy_set_bv, NULL); + dobj->qv =3D g_new0(UserDefOne, 1); + dobj->qv->string =3D g_strdup("dummy string"); +} + + +static void dummy_get_qv(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DummyObject *dobj =3D DUMMY_OBJECT(obj); + + visit_type_UserDefOne(v, name, &dobj->qv, errp); } =20 +static void dummy_set_qv(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DummyObject *dobj =3D DUMMY_OBJECT(obj); + UserDefOne *qv =3D NULL; + Error *local_err =3D NULL; + + visit_type_UserDefOne(v, name, &qv, &local_err); + if (local_err) { + g_assert(qv =3D=3D NULL); + error_propagate(errp, local_err); + return; + } + + qapi_free_UserDefOne(dobj->qv); + dobj->qv =3D qv; +} =20 static void dummy_class_init(ObjectClass *cls, void *data) { @@ -143,6 +178,13 @@ static void dummy_class_init(ObjectClass *cls, void *d= ata) dummy_get_av, dummy_set_av, NULL); + object_class_property_add(cls, "qv", + "UserDefOne", + dummy_get_qv, + dummy_set_qv, + NULL, + NULL, + NULL); } =20 =20 @@ -151,9 +193,9 @@ static void dummy_finalize(Object *obj) DummyObject *dobj =3D DUMMY_OBJECT(obj); =20 g_free(dobj->sv); + qapi_free_UserDefOne(dobj->qv); } =20 - static const TypeInfo dummy_info =3D { .name =3D TYPE_DUMMY, .parent =3D TYPE_OBJECT, @@ -473,7 +515,8 @@ static void test_dummy_iterator(void) =20 ObjectProperty *prop; ObjectPropertyIterator iter; - bool seenbv =3D false, seensv =3D false, seenav =3D false, seentype; + bool seenbv =3D false, seensv =3D false, seenav =3D false; + bool seenqv =3D false, seentype =3D false; =20 object_property_iter_init(&iter, OBJECT(dobj)); while ((prop =3D object_property_iter_next(&iter))) { @@ -483,6 +526,8 @@ static void test_dummy_iterator(void) seensv =3D true; } else if (g_str_equal(prop->name, "av")) { seenav =3D true; + } else if (g_str_equal(prop->name, "qv")) { + seenqv =3D true; } else if (g_str_equal(prop->name, "type")) { /* This prop comes from the base Object class */ seentype =3D true; @@ -494,6 +539,7 @@ static void test_dummy_iterator(void) g_assert(seenbv); g_assert(seenav); g_assert(seensv); + g_assert(seenqv); g_assert(seentype); =20 object_unparent(OBJECT(dobj)); @@ -513,6 +559,137 @@ static void test_dummy_delchild(void) object_unparent(OBJECT(dev)); } =20 +static void test_dummy_get_set_ptr_struct(void) +{ + DummyObject *dobj =3D DUMMY_OBJECT(object_new(TYPE_DUMMY)); + Error *local_err =3D NULL; + const char *s =3D "my other dummy string"; + UserDefOne *ret; + UserDefOne val; + + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "qv", + UserDefOne, &local_err); + g_assert(!local_err); + + g_assert_cmpint(ret->integer, =3D=3D, 0); + g_assert_cmpstr(ret->string, =3D=3D, "dummy string"); + g_assert(!ret->has_enum1); + qapi_free_UserDefOne(ret); + + val.integer =3D 42; + val.string =3D g_strdup(s); + val.has_enum1 =3D true; + val.enum1 =3D ENUM_ONE_VALUE1; + OBJECT_PROPERTY_SET_PTR(OBJECT(dobj), &val, "qv", + UserDefOne, &local_err); + g_assert(!local_err); + + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "qv", + UserDefOne, &local_err); + g_assert(!local_err); + + g_assert_cmpint(ret->integer, =3D=3D, val.integer); + g_assert_cmpstr(ret->string, =3D=3D, val.string); + g_assert(ret->has_enum1); + g_assert_cmpint(ret->enum1, =3D=3D, val.enum1); + g_free(val.string); + qapi_free_UserDefOne(ret); +} + +static void test_dummy_get_set_ptr_contravariant(void) +{ + DummyObject *dobj =3D DUMMY_OBJECT(object_new(TYPE_DUMMY)); + Error *local_err =3D NULL; + UserDefOneMore *ret; + UserDefOneMore val; + + /* You cannot retrieve a contravariant (subclass) type... */ + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "qv", + UserDefOneMore, &local_err); + g_assert(local_err); + g_assert(!ret); + error_free(local_err); + local_err =3D NULL; + + /* And you cannot set one either. */ + val.integer =3D 42; + val.string =3D g_strdup("unused"); + val.has_enum1 =3D false; + val.boolean =3D false; + + OBJECT_PROPERTY_SET_PTR(OBJECT(dobj), &val, "qv", + UserDefOneMore, &local_err); + g_assert(local_err); +} + +static void test_dummy_get_set_ptr_covariant(void) +{ + DummyObject *dobj =3D DUMMY_OBJECT(object_new(TYPE_DUMMY)); + Error *local_err =3D NULL; + UserDefZero *ret; + UserDefZero val; + + /* You can retrieve a covariant (superclass) type... */ + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "qv", + UserDefZero, &local_err); + g_assert(!local_err); + + g_assert_cmpint(ret->integer, =3D=3D, 0); + qapi_free_UserDefZero(ret); + + /* But you cannot set one. */ + val.integer =3D 42; + OBJECT_PROPERTY_SET_PTR(OBJECT(dobj), &val, "qv", + UserDefZero, &local_err); + g_assert(local_err); + error_free(local_err); + local_err =3D NULL; + + /* Test that the property has not been modified at all */ + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "qv", + UserDefZero, &local_err); + g_assert(!local_err); + + g_assert_cmpint(ret->integer, =3D=3D, 0); + qapi_free_UserDefZero(ret); +} + +static void test_dummy_get_set_ptr_error(void) +{ + DummyObject *dobj =3D DUMMY_OBJECT(object_new(TYPE_DUMMY)); + Error *local_err =3D NULL; + const char *s =3D "my other dummy string"; + UserDefOne *ret; + UserDefOne val; + + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "blah", + UserDefOne, &local_err); + g_assert(local_err); + g_assert(!ret); + error_free(local_err); + local_err =3D NULL; + + val.integer =3D 42; + val.string =3D g_strdup(s); + val.has_enum1 =3D true; + val.enum1 =3D 100; + OBJECT_PROPERTY_SET_PTR(OBJECT(dobj), &val, "qv", + UserDefOne, &local_err); + g_assert(local_err); + error_free(local_err); + local_err =3D NULL; + + ret =3D OBJECT_PROPERTY_GET_PTR(OBJECT(dobj), "qv", + UserDefOne, &local_err); + g_assert(!local_err); + + /* Test that the property has not been modified at all */ + g_assert_cmpint(ret->integer, =3D=3D, 0); + g_assert_cmpstr(ret->string, =3D=3D, "dummy string"); + g_assert(!ret->has_enum1); + qapi_free_UserDefOne(ret); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -530,5 +707,9 @@ int main(int argc, char **argv) g_test_add_func("/qom/proplist/iterator", test_dummy_iterator); g_test_add_func("/qom/proplist/delchild", test_dummy_delchild); =20 + g_test_add_func("/qom/proplist/get-set-ptr/struct", test_dummy_get_set= _ptr_struct); + g_test_add_func("/qom/proplist/get-set-ptr/error", test_dummy_get_set_= ptr_error); + g_test_add_func("/qom/proplist/get-set-ptr/covariant", test_dummy_get_= set_ptr_covariant); + g_test_add_func("/qom/proplist/get-set-ptr/contravariant", test_dummy_= get_set_ptr_contravariant); return g_test_run(); } diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qa= pi-schema-test.json index f4d8cc4..4e3f6ff 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -91,6 +91,14 @@ '*enum1': 'EnumOne' } } # intentional forward reference =20 ## +# @UserDefOneMore: +# for testing nested structs +## +{ 'struct': 'UserDefOneMore', + 'base': 'UserDefOne', + 'data': { 'boolean': 'bool' } } + +## # @EnumOne: ## { 'enum': 'EnumOne', --=20 2.9.3