Patchwork [04/21] qom: add Plug class

login
register
mail settings
Submitter Anthony Liguori
Date July 25, 2011, 1:44 a.m.
Message ID <1311558293-5855-5-git-send-email-aliguori@us.ibm.com>
Download mbox | patch
Permalink /patch/106579/
State New
Headers show

Comments

Anthony Liguori - July 25, 2011, 1:44 a.m.
The Plug class is the base class for all objects.  Plugs implement properties
using the existing Visitor framework.  This allows for very complex properties
to be implemented.

Plugs also implement life cycle management by containing a realized state.  An
object isn't fully constructed until its realized.  By setting realized to
false, an object can also be reset.

Plug properties can be set to be read-only or read-write.  A read-write property
can be locked.  While a read-write property is locked, it cannot be written to.

The expectation is that some properties will be locked at realize time.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 include/qemu/plug-proptypes.h |   14 +++
 include/qemu/plug.h           |   73 +++++++++++++
 qerror.c                      |    4 +
 qerror.h                      |    3 +
 qom/Makefile                  |    2 +-
 qom/plug-proptypes.c          |   52 ++++++++++
 qom/plug.c                    |  225 +++++++++++++++++++++++++++++++++++++++++
 qom/string-visitor.c          |   41 ++++++++
 qom/string-visitor.h          |   21 ++++
 9 files changed, 434 insertions(+), 1 deletions(-)
 create mode 100644 include/qemu/plug-proptypes.h
 create mode 100644 include/qemu/plug.h
 create mode 100644 qom/plug-proptypes.c
 create mode 100644 qom/plug.c
 create mode 100644 qom/string-visitor.c
 create mode 100644 qom/string-visitor.h

Patch

diff --git a/include/qemu/plug-proptypes.h b/include/qemu/plug-proptypes.h
new file mode 100644
index 0000000..2c7be0e
--- /dev/null
+++ b/include/qemu/plug-proptypes.h
@@ -0,0 +1,14 @@ 
+#ifndef PLUG_PROPTYPES_H
+#define PLUG_PROPTYPES_H
+
+#include "plug.h"
+
+typedef bool (PlugPropertyGetterBool)(Plug *plug);
+typedef void (PlugPropertySetterBool)(Plug *plug, bool value);
+
+void plug_add_property_bool(Plug *plug, const char *name,
+                            PlugPropertyGetterBool *getter,
+                            PlugPropertySetterBool *setter,
+                            int flags);
+
+#endif
diff --git a/include/qemu/plug.h b/include/qemu/plug.h
new file mode 100644
index 0000000..f6948a0
--- /dev/null
+++ b/include/qemu/plug.h
@@ -0,0 +1,73 @@ 
+#ifndef PLUG_H
+#define PLUG_H
+
+#include "qemu/type.h"
+#include "error.h"
+#include "qapi/qapi-visit-core.h"
+
+typedef struct Plug Plug;
+typedef struct PlugProperty PlugProperty;
+
+typedef enum PlugPropertyFlags
+{
+    PROP_F_NONE = 0,
+    PROP_F_READ = 1,
+    PROP_F_WRITE = 2,
+    PROP_F_READWRITE = (PROP_F_READ | PROP_F_WRITE),
+    PROP_F_LOCKED = 4,
+} PlugPropertyFlags;
+
+struct Plug
+{
+    TypeInstance parent;
+
+    /* private */
+    bool realized;
+    PlugProperty *first_prop;
+};
+
+typedef struct PlugClass {
+    TypeClass parent_class;
+
+    /* protected */
+    void (*realize)(Plug *plug);
+    void (*unrealize)(Plug *plug);
+} PlugClass;
+
+#define TYPE_PLUG "plug"
+#define PLUG(obj) TYPE_CHECK(Plug, obj, TYPE_PLUG)
+#define PLUG_GET_CLASS(obj) TYPE_GET_CLASS(PlugClass, obj, TYPE_PLUG)
+#define PLUG_CLASS(obj) TYPE_CLASS_CHECK(PlugClass, obj, TYPE_PLUG)
+
+typedef void (PlugPropertyAccessor)(Plug *plug, const char *name, Visitor *v, void *opaque, Error **errp);
+typedef void (PlugPropertyFinalize)(Plug *plug, const char *name, void *opaque);
+typedef void (PropertyEnumerator)(Plug *plug, const char *name, const char *typename, int flags, void *opaque);
+
+void plug_set_property(Plug *plug, const char *name, Visitor *v, Error **errp);
+
+void plug_get_property(Plug *plug, const char *name, Visitor *v, Error **errp);
+
+void plug_add_property_full(Plug *plug, const char *name,
+                            PlugPropertyAccessor *getter,
+                            PlugPropertyAccessor *setter,
+                            PlugPropertyFinalize *fini,
+                            void *opaque,
+                            const char *typename, int flags);
+
+void plug_foreach_property(Plug *plug, PropertyEnumerator *enumfn, void *opaque);
+
+void plug_lock_property(Plug *plug, const char *name);
+void plug_unlock_property(Plug *plug, const char *name);
+
+void plug_lock_all_properties(Plug *plug);
+void plug_unlock_all_properties(Plug *plug);
+
+void plug_set_realized(Plug *plug, bool realized);
+bool plug_get_realized(Plug *plug);
+
+void plug_realize_all(Plug *plug);
+void plug_unrealize_all(Plug *plug);
+
+#include "qemu/plug-proptypes.h"
+
+#endif
diff --git a/qerror.c b/qerror.c
index 69c1bc9..dbe119c 100644
--- a/qerror.c
+++ b/qerror.c
@@ -170,6 +170,10 @@  static const QErrorStringTable qerror_table[] = {
         .desc      = "Property '%(device).%(property)' not found",
     },
     {
+        .error_fmt = QERR_PROPERTY_READ_ONLY,
+        .desc      = "Property '%(device).%(property)' is read only",
+    },
+    {
         .error_fmt = QERR_PROPERTY_VALUE_BAD,
         .desc      = "Property '%(device).%(property)' doesn't take value '%(value)'",
     },
diff --git a/qerror.h b/qerror.h
index 8058456..eaabe6c 100644
--- a/qerror.h
+++ b/qerror.h
@@ -145,6 +145,9 @@  QError *qobject_to_qerror(const QObject *obj);
 #define QERR_PROPERTY_NOT_FOUND \
     "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
 
+#define QERR_PROPERTY_READ_ONLY \
+    "{ 'class': 'PropertyReadOnly', 'data': { 'device': %s, 'property': %s } }"
+
 #define QERR_PROPERTY_VALUE_BAD \
     "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
 
diff --git a/qom/Makefile b/qom/Makefile
index 838054f..8a438d5 100644
--- a/qom/Makefile
+++ b/qom/Makefile
@@ -1 +1 @@ 
-qom-obj-$(CONFIG_QOM) += type.o
+qom-obj-$(CONFIG_QOM) += type.o string-visitor.o plug.o plug-proptypes.o
diff --git a/qom/plug-proptypes.c b/qom/plug-proptypes.c
new file mode 100644
index 0000000..e9152a7
--- /dev/null
+++ b/qom/plug-proptypes.c
@@ -0,0 +1,52 @@ 
+/** FIXME: move to generated code **/
+
+#include "qemu/plug-proptypes.h"
+
+typedef struct FunctionPointer
+{
+    void (*getter)(void);
+    void (*setter)(void);
+} FunctionPointer;
+
+static void plug_get_property__bool(Plug *plug, const char *name, Visitor *v, void *opaque, Error **errp)
+{
+    FunctionPointer *fp = opaque;
+    PlugPropertyGetterBool *getter = (PlugPropertyGetterBool *)fp->getter;
+    bool value;
+
+    value = getter(plug);
+    visit_type_bool(v, &value, name, errp);
+}
+
+static void plug_set_property__bool(Plug *plug, const char *name, Visitor *v, void *opaque, Error **errp)
+{
+    FunctionPointer *fp = opaque;
+    PlugPropertySetterBool *setter = (PlugPropertySetterBool *)fp->setter;
+    bool value = false;
+    Error *local_err = NULL;
+
+    visit_type_bool(v, &value, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    setter(plug, value);
+}
+
+void plug_add_property_bool(Plug *plug, const char *name,
+                            PlugPropertyGetterBool *getter,
+                            PlugPropertySetterBool *setter,
+                            int flags)
+{
+    FunctionPointer *fp = qemu_mallocz(sizeof(*fp));
+
+    fp->getter = (void (*)(void))getter;
+    fp->setter = (void (*)(void))setter;
+
+    plug_add_property_full(plug, name,
+                           plug_get_property__bool,
+                           plug_set_property__bool,
+                           plug_del_property__fp,
+                           fp, "bool", flags);
+}
diff --git a/qom/plug.c b/qom/plug.c
new file mode 100644
index 0000000..4a5f2fb
--- /dev/null
+++ b/qom/plug.c
@@ -0,0 +1,225 @@ 
+#include "qemu/plug.h"
+#include "qerror.h"
+#include "qom/string-visitor.h"
+
+#define MAX_NAME (128 + 1)
+#define MAX_TYPENAME (32 + 1)
+
+struct PlugProperty
+{
+    char name[MAX_NAME];
+    char typename[MAX_TYPENAME];
+    
+    PlugPropertyAccessor *getter;
+    PlugPropertyAccessor *setter;
+    PlugPropertyFinalize *finalize;
+    void *opaque;
+
+    int flags;
+
+    PlugProperty *next;
+};
+
+void plug_add_property_full(Plug *plug, const char *name,
+                            PlugPropertyAccessor *getter,
+                            PlugPropertyAccessor *setter,
+                            PlugPropertyFinalize *fini,
+                            void *opaque, const char *typename, int flags)
+{
+    PlugProperty *prop = qemu_mallocz(sizeof(*prop));
+
+    snprintf(prop->name, sizeof(prop->name), "%s", name);
+    snprintf(prop->typename, sizeof(prop->typename), "%s", typename);
+
+    prop->getter = getter;
+    prop->setter = setter;
+    prop->finalize = fini;
+    prop->opaque = opaque;
+
+    prop->flags = flags;
+
+    prop->next = plug->first_prop;
+    plug->first_prop = prop;
+}
+
+static PlugProperty *plug_find_property(Plug *plug, const char *name)
+{
+    PlugProperty *prop;
+
+    for (prop = plug->first_prop; prop; prop = prop->next) {
+        if (strcmp(prop->name, name) == 0) {
+            return prop;
+        }
+    }
+
+    return NULL;
+}
+
+void plug_set_property(Plug *plug, const char *name, Visitor *v, Error **errp)
+{
+    PlugProperty *prop = plug_find_property(plug, name);
+
+    if (!prop) {
+        error_set(errp, QERR_PROPERTY_NOT_FOUND, type_get_id(TYPE_INSTANCE(plug)), name);
+        return;
+    }
+
+    if (!(prop->flags & PROP_F_WRITE) || (prop->flags & PROP_F_LOCKED)) {
+        error_set(errp, QERR_PROPERTY_READ_ONLY, type_get_id(TYPE_INSTANCE(plug)), name);
+        return;
+    }
+
+    prop->setter(plug, name, v, prop->opaque, errp);
+}
+
+void plug_get_property(Plug *plug, const char *name, Visitor *v, Error **errp)
+{
+    PlugProperty *prop = plug_find_property(plug, name);
+
+    if (!prop) {
+        error_set(errp, QERR_PROPERTY_NOT_FOUND, type_get_id(TYPE_INSTANCE(plug)), name);
+        printf("property not found\n");
+        return;
+    }
+
+    if (!(prop->flags & PROP_F_READ)) {
+        error_set(errp, QERR_PROPERTY_READ_ONLY, type_get_id(TYPE_INSTANCE(plug)), name);
+        printf("property read only\n");
+        return;
+    }
+
+    prop->getter(plug, name, v, prop->opaque, errp);
+}
+
+void plug_lock_property(Plug *plug, const char *name)
+{
+    PlugProperty *prop = plug_find_property(plug, name);
+
+    assert(prop != NULL);
+
+    prop->flags |= PROP_F_LOCKED;
+}
+
+void plug_unlock_property(Plug *plug, const char *name)
+{
+    PlugProperty *prop = plug_find_property(plug, name);
+
+    assert(prop != NULL);
+
+    prop->flags &= ~PROP_F_LOCKED;
+}
+
+void plug_lock_all_properties(Plug *plug)
+{
+    PlugProperty *prop;
+
+    for (prop = plug->first_prop; prop; prop = prop->next) {
+        prop->flags |= PROP_F_LOCKED;
+    }
+}
+
+void plug_unlock_all_properties(Plug *plug)
+{
+    PlugProperty *prop;
+
+    for (prop = plug->first_prop; prop; prop = prop->next) {
+        prop->flags &= ~PROP_F_LOCKED;
+    }
+}
+
+void plug_foreach_property(Plug *plug, PropertyEnumerator *enumfn, void *opaque)
+{
+    PlugProperty *prop;
+
+    for (prop = plug->first_prop; prop; prop = prop->next) {
+        enumfn(plug, prop->name, prop->typename, prop->flags, opaque);
+    }
+}
+
+void plug_set_realized(Plug *plug, bool realized)
+{
+    PlugClass *class = PLUG_GET_CLASS(plug);
+    bool old_value = plug->realized;
+
+    plug->realized = realized;
+
+    if (plug->realized && !old_value) {
+        if (class->realize) {
+            class->realize(plug);
+        }
+    } else if (!plug->realized && old_value) {
+        if (class->unrealize) {
+            class->unrealize(plug);
+        }
+    }
+}
+
+bool plug_get_realized(Plug *plug)
+{
+    return plug->realized;
+}
+
+void plug_realize_all(Plug *plug)
+{
+    /* This doesn't loop infinitely because the callbacks are only called when
+     * the state changes. */
+    plug_set_realized(plug, true);
+    plug_lock_all_properties(plug);
+}
+
+void plug_unrealize_all(Plug *plug)
+{
+    /* This doesn't loop infinitely because the callbacks are only called when
+     * the state changes. */
+    plug_set_realized(plug, false);
+    plug_unlock_all_properties(plug);
+}
+
+static void plug_class_initfn(TypeClass *base_class)
+{
+    PlugClass *class = PLUG_CLASS(base_class);
+
+    class->realize = plug_realize_all;
+    class->unrealize = plug_unrealize_all;
+}
+
+static void plug_initfn(TypeInstance *inst)
+{
+    Plug *obj = PLUG(inst);
+
+    plug_add_property_bool(obj, "realized",
+                           plug_get_realized,
+                           plug_set_realized,
+                           PROP_F_READWRITE);
+}
+
+static void plug_finifn(TypeInstance *inst)
+{
+    Plug *plug = PLUG(inst);
+
+    while (plug->first_prop) {
+        PlugProperty *p = plug->first_prop;
+
+        plug->first_prop = plug->first_prop->next;
+        if (p->finalize) {
+            p->finalize(plug, p->name, p->opaque);
+        }
+        qemu_free(p);
+    }
+}
+
+static const TypeInfo plug_type_info = {
+    .name = TYPE_PLUG,
+    .instance_size = sizeof(Plug),
+    .class_size = sizeof(PlugClass),
+    .instance_init = plug_initfn,
+    .instance_finalize = plug_finifn,
+    .class_init = plug_class_initfn,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&plug_type_info);
+}
+
+device_init(register_devices);
diff --git a/qom/string-visitor.c b/qom/string-visitor.c
new file mode 100644
index 0000000..55297e2
--- /dev/null
+++ b/qom/string-visitor.c
@@ -0,0 +1,41 @@ 
+#include "string-visitor.h"
+
+static void string_input_visitor_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    StringInputVisitor *sv = container_of(v, StringInputVisitor, parent);
+    *obj = atoi(sv->value);
+}
+
+static void string_input_visitor_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    StringInputVisitor *sv = container_of(v, StringInputVisitor, parent);
+    *obj = qemu_strdup(sv->value);
+}
+
+void string_input_visitor_init(StringInputVisitor *sv, const char *value)
+{
+    memset(sv, 0, sizeof(*sv));
+    sv->parent.type_int = string_input_visitor_int;
+    sv->parent.type_str = string_input_visitor_str;
+    sv->value = value;
+}
+
+static void string_output_visitor_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
+{
+    StringOutputVisitor *sv = container_of(v, StringOutputVisitor, parent);
+    snprintf(sv->value, sizeof(sv->value), "%" PRId64, *obj);
+}
+
+static void string_output_visitor_str(Visitor *v, char **obj, const char *name, Error **errp)
+{
+    StringOutputVisitor *sv = container_of(v, StringOutputVisitor, parent);
+
+    snprintf(sv->value, sizeof(sv->value), "%s", *obj);
+}
+
+void string_output_visitor_init(StringOutputVisitor *sv)
+{
+    memset(sv, 0, sizeof(*sv));
+    sv->parent.type_int = string_output_visitor_int;
+    sv->parent.type_str = string_output_visitor_str;
+}
diff --git a/qom/string-visitor.h b/qom/string-visitor.h
new file mode 100644
index 0000000..ddee3e5
--- /dev/null
+++ b/qom/string-visitor.h
@@ -0,0 +1,21 @@ 
+#ifndef STRING_VISITOR_H
+#define STRING_VISITOR_H
+
+#include "qapi/qapi-visit-core.h"
+
+typedef struct StringInputVisitor
+{
+    Visitor parent;
+    const char *value;
+} StringInputVisitor;
+
+typedef struct StringOutputVisitor
+{
+    Visitor parent;
+    char value[256];
+} StringOutputVisitor;
+
+void string_input_visitor_init(StringInputVisitor *sv, const char *value);
+void string_output_visitor_init(StringOutputVisitor *sv);
+
+#endif