diff mbox

[v1,RFC,04/34] qom: add object_new_propv / object_new_proplist constructors

Message ID 1429280557-8887-5-git-send-email-berrange@redhat.com
State New
Headers show

Commit Message

Daniel P. Berrangé April 17, 2015, 2:22 p.m. UTC
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 <berrange@redhat.com>
---
 include/qom/object.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++
 qom/object.c         | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/Makefile       |  2 +-
 3 files changed, 123 insertions(+), 1 deletion(-)

Comments

Paolo Bonzini April 17, 2015, 2:55 p.m. UTC | #1
On 17/04/2015 16:22, Daniel P. Berrange wrote:
> +
> +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);

I would pass the parent as an additional argument to
object_new_proplist().  Otherwise looks good.

Paolo
Daniel P. Berrangé April 17, 2015, 3:16 p.m. UTC | #2
On Fri, Apr 17, 2015 at 04:55:26PM +0200, Paolo Bonzini wrote:
> 
> 
> On 17/04/2015 16:22, Daniel P. Berrange wrote:
> > +
> > +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);
> 
> I would pass the parent as an additional argument to
> object_new_proplist().  Otherwise looks good.

Yep, that does rather make sense for flexibility.

Regards,
Daniel
Eric Blake April 17, 2015, 4:11 p.m. UTC | #3
On 04/17/2015 08:22 AM, Daniel P. Berrange wrote:
> 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.

s/alot/a lot/

> 
> 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",

s/:/,/

>                           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 <berrange@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

> + *
> + *   obj = object_new_propv(TYPE_MEMORY_BACKEND_FILE,
> + *                          "hostmem0",
> + *                          &err,
> + *                          "share", "yes",
> + *                          "mem-path", "/dev/shm/somefile",
> + *                          "prealloc", "yes",
> + *                          "size": "1048576",

and again

> + *                          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,
> +                         ...);

You probably want to use the gcc __attribute__((__sentinel__)), so that
the compiler can ensure that the caller NULL-terminates their list.


> +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);

Is it worth a sanity check of assert(value) prior to calling
object_property_parse(), as I have the suspicion that it doesn't handle
NULL very well?
diff mbox

Patch

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