aboutsummaryrefslogtreecommitdiff
path: root/qom
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-01-30 08:55:55 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2012-02-03 10:41:08 -0600
commit57c9fafe0f759c9f1efa5451662b3627f9bb95e0 (patch)
tree6a097cdea9a82e94cbd696a45e3e5faac917881b /qom
parent0beb4942071e385c16deba03848898865842edc7 (diff)
qom: move properties from qdev to object
This is mostly code movement although not entirely. This makes properties part of the Object base class which means that we can now start using Object in a meaningful way outside of qdev. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'qom')
-rw-r--r--qom/object.c468
1 files changed, 468 insertions, 0 deletions
diff --git a/qom/object.c b/qom/object.c
index 3dabb1abb0..2506d78e68 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -12,6 +12,9 @@
#include "qemu/object.h"
#include "qemu-common.h"
+#include "qapi/qapi-visit-core.h"
+#include "hw/qdev.h"
+// FIXME remove above
#define MAX_INTERFACES 32
@@ -258,6 +261,7 @@ void object_initialize_with_type(void *data, TypeImpl *type)
memset(obj, 0, type->instance_size);
obj->class = type->class;
+ QTAILQ_INIT(&obj->properties);
object_init_with_type(obj, type);
}
@@ -268,6 +272,45 @@ void object_initialize(void *data, const char *typename)
object_initialize_with_type(data, type);
}
+static void object_property_del_all(Object *obj)
+{
+ while (!QTAILQ_EMPTY(&obj->properties)) {
+ ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
+
+ QTAILQ_REMOVE(&obj->properties, prop, node);
+
+ if (prop->release) {
+ prop->release(obj, prop->name, prop->opaque);
+ }
+
+ g_free(prop->name);
+ g_free(prop->type);
+ g_free(prop);
+ }
+}
+
+static void object_property_del_child(Object *obj, Object *child, Error **errp)
+{
+ ObjectProperty *prop;
+
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ if (prop->opaque == child) {
+ object_property_del(obj, prop->name, errp);
+ }
+ }
+}
+
+void object_unparent(Object *obj)
+{
+ if (obj->parent) {
+ object_property_del_child(obj->parent, obj, NULL);
+ }
+}
+
static void object_deinit(Object *obj, TypeImpl *type)
{
if (type->instance_finalize) {
@@ -283,6 +326,8 @@ static void object_deinit(Object *obj, TypeImpl *type)
if (type_has_parent(type)) {
object_deinit(obj, type_get_parent(type));
}
+
+ object_unparent(obj);
}
void object_finalize(void *data)
@@ -291,6 +336,7 @@ void object_finalize(void *data)
TypeImpl *ti = obj->class->type;
object_deinit(obj, ti);
+ object_property_del_all(obj);
}
Object *object_new_with_type(Type type)
@@ -502,3 +548,425 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
}
+
+void object_ref(Object *obj)
+{
+ obj->ref++;
+}
+
+void object_unref(Object *obj)
+{
+ g_assert(obj->ref > 0);
+ obj->ref--;
+
+ /* parent always holds a reference to its children */
+ if (obj->ref == 0) {
+ object_finalize(obj);
+ }
+}
+
+void object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp)
+{
+ ObjectProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->name = g_strdup(name);
+ prop->type = g_strdup(type);
+
+ prop->get = get;
+ prop->set = set;
+ prop->release = release;
+ prop->opaque = opaque;
+
+ QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
+}
+
+static ObjectProperty *object_property_find(Object *obj, const char *name)
+{
+ ObjectProperty *prop;
+
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ if (strcmp(prop->name, name) == 0) {
+ return prop;
+ }
+ }
+
+ return NULL;
+}
+
+void object_property_del(Object *obj, const char *name, Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ QTAILQ_REMOVE(&obj->properties, prop, node);
+
+ prop->release(obj, prop->name, prop->opaque);
+
+ g_free(prop->name);
+ g_free(prop->type);
+ g_free(prop);
+}
+
+void object_property_get(Object *obj, Visitor *v, const char *name,
+ Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return;
+ }
+
+ if (!prop->get) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ prop->get(obj, v, prop->opaque, name, errp);
+ }
+}
+
+void object_property_set(Object *obj, Visitor *v, const char *name,
+ Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return;
+ }
+
+ if (!prop->set) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ prop->set(obj, v, prop->opaque, name, errp);
+ }
+}
+
+const char *object_property_get_type(Object *obj, const char *name, Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return NULL;
+ }
+
+ return prop->type;
+}
+
+Object *object_get_root(void)
+{
+ static DeviceState *object_root;
+
+ if (!object_root) {
+ object_root = qdev_create(NULL, "container");
+ qdev_init_nofail(object_root);
+ }
+
+ return OBJECT(object_root);
+}
+
+static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object *child = opaque;
+ gchar *path;
+
+ path = object_get_canonical_path(child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+}
+
+void object_property_add_child(Object *obj, const char *name,
+ Object *child, Error **errp)
+{
+ gchar *type;
+
+ type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
+
+ object_property_add(obj, name, type, object_get_child_property,
+ NULL, NULL, child, errp);
+
+ object_ref(child);
+ g_assert(child->parent == NULL);
+ child->parent = obj;
+
+ g_free(type);
+}
+
+static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object **child = opaque;
+ gchar *path;
+
+ if (*child) {
+ path = object_get_canonical_path(*child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+ } else {
+ path = (gchar *)"";
+ visit_type_str(v, &path, name, errp);
+ }
+}
+
+static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object **child = opaque;
+ bool ambiguous = false;
+ const char *type;
+ char *path;
+
+ type = object_property_get_type(obj, name, NULL);
+
+ visit_type_str(v, &path, name, errp);
+
+ if (*child) {
+ object_unref(*child);
+ }
+
+ if (strcmp(path, "") != 0) {
+ Object *target;
+
+ target = object_resolve_path(path, &ambiguous);
+ if (target) {
+ gchar *target_type;
+
+ target_type = g_strdup_printf("link<%s>",
+ object_get_typename(OBJECT(target)));
+ if (strcmp(target_type, type) == 0) {
+ *child = target;
+ object_ref(target);
+ } else {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
+ }
+
+ g_free(target_type);
+ } else {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+ }
+ } else {
+ *child = NULL;
+ }
+
+ g_free(path);
+}
+
+void object_property_add_link(Object *obj, const char *name,
+ const char *type, Object **child,
+ Error **errp)
+{
+ gchar *full_type;
+
+ full_type = g_strdup_printf("link<%s>", type);
+
+ object_property_add(obj, name, full_type,
+ object_get_link_property,
+ object_set_link_property,
+ NULL, child, errp);
+
+ g_free(full_type);
+}
+
+gchar *object_get_canonical_path(Object *obj)
+{
+ Object *root = object_get_root();
+ char *newpath = NULL, *path = NULL;
+
+ while (obj != root) {
+ ObjectProperty *prop = NULL;
+
+ g_assert(obj->parent != NULL);
+
+ QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ if (prop->opaque == obj) {
+ if (path) {
+ newpath = g_strdup_printf("%s/%s", prop->name, path);
+ g_free(path);
+ path = newpath;
+ } else {
+ path = g_strdup(prop->name);
+ }
+ break;
+ }
+ }
+
+ g_assert(prop != NULL);
+
+ obj = obj->parent;
+ }
+
+ newpath = g_strdup_printf("/%s", path);
+ g_free(path);
+
+ return newpath;
+}
+
+static Object *object_resolve_abs_path(Object *parent,
+ gchar **parts,
+ int index)
+{
+ ObjectProperty *prop;
+ Object *child;
+
+ if (parts[index] == NULL) {
+ return parent;
+ }
+
+ if (strcmp(parts[index], "") == 0) {
+ return object_resolve_abs_path(parent, parts, index + 1);
+ }
+
+ prop = object_property_find(parent, parts[index]);
+ if (prop == NULL) {
+ return NULL;
+ }
+
+ child = NULL;
+ if (strstart(prop->type, "link<", NULL)) {
+ Object **pchild = prop->opaque;
+ if (*pchild) {
+ child = *pchild;
+ }
+ } else if (strstart(prop->type, "child<", NULL)) {
+ child = prop->opaque;
+ }
+
+ if (!child) {
+ return NULL;
+ }
+
+ return object_resolve_abs_path(child, parts, index + 1);
+}
+
+static Object *object_resolve_partial_path(Object *parent,
+ gchar **parts,
+ bool *ambiguous)
+{
+ Object *obj;
+ ObjectProperty *prop;
+
+ obj = object_resolve_abs_path(parent, parts, 0);
+
+ QTAILQ_FOREACH(prop, &parent->properties, node) {
+ Object *found;
+
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
+ if (found) {
+ if (obj) {
+ if (ambiguous) {
+ *ambiguous = true;
+ }
+ return NULL;
+ }
+ obj = found;
+ }
+
+ if (ambiguous && *ambiguous) {
+ return NULL;
+ }
+ }
+
+ return obj;
+}
+
+Object *object_resolve_path(const char *path, bool *ambiguous)
+{
+ bool partial_path = true;
+ Object *obj;
+ gchar **parts;
+
+ parts = g_strsplit(path, "/", 0);
+ if (parts == NULL || parts[0] == NULL) {
+ g_strfreev(parts);
+ return object_get_root();
+ }
+
+ if (strcmp(parts[0], "") == 0) {
+ partial_path = false;
+ }
+
+ if (partial_path) {
+ if (ambiguous) {
+ *ambiguous = false;
+ }
+ obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
+ } else {
+ obj = object_resolve_abs_path(object_get_root(), parts, 1);
+ }
+
+ g_strfreev(parts);
+
+ return obj;
+}
+
+typedef struct StringProperty
+{
+ char *(*get)(Object *, Error **);
+ void (*set)(Object *, const char *, Error **);
+} StringProperty;
+
+static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ StringProperty *prop = opaque;
+ char *value;
+
+ value = prop->get(obj, errp);
+ if (value) {
+ visit_type_str(v, &value, name, errp);
+ g_free(value);
+ }
+}
+
+static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ StringProperty *prop = opaque;
+ char *value;
+ Error *local_err = NULL;
+
+ visit_type_str(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ prop->set(obj, value, errp);
+ g_free(value);
+}
+
+static void object_property_release_str(Object *obj, const char *name,
+ void *opaque)
+{
+ StringProperty *prop = opaque;
+ g_free(prop);
+}
+
+void object_property_add_str(Object *obj, const char *name,
+ char *(*get)(Object *, Error **),
+ void (*set)(Object *, const char *, Error **),
+ Error **errp)
+{
+ StringProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->get = get;
+ prop->set = set;
+
+ object_property_add(obj, name, "string",
+ get ? object_property_get_str : NULL,
+ set ? object_property_set_str : NULL,
+ object_property_release_str,
+ prop, errp);
+}