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, const char *name,
Error **errp); 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: * ObjectPropertyRelease:
* @obj: the object that owns the property * @obj: the object that owns the property
@ -321,6 +340,7 @@ typedef struct ObjectProperty
gchar *type; gchar *type;
ObjectPropertyAccessor *get; ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set; ObjectPropertyAccessor *set;
ObjectPropertyResolve *resolve;
ObjectPropertyRelease *release; ObjectPropertyRelease *release;
void *opaque; void *opaque;
@ -787,12 +807,16 @@ void object_unref(Object *obj);
* destruction. This may be NULL. * destruction. This may be NULL.
* @opaque: an opaque pointer to pass to the callbacks for the property * @opaque: an opaque pointer to pass to the callbacks for the property
* @errp: returns an error if this function fails * @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, ObjectProperty *object_property_add(Object *obj, const char *name,
ObjectPropertyAccessor *get, const char *type,
ObjectPropertyAccessor *set, ObjectPropertyAccessor *get,
ObjectPropertyRelease *release, ObjectPropertyAccessor *set,
void *opaque, Error **errp); ObjectPropertyRelease *release,
void *opaque, Error **errp);
void object_property_del(Object *obj, const char *name, 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); 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) static void object_property_del_all(Object *obj)
{ {
while (!QTAILQ_EMPTY(&obj->properties)) { 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, ObjectProperty *
ObjectPropertyAccessor *get, object_property_add(Object *obj, const char *name, const char *type,
ObjectPropertyAccessor *set, ObjectPropertyAccessor *get,
ObjectPropertyRelease *release, ObjectPropertyAccessor *set,
void *opaque, Error **errp) ObjectPropertyRelease *release,
void *opaque, Error **errp)
{ {
ObjectProperty *prop; 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'" error_setg(errp, "attempt to add duplicate property '%s'"
" to object (type '%s')", name, " to object (type '%s')", name,
object_get_typename(obj)); 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; prop->opaque = opaque;
QTAILQ_INSERT_TAIL(&obj->properties, prop, node); QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
return prop;
} }
ObjectProperty *object_property_find(Object *obj, const char *name, 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); 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, static void object_finalize_child_property(Object *obj, const char *name,
void *opaque) void *opaque)
{ {
@ -1041,15 +1043,18 @@ void object_property_add_child(Object *obj, const char *name,
{ {
Error *local_err = NULL; Error *local_err = NULL;
gchar *type; gchar *type;
ObjectProperty *op;
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
object_property_add(obj, name, type, object_get_child_property, NULL, op = object_property_add(obj, name, type, object_get_child_property, NULL,
object_finalize_child_property, child, &local_err); object_finalize_child_property, child, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out; goto out;
} }
op->resolve = object_resolve_child_property;
object_ref(child); object_ref(child);
g_assert(child->parent == NULL); g_assert(child->parent == NULL);
child->parent = obj; 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, static void object_release_link_property(Object *obj, const char *name,
void *opaque) void *opaque)
{ {
@ -1184,6 +1196,7 @@ void object_property_add_link(Object *obj, const char *name,
Error *local_err = NULL; Error *local_err = NULL;
LinkProperty *prop = g_malloc(sizeof(*prop)); LinkProperty *prop = g_malloc(sizeof(*prop));
gchar *full_type; gchar *full_type;
ObjectProperty *op;
prop->child = child; prop->child = child;
prop->check = check; 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); full_type = g_strdup_printf("link<%s>", type);
object_property_add(obj, name, full_type, op = object_property_add(obj, name, full_type,
object_get_link_property, object_get_link_property,
check ? object_set_link_property : NULL, check ? object_set_link_property : NULL,
object_release_link_property, object_release_link_property,
prop, prop,
&local_err); &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
g_free(prop); g_free(prop);
goto out;
} }
op->resolve = object_resolve_link_property;
out:
g_free(full_type); g_free(full_type);
} }
@ -1260,11 +1277,8 @@ Object *object_resolve_path_component(Object *parent, const gchar *part)
return NULL; return NULL;
} }
if (object_property_is_link(prop)) { if (prop->resolve) {
LinkProperty *lprop = prop->opaque; return prop->resolve(parent, prop->opaque, part);
return *lprop->child;
} else if (object_property_is_child(prop)) {
return prop->opaque;
} else { } else {
return NULL; 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); 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) static void property_release_alias(Object *obj, const char *name, void *opaque)
{ {
AliasProperty *prop = opaque; AliasProperty *prop = opaque;
@ -1583,6 +1605,7 @@ void object_property_add_alias(Object *obj, const char *name,
Error **errp) Error **errp)
{ {
AliasProperty *prop; AliasProperty *prop;
ObjectProperty *op;
ObjectProperty *target_prop; ObjectProperty *target_prop;
target_prop = object_property_find(target_obj, target_name, errp); 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_obj = target_obj;
prop->target_name = target_name; prop->target_name = target_name;
object_property_add(obj, name, target_prop->type, op = object_property_add(obj, name, target_prop->type,
property_get_alias, property_get_alias,
property_set_alias, property_set_alias,
property_release_alias, property_release_alias,
prop, errp); prop, errp);
op->resolve = property_resolve_alias;
} }
static void object_instance_init(Object *obj) static void object_instance_init(Object *obj)