aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-06-05 13:11:51 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2014-07-01 10:17:48 +0200
commit64607d088132abdb25bf30d93e97d0c8df7b364c (patch)
treead3b8d616ee3b858d0e81ead81c2a9daefb85018
parentef7c7ff6d4ca1955278af1bc5025f47044183250 (diff)
qom: add a generic mechanism to resolve paths
It may be desirable to have custom link<> properties that do more than just store an object. Even the addition of a "check" function is not enough if setting the link has side effects or if a non-standard reference counting is preferrable. Avoid the assumption that the opaque field of a link<> is a LinkProperty struct, by adding a generic "resolve" callback to ObjectProperty. This fixes aliases of link properties. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--include/qom/object.h34
-rw-r--r--qom/object.c82
2 files changed, 82 insertions, 34 deletions
diff --git a/include/qom/object.h b/include/qom/object.h
index 44c513f985..8a05a81a99 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -304,6 +304,25 @@ typedef void (ObjectPropertyAccessor)(Object *obj,
Error **errp);
/**
+ * ObjectPropertyResolve:
+ * @obj: the object that owns the property
+ * @opaque: the opaque registered with the property
+ * @part: the name of the property
+ *
+ * Resolves the #Object corresponding to property @part.
+ *
+ * The returned object can also be used as a starting point
+ * to resolve a relative path starting with "@part".
+ *
+ * Returns: If @path is the path that led to @obj, the function
+ * returns the #Object corresponding to "@path/@part".
+ * If "@path/@part" is not a valid object path, it returns #NULL.
+ */
+typedef Object *(ObjectPropertyResolve)(Object *obj,
+ void *opaque,
+ const char *part);
+
+/**
* ObjectPropertyRelease:
* @obj: the object that owns the property
* @name: the name of the property
@@ -321,6 +340,7 @@ typedef struct ObjectProperty
gchar *type;
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
+ ObjectPropertyResolve *resolve;
ObjectPropertyRelease *release;
void *opaque;
@@ -787,12 +807,16 @@ void object_unref(Object *obj);
* destruction. This may be NULL.
* @opaque: an opaque pointer to pass to the callbacks for the property
* @errp: returns an error if this function fails
+ *
+ * Returns: The #ObjectProperty; this can be used to set the @resolve
+ * callback for child and link properties.
*/
-void object_property_add(Object *obj, const char *name, const char *type,
- ObjectPropertyAccessor *get,
- ObjectPropertyAccessor *set,
- ObjectPropertyRelease *release,
- void *opaque, Error **errp);
+ObjectProperty *object_property_add(Object *obj, const char *name,
+ const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp);
void object_property_del(Object *obj, const char *name, Error **errp);
diff --git a/qom/object.c b/qom/object.c
index a760514787..7a892ef4a6 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -356,11 +356,6 @@ static inline bool object_property_is_child(ObjectProperty *prop)
return strstart(prop->type, "child<", NULL);
}
-static inline bool object_property_is_link(ObjectProperty *prop)
-{
- return strstart(prop->type, "link<", NULL);
-}
-
static void object_property_del_all(Object *obj)
{
while (!QTAILQ_EMPTY(&obj->properties)) {
@@ -728,11 +723,12 @@ void object_unref(Object *obj)
}
}
-void object_property_add(Object *obj, const char *name, const char *type,
- ObjectPropertyAccessor *get,
- ObjectPropertyAccessor *set,
- ObjectPropertyRelease *release,
- void *opaque, Error **errp)
+ObjectProperty *
+object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp)
{
ObjectProperty *prop;
@@ -741,7 +737,7 @@ void object_property_add(Object *obj, const char *name, const char *type,
error_setg(errp, "attempt to add duplicate property '%s'"
" to object (type '%s')", name,
object_get_typename(obj));
- return;
+ return NULL;
}
}
@@ -756,6 +752,7 @@ void object_property_add(Object *obj, const char *name, const char *type,
prop->opaque = opaque;
QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
+ return prop;
}
ObjectProperty *object_property_find(Object *obj, const char *name,
@@ -1028,6 +1025,11 @@ static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
g_free(path);
}
+static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part)
+{
+ return opaque;
+}
+
static void object_finalize_child_property(Object *obj, const char *name,
void *opaque)
{
@@ -1041,15 +1043,18 @@ void object_property_add_child(Object *obj, const char *name,
{
Error *local_err = NULL;
gchar *type;
+ ObjectProperty *op;
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
- object_property_add(obj, name, type, object_get_child_property, NULL,
- object_finalize_child_property, child, &local_err);
+ op = object_property_add(obj, name, type, object_get_child_property, NULL,
+ object_finalize_child_property, child, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
+
+ op->resolve = object_resolve_child_property;
object_ref(child);
g_assert(child->parent == NULL);
child->parent = obj;
@@ -1163,6 +1168,13 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
}
}
+static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
+{
+ LinkProperty *lprop = opaque;
+
+ return *lprop->child;
+}
+
static void object_release_link_property(Object *obj, const char *name,
void *opaque)
{
@@ -1184,6 +1196,7 @@ void object_property_add_link(Object *obj, const char *name,
Error *local_err = NULL;
LinkProperty *prop = g_malloc(sizeof(*prop));
gchar *full_type;
+ ObjectProperty *op;
prop->child = child;
prop->check = check;
@@ -1191,17 +1204,21 @@ void object_property_add_link(Object *obj, const char *name,
full_type = g_strdup_printf("link<%s>", type);
- object_property_add(obj, name, full_type,
- object_get_link_property,
- check ? object_set_link_property : NULL,
- object_release_link_property,
- prop,
- &local_err);
+ op = object_property_add(obj, name, full_type,
+ object_get_link_property,
+ check ? object_set_link_property : NULL,
+ object_release_link_property,
+ prop,
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
g_free(prop);
+ goto out;
}
+ op->resolve = object_resolve_link_property;
+
+out:
g_free(full_type);
}
@@ -1260,11 +1277,8 @@ Object *object_resolve_path_component(Object *parent, const gchar *part)
return NULL;
}
- if (object_property_is_link(prop)) {
- LinkProperty *lprop = prop->opaque;
- return *lprop->child;
- } else if (object_property_is_child(prop)) {
- return prop->opaque;
+ if (prop->resolve) {
+ return prop->resolve(parent, prop->opaque, part);
} else {
return NULL;
}
@@ -1571,6 +1585,14 @@ static void property_set_alias(Object *obj, struct Visitor *v, void *opaque,
object_property_set(prop->target_obj, v, prop->target_name, errp);
}
+static Object *property_resolve_alias(Object *obj, void *opaque,
+ const gchar *part)
+{
+ AliasProperty *prop = opaque;
+
+ return object_resolve_path_component(prop->target_obj, prop->target_name);
+}
+
static void property_release_alias(Object *obj, const char *name, void *opaque)
{
AliasProperty *prop = opaque;
@@ -1583,6 +1605,7 @@ void object_property_add_alias(Object *obj, const char *name,
Error **errp)
{
AliasProperty *prop;
+ ObjectProperty *op;
ObjectProperty *target_prop;
target_prop = object_property_find(target_obj, target_name, errp);
@@ -1594,11 +1617,12 @@ void object_property_add_alias(Object *obj, const char *name,
prop->target_obj = target_obj;
prop->target_name = target_name;
- object_property_add(obj, name, target_prop->type,
- property_get_alias,
- property_set_alias,
- property_release_alias,
- prop, errp);
+ op = object_property_add(obj, name, target_prop->type,
+ property_get_alias,
+ property_set_alias,
+ property_release_alias,
+ prop, errp);
+ op->resolve = property_resolve_alias;
}
static void object_instance_init(Object *obj)