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>
This commit is contained in:
Paolo Bonzini 2014-06-05 13:11:51 +02:00
parent ef7c7ff6d4
commit 64607d0881
2 changed files with 82 additions and 34 deletions

View File

@ -303,6 +303,25 @@ typedef void (ObjectPropertyAccessor)(Object *obj,
const char *name,
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
@ -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);

View File

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