It is reasonably common to want to create an object, set a number of properties, register it in the hierarchy and then mark it as complete (if a user creatable type). This requires quite alot of error prone, verbose, boilerplate code to achieve.
The object_new_propv / object_new_proplist constructors will simplify this task by performing all required steps in one go, accepting the property names/values as variadic args. Usage would be: Error *err = NULL; Object *obj; obj = object_new_propv(TYPE_MEMORY_BACKEND_FILE, "hostmem0", &err, "share", "yes", "mem-path", "/dev/shm/somefile", "prealloc", "yes", "size": "1048576", NULL); Note all property values are passed in string form and will be parsed into their required data types. Signed-off-by: Daniel P. Berrange <berra...@redhat.com> --- include/qom/object.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/Makefile | 2 +- 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/include/qom/object.h b/include/qom/object.h index d2d7748..223b577 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -607,6 +607,64 @@ Object *object_new(const char *typename); Object *object_new_with_type(Type type); /** + * object_new_propv: + * @typename: The name of the type of the object to instantiate. + * @id: The unique ID of the object + * @errp: pointer to error object + * @...: list of property names and values + * + * This function with initialize a new object using heap allocated memory. + * The returned object has a reference count of 1, and will be freed when + * the last reference is dropped. + * + * The @id parameter will be used to register the object in the /objects + * hierarchy. + * + * The variadic parameters are a list of pairs of (propname, propvalue) + * strings. The propname of NULL indicates the end of the property + * list. If the object implements the user creatable interface, the + * object will be marked complete once all the properties have been + * processed. + * + * Error *err = NULL; + * Object *obj; + * + * obj = object_new_propv(TYPE_MEMORY_BACKEND_FILE, + * "hostmem0", + * &err, + * "share", "yes", + * "mem-path", "/dev/shm/somefile", + * "prealloc", "yes", + * "size": "1048576", + * NULL); + * + * if (!obj) { + * g_printerr("Cannot create memory backend: %s\n", + * error_get_pretty(err)); + * } + * + * Returns: The newly allocated, instantiated & initialized object. + */ +Object *object_new_propv(const char *typename, + const char *id, + Error **errp, + ...); + +/** + * object_new_proplist: + * @typename: The name of the type of the object to instantiate. + * @id: The unique ID of the object + * @errp: pointer to error object + * @vargs: list of property names and values + * + * See object_new_propv for documentation. + */ +Object *object_new_proplist(const char *typename, + const char *id, + Error **errp, + va_list vargs); + +/** * object_initialize_with_type: * @data: A pointer to the memory to be used for the object. * @size: The maximum size available at @data for the object. diff --git a/qom/object.c b/qom/object.c index b8dff43..29c7aea 100644 --- a/qom/object.c +++ b/qom/object.c @@ -11,6 +11,7 @@ */ #include "qom/object.h" +#include "qom/object_interfaces.h" #include "qemu-common.h" #include "qapi/visitor.h" #include "qapi-visit.h" @@ -439,6 +440,69 @@ Object *object_new(const char *typename) return object_new_with_type(ti); } +Object *object_new_propv(const char *typename, + const char *id, + Error **errp, + ...) +{ + va_list vargs; + Object *obj; + + va_start(vargs, errp); + obj = object_new_proplist(typename, id, errp, vargs); + va_end(vargs); + + return obj; +} + +Object *object_new_proplist(const char *typename, + const char *id, + Error **errp, + va_list vargs) +{ + Object *obj; + const char *propname; + + obj = object_new(typename); + + if (object_class_is_abstract(object_get_class(obj))) { + error_setg(errp, "object type '%s' is abstract", typename); + goto error; + } + + propname = va_arg(vargs, char *); + while (propname != NULL) { + const char *value = va_arg(vargs, char *); + + object_property_parse(obj, value, propname, errp); + if (*errp) { + goto error; + } + propname = va_arg(vargs, char *); + } + + object_property_add_child(container_get(object_get_root(), "/objects"), + id, obj, errp); + if (*errp) { + goto error; + } + + if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { + user_creatable_complete(obj, errp); + if (*errp) { + object_property_del(container_get(object_get_root(), "/objects"), + id, &error_abort); + goto error; + } + } + + return obj; + + error: + object_unref(obj); + return NULL; +} + Object *object_dynamic_cast(Object *obj, const char *typename) { if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { diff --git a/tests/Makefile b/tests/Makefile index 55aa745..e212ba9 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -240,7 +240,7 @@ test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ $(test-obj-y): QEMU_INCLUDES += -Itests QEMU_CFLAGS += -I$(SRC_PATH)/tests -qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o +qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o qom/object_interfaces.o tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a -- 2.1.0