mirror of https://github.com/xemu-project/xemu.git
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:
parent
ef7c7ff6d4
commit
64607d0881
|
@ -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);
|
||||||
|
|
||||||
|
|
82
qom/object.c
82
qom/object.c
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue