xref: /qemu/qom/object.c (revision 11e35bfd)
12f28d2ffSAnthony Liguori /*
22f28d2ffSAnthony Liguori  * QEMU Object Model
32f28d2ffSAnthony Liguori  *
42f28d2ffSAnthony Liguori  * Copyright IBM, Corp. 2011
52f28d2ffSAnthony Liguori  *
62f28d2ffSAnthony Liguori  * Authors:
72f28d2ffSAnthony Liguori  *  Anthony Liguori   <aliguori@us.ibm.com>
82f28d2ffSAnthony Liguori  *
92f28d2ffSAnthony Liguori  * This work is licensed under the terms of the GNU GPL, version 2 or later.
102f28d2ffSAnthony Liguori  * See the COPYING file in the top-level directory.
112f28d2ffSAnthony Liguori  */
122f28d2ffSAnthony Liguori 
132f28d2ffSAnthony Liguori #include "qemu/object.h"
142f28d2ffSAnthony Liguori #include "qemu-common.h"
1557c9fafeSAnthony Liguori #include "qapi/qapi-visit-core.h"
162f28d2ffSAnthony Liguori 
177b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency
187b7b7d18SPaolo Bonzini  * of the QOM core on QObject?  */
197b7b7d18SPaolo Bonzini #include "qemu/qom-qobject.h"
207b7b7d18SPaolo Bonzini #include "qobject.h"
217b7b7d18SPaolo Bonzini #include "qbool.h"
227b7b7d18SPaolo Bonzini #include "qint.h"
237b7b7d18SPaolo Bonzini #include "qstring.h"
247b7b7d18SPaolo Bonzini 
252f28d2ffSAnthony Liguori #define MAX_INTERFACES 32
262f28d2ffSAnthony Liguori 
272f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl;
282f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl;
292f28d2ffSAnthony Liguori 
302f28d2ffSAnthony Liguori struct InterfaceImpl
312f28d2ffSAnthony Liguori {
322f28d2ffSAnthony Liguori     const char *parent;
332f28d2ffSAnthony Liguori     void (*interface_initfn)(ObjectClass *class, void *data);
342f28d2ffSAnthony Liguori     TypeImpl *type;
352f28d2ffSAnthony Liguori };
362f28d2ffSAnthony Liguori 
372f28d2ffSAnthony Liguori struct TypeImpl
382f28d2ffSAnthony Liguori {
392f28d2ffSAnthony Liguori     const char *name;
402f28d2ffSAnthony Liguori 
412f28d2ffSAnthony Liguori     size_t class_size;
422f28d2ffSAnthony Liguori 
432f28d2ffSAnthony Liguori     size_t instance_size;
442f28d2ffSAnthony Liguori 
452f28d2ffSAnthony Liguori     void (*class_init)(ObjectClass *klass, void *data);
462f28d2ffSAnthony Liguori     void (*class_finalize)(ObjectClass *klass, void *data);
472f28d2ffSAnthony Liguori 
482f28d2ffSAnthony Liguori     void *class_data;
492f28d2ffSAnthony Liguori 
502f28d2ffSAnthony Liguori     void (*instance_init)(Object *obj);
512f28d2ffSAnthony Liguori     void (*instance_finalize)(Object *obj);
522f28d2ffSAnthony Liguori 
532f28d2ffSAnthony Liguori     bool abstract;
542f28d2ffSAnthony Liguori 
552f28d2ffSAnthony Liguori     const char *parent;
562f28d2ffSAnthony Liguori     TypeImpl *parent_type;
572f28d2ffSAnthony Liguori 
582f28d2ffSAnthony Liguori     ObjectClass *class;
592f28d2ffSAnthony Liguori 
602f28d2ffSAnthony Liguori     int num_interfaces;
612f28d2ffSAnthony Liguori     InterfaceImpl interfaces[MAX_INTERFACES];
622f28d2ffSAnthony Liguori };
632f28d2ffSAnthony Liguori 
642f28d2ffSAnthony Liguori typedef struct Interface
652f28d2ffSAnthony Liguori {
662f28d2ffSAnthony Liguori     Object parent;
672f28d2ffSAnthony Liguori     Object *obj;
682f28d2ffSAnthony Liguori } Interface;
692f28d2ffSAnthony Liguori 
702f28d2ffSAnthony Liguori #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
712f28d2ffSAnthony Liguori 
729970bd88SPaolo Bonzini static Type type_interface;
739970bd88SPaolo Bonzini 
742f28d2ffSAnthony Liguori static GHashTable *type_table_get(void)
752f28d2ffSAnthony Liguori {
762f28d2ffSAnthony Liguori     static GHashTable *type_table;
772f28d2ffSAnthony Liguori 
782f28d2ffSAnthony Liguori     if (type_table == NULL) {
792f28d2ffSAnthony Liguori         type_table = g_hash_table_new(g_str_hash, g_str_equal);
802f28d2ffSAnthony Liguori     }
812f28d2ffSAnthony Liguori 
822f28d2ffSAnthony Liguori     return type_table;
832f28d2ffSAnthony Liguori }
842f28d2ffSAnthony Liguori 
852f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti)
862f28d2ffSAnthony Liguori {
872f28d2ffSAnthony Liguori     g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
882f28d2ffSAnthony Liguori }
892f28d2ffSAnthony Liguori 
902f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name)
912f28d2ffSAnthony Liguori {
922f28d2ffSAnthony Liguori     return g_hash_table_lookup(type_table_get(), name);
932f28d2ffSAnthony Liguori }
942f28d2ffSAnthony Liguori 
952f28d2ffSAnthony Liguori TypeImpl *type_register(const TypeInfo *info)
962f28d2ffSAnthony Liguori {
972f28d2ffSAnthony Liguori     TypeImpl *ti = g_malloc0(sizeof(*ti));
982f28d2ffSAnthony Liguori 
992f28d2ffSAnthony Liguori     g_assert(info->name != NULL);
1002f28d2ffSAnthony Liguori 
10173093354SAnthony Liguori     if (type_table_lookup(info->name) != NULL) {
10273093354SAnthony Liguori         fprintf(stderr, "Registering `%s' which already exists\n", info->name);
10373093354SAnthony Liguori         abort();
10473093354SAnthony Liguori     }
10573093354SAnthony Liguori 
1062f28d2ffSAnthony Liguori     ti->name = g_strdup(info->name);
1072f28d2ffSAnthony Liguori     ti->parent = g_strdup(info->parent);
1082f28d2ffSAnthony Liguori 
1092f28d2ffSAnthony Liguori     ti->class_size = info->class_size;
1102f28d2ffSAnthony Liguori     ti->instance_size = info->instance_size;
1112f28d2ffSAnthony Liguori 
1122f28d2ffSAnthony Liguori     ti->class_init = info->class_init;
1132f28d2ffSAnthony Liguori     ti->class_finalize = info->class_finalize;
1142f28d2ffSAnthony Liguori     ti->class_data = info->class_data;
1152f28d2ffSAnthony Liguori 
1162f28d2ffSAnthony Liguori     ti->instance_init = info->instance_init;
1172f28d2ffSAnthony Liguori     ti->instance_finalize = info->instance_finalize;
1182f28d2ffSAnthony Liguori 
1192f28d2ffSAnthony Liguori     ti->abstract = info->abstract;
1202f28d2ffSAnthony Liguori 
1212f28d2ffSAnthony Liguori     if (info->interfaces) {
1222f28d2ffSAnthony Liguori         int i;
1232f28d2ffSAnthony Liguori 
1242f28d2ffSAnthony Liguori         for (i = 0; info->interfaces[i].type; i++) {
1252f28d2ffSAnthony Liguori             ti->interfaces[i].parent = info->interfaces[i].type;
1262f28d2ffSAnthony Liguori             ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
1272f28d2ffSAnthony Liguori             ti->num_interfaces++;
1282f28d2ffSAnthony Liguori         }
1292f28d2ffSAnthony Liguori     }
1302f28d2ffSAnthony Liguori 
1312f28d2ffSAnthony Liguori     type_table_add(ti);
1322f28d2ffSAnthony Liguori 
1332f28d2ffSAnthony Liguori     return ti;
1342f28d2ffSAnthony Liguori }
1352f28d2ffSAnthony Liguori 
1362f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info)
1372f28d2ffSAnthony Liguori {
1382f28d2ffSAnthony Liguori     return type_register(info);
1392f28d2ffSAnthony Liguori }
1402f28d2ffSAnthony Liguori 
1412f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name)
1422f28d2ffSAnthony Liguori {
1432f28d2ffSAnthony Liguori     if (name == NULL) {
1442f28d2ffSAnthony Liguori         return NULL;
1452f28d2ffSAnthony Liguori     }
1462f28d2ffSAnthony Liguori 
1472f28d2ffSAnthony Liguori     return type_table_lookup(name);
1482f28d2ffSAnthony Liguori }
1492f28d2ffSAnthony Liguori 
1502f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type)
1512f28d2ffSAnthony Liguori {
1522f28d2ffSAnthony Liguori     if (!type->parent_type && type->parent) {
1532f28d2ffSAnthony Liguori         type->parent_type = type_get_by_name(type->parent);
1542f28d2ffSAnthony Liguori         g_assert(type->parent_type != NULL);
1552f28d2ffSAnthony Liguori     }
1562f28d2ffSAnthony Liguori 
1572f28d2ffSAnthony Liguori     return type->parent_type;
1582f28d2ffSAnthony Liguori }
1592f28d2ffSAnthony Liguori 
1602f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type)
1612f28d2ffSAnthony Liguori {
1622f28d2ffSAnthony Liguori     return (type->parent != NULL);
1632f28d2ffSAnthony Liguori }
1642f28d2ffSAnthony Liguori 
1652f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti)
1662f28d2ffSAnthony Liguori {
1672f28d2ffSAnthony Liguori     if (ti->class_size) {
1682f28d2ffSAnthony Liguori         return ti->class_size;
1692f28d2ffSAnthony Liguori     }
1702f28d2ffSAnthony Liguori 
1712f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
1722f28d2ffSAnthony Liguori         return type_class_get_size(type_get_parent(ti));
1732f28d2ffSAnthony Liguori     }
1742f28d2ffSAnthony Liguori 
1752f28d2ffSAnthony Liguori     return sizeof(ObjectClass);
1762f28d2ffSAnthony Liguori }
1772f28d2ffSAnthony Liguori 
1782f28d2ffSAnthony Liguori static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
1792f28d2ffSAnthony Liguori {
1802f28d2ffSAnthony Liguori     TypeInfo info = {
1812f28d2ffSAnthony Liguori         .instance_size = sizeof(Interface),
1822f28d2ffSAnthony Liguori         .parent = iface->parent,
1832f28d2ffSAnthony Liguori         .class_size = sizeof(InterfaceClass),
1842f28d2ffSAnthony Liguori         .class_init = iface->interface_initfn,
1852f28d2ffSAnthony Liguori         .abstract = true,
1862f28d2ffSAnthony Liguori     };
1872f28d2ffSAnthony Liguori     char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
1882f28d2ffSAnthony Liguori 
1892f28d2ffSAnthony Liguori     info.name = name;
1902f28d2ffSAnthony Liguori     iface->type = type_register(&info);
1912f28d2ffSAnthony Liguori     g_free(name);
1922f28d2ffSAnthony Liguori }
1932f28d2ffSAnthony Liguori 
1942f28d2ffSAnthony Liguori static void type_class_init(TypeImpl *ti)
1952f28d2ffSAnthony Liguori {
1962f28d2ffSAnthony Liguori     size_t class_size = sizeof(ObjectClass);
1972f28d2ffSAnthony Liguori     int i;
1982f28d2ffSAnthony Liguori 
1992f28d2ffSAnthony Liguori     if (ti->class) {
2002f28d2ffSAnthony Liguori         return;
2012f28d2ffSAnthony Liguori     }
2022f28d2ffSAnthony Liguori 
2032f28d2ffSAnthony Liguori     ti->class_size = type_class_get_size(ti);
2042f28d2ffSAnthony Liguori 
2052f28d2ffSAnthony Liguori     ti->class = g_malloc0(ti->class_size);
2062f28d2ffSAnthony Liguori     ti->class->type = ti;
2072f28d2ffSAnthony Liguori 
2082f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
2092f28d2ffSAnthony Liguori         TypeImpl *parent = type_get_parent(ti);
2102f28d2ffSAnthony Liguori 
2112f28d2ffSAnthony Liguori         type_class_init(parent);
2122f28d2ffSAnthony Liguori 
2132f28d2ffSAnthony Liguori         class_size = parent->class_size;
2142f28d2ffSAnthony Liguori         g_assert(parent->class_size <= ti->class_size);
2152f28d2ffSAnthony Liguori 
2162f28d2ffSAnthony Liguori         memcpy((void *)ti->class + sizeof(ObjectClass),
2172f28d2ffSAnthony Liguori                (void *)parent->class + sizeof(ObjectClass),
2182f28d2ffSAnthony Liguori                parent->class_size - sizeof(ObjectClass));
2192f28d2ffSAnthony Liguori     }
2202f28d2ffSAnthony Liguori 
2212f28d2ffSAnthony Liguori     memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
2222f28d2ffSAnthony Liguori 
2232f28d2ffSAnthony Liguori     for (i = 0; i < ti->num_interfaces; i++) {
2242f28d2ffSAnthony Liguori         type_class_interface_init(ti, &ti->interfaces[i]);
2252f28d2ffSAnthony Liguori     }
2262f28d2ffSAnthony Liguori 
2272f28d2ffSAnthony Liguori     if (ti->class_init) {
2282f28d2ffSAnthony Liguori         ti->class_init(ti->class, ti->class_data);
2292f28d2ffSAnthony Liguori     }
2302f28d2ffSAnthony Liguori }
2312f28d2ffSAnthony Liguori 
2322f28d2ffSAnthony Liguori static void object_interface_init(Object *obj, InterfaceImpl *iface)
2332f28d2ffSAnthony Liguori {
2342f28d2ffSAnthony Liguori     TypeImpl *ti = iface->type;
2352f28d2ffSAnthony Liguori     Interface *iface_obj;
2362f28d2ffSAnthony Liguori 
2372f28d2ffSAnthony Liguori     iface_obj = INTERFACE(object_new(ti->name));
2382f28d2ffSAnthony Liguori     iface_obj->obj = obj;
2392f28d2ffSAnthony Liguori 
2402f28d2ffSAnthony Liguori     obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
2412f28d2ffSAnthony Liguori }
2422f28d2ffSAnthony Liguori 
2432f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti)
2442f28d2ffSAnthony Liguori {
2452f28d2ffSAnthony Liguori     int i;
2462f28d2ffSAnthony Liguori 
2472f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
2482f28d2ffSAnthony Liguori         object_init_with_type(obj, type_get_parent(ti));
2492f28d2ffSAnthony Liguori     }
2502f28d2ffSAnthony Liguori 
2512f28d2ffSAnthony Liguori     for (i = 0; i < ti->num_interfaces; i++) {
2522f28d2ffSAnthony Liguori         object_interface_init(obj, &ti->interfaces[i]);
2532f28d2ffSAnthony Liguori     }
2542f28d2ffSAnthony Liguori 
2552f28d2ffSAnthony Liguori     if (ti->instance_init) {
2562f28d2ffSAnthony Liguori         ti->instance_init(obj);
2572f28d2ffSAnthony Liguori     }
2582f28d2ffSAnthony Liguori }
2592f28d2ffSAnthony Liguori 
2602f28d2ffSAnthony Liguori void object_initialize_with_type(void *data, TypeImpl *type)
2612f28d2ffSAnthony Liguori {
2622f28d2ffSAnthony Liguori     Object *obj = data;
2632f28d2ffSAnthony Liguori 
2642f28d2ffSAnthony Liguori     g_assert(type != NULL);
2652f28d2ffSAnthony Liguori     g_assert(type->instance_size >= sizeof(ObjectClass));
2662f28d2ffSAnthony Liguori 
2672f28d2ffSAnthony Liguori     type_class_init(type);
2682f28d2ffSAnthony Liguori     g_assert(type->abstract == false);
2692f28d2ffSAnthony Liguori 
2702f28d2ffSAnthony Liguori     memset(obj, 0, type->instance_size);
2712f28d2ffSAnthony Liguori     obj->class = type->class;
27257c9fafeSAnthony Liguori     QTAILQ_INIT(&obj->properties);
2732f28d2ffSAnthony Liguori     object_init_with_type(obj, type);
2742f28d2ffSAnthony Liguori }
2752f28d2ffSAnthony Liguori 
2762f28d2ffSAnthony Liguori void object_initialize(void *data, const char *typename)
2772f28d2ffSAnthony Liguori {
2782f28d2ffSAnthony Liguori     TypeImpl *type = type_get_by_name(typename);
2792f28d2ffSAnthony Liguori 
2802f28d2ffSAnthony Liguori     object_initialize_with_type(data, type);
2812f28d2ffSAnthony Liguori }
2822f28d2ffSAnthony Liguori 
28357c9fafeSAnthony Liguori static void object_property_del_all(Object *obj)
28457c9fafeSAnthony Liguori {
28557c9fafeSAnthony Liguori     while (!QTAILQ_EMPTY(&obj->properties)) {
28657c9fafeSAnthony Liguori         ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
28757c9fafeSAnthony Liguori 
28857c9fafeSAnthony Liguori         QTAILQ_REMOVE(&obj->properties, prop, node);
28957c9fafeSAnthony Liguori 
29057c9fafeSAnthony Liguori         if (prop->release) {
29157c9fafeSAnthony Liguori             prop->release(obj, prop->name, prop->opaque);
29257c9fafeSAnthony Liguori         }
29357c9fafeSAnthony Liguori 
29457c9fafeSAnthony Liguori         g_free(prop->name);
29557c9fafeSAnthony Liguori         g_free(prop->type);
29657c9fafeSAnthony Liguori         g_free(prop);
29757c9fafeSAnthony Liguori     }
29857c9fafeSAnthony Liguori }
29957c9fafeSAnthony Liguori 
30057c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp)
30157c9fafeSAnthony Liguori {
30257c9fafeSAnthony Liguori     ObjectProperty *prop;
30357c9fafeSAnthony Liguori 
30457c9fafeSAnthony Liguori     QTAILQ_FOREACH(prop, &obj->properties, node) {
30557c9fafeSAnthony Liguori         if (!strstart(prop->type, "child<", NULL)) {
30657c9fafeSAnthony Liguori             continue;
30757c9fafeSAnthony Liguori         }
30857c9fafeSAnthony Liguori 
30957c9fafeSAnthony Liguori         if (prop->opaque == child) {
31057c9fafeSAnthony Liguori             object_property_del(obj, prop->name, errp);
31157c9fafeSAnthony Liguori         }
31257c9fafeSAnthony Liguori     }
31357c9fafeSAnthony Liguori }
31457c9fafeSAnthony Liguori 
31557c9fafeSAnthony Liguori void object_unparent(Object *obj)
31657c9fafeSAnthony Liguori {
31757c9fafeSAnthony Liguori     if (obj->parent) {
31857c9fafeSAnthony Liguori         object_property_del_child(obj->parent, obj, NULL);
31957c9fafeSAnthony Liguori     }
32057c9fafeSAnthony Liguori }
32157c9fafeSAnthony Liguori 
3222f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type)
3232f28d2ffSAnthony Liguori {
3242f28d2ffSAnthony Liguori     if (type->instance_finalize) {
3252f28d2ffSAnthony Liguori         type->instance_finalize(obj);
3262f28d2ffSAnthony Liguori     }
3272f28d2ffSAnthony Liguori 
3282f28d2ffSAnthony Liguori     while (obj->interfaces) {
3292f28d2ffSAnthony Liguori         Interface *iface_obj = obj->interfaces->data;
3302f28d2ffSAnthony Liguori         obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
3312f28d2ffSAnthony Liguori         object_delete(OBJECT(iface_obj));
3322f28d2ffSAnthony Liguori     }
3332f28d2ffSAnthony Liguori 
3342f28d2ffSAnthony Liguori     if (type_has_parent(type)) {
3352f28d2ffSAnthony Liguori         object_deinit(obj, type_get_parent(type));
3362f28d2ffSAnthony Liguori     }
33757c9fafeSAnthony Liguori 
33857c9fafeSAnthony Liguori     object_unparent(obj);
3392f28d2ffSAnthony Liguori }
3402f28d2ffSAnthony Liguori 
3412f28d2ffSAnthony Liguori void object_finalize(void *data)
3422f28d2ffSAnthony Liguori {
3432f28d2ffSAnthony Liguori     Object *obj = data;
3442f28d2ffSAnthony Liguori     TypeImpl *ti = obj->class->type;
3452f28d2ffSAnthony Liguori 
3462f28d2ffSAnthony Liguori     object_deinit(obj, ti);
34757c9fafeSAnthony Liguori     object_property_del_all(obj);
348db85b575SAnthony Liguori 
349db85b575SAnthony Liguori     g_assert(obj->ref == 0);
3502f28d2ffSAnthony Liguori }
3512f28d2ffSAnthony Liguori 
3522f28d2ffSAnthony Liguori Object *object_new_with_type(Type type)
3532f28d2ffSAnthony Liguori {
3542f28d2ffSAnthony Liguori     Object *obj;
3552f28d2ffSAnthony Liguori 
3562f28d2ffSAnthony Liguori     g_assert(type != NULL);
3572f28d2ffSAnthony Liguori 
3582f28d2ffSAnthony Liguori     obj = g_malloc(type->instance_size);
3592f28d2ffSAnthony Liguori     object_initialize_with_type(obj, type);
360db85b575SAnthony Liguori     object_ref(obj);
3612f28d2ffSAnthony Liguori 
3622f28d2ffSAnthony Liguori     return obj;
3632f28d2ffSAnthony Liguori }
3642f28d2ffSAnthony Liguori 
3652f28d2ffSAnthony Liguori Object *object_new(const char *typename)
3662f28d2ffSAnthony Liguori {
3672f28d2ffSAnthony Liguori     TypeImpl *ti = type_get_by_name(typename);
3682f28d2ffSAnthony Liguori 
3692f28d2ffSAnthony Liguori     return object_new_with_type(ti);
3702f28d2ffSAnthony Liguori }
3712f28d2ffSAnthony Liguori 
3722f28d2ffSAnthony Liguori void object_delete(Object *obj)
3732f28d2ffSAnthony Liguori {
374db85b575SAnthony Liguori     object_unref(obj);
375db85b575SAnthony Liguori     g_assert(obj->ref == 0);
3762f28d2ffSAnthony Liguori     g_free(obj);
3772f28d2ffSAnthony Liguori }
3782f28d2ffSAnthony Liguori 
379acc4af3fSPaolo Bonzini static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
3802f28d2ffSAnthony Liguori {
381acc4af3fSPaolo Bonzini     assert(target_type);
3822f28d2ffSAnthony Liguori 
3832f28d2ffSAnthony Liguori     /* Check if typename is a direct ancestor of type */
3842f28d2ffSAnthony Liguori     while (type) {
3852f28d2ffSAnthony Liguori         if (type == target_type) {
3862f28d2ffSAnthony Liguori             return true;
3872f28d2ffSAnthony Liguori         }
3882f28d2ffSAnthony Liguori 
3892f28d2ffSAnthony Liguori         type = type_get_parent(type);
3902f28d2ffSAnthony Liguori     }
3912f28d2ffSAnthony Liguori 
392acc4af3fSPaolo Bonzini     return false;
393acc4af3fSPaolo Bonzini }
3942f28d2ffSAnthony Liguori 
3959970bd88SPaolo Bonzini static bool object_is_type(Object *obj, TypeImpl *target_type)
396acc4af3fSPaolo Bonzini {
3979970bd88SPaolo Bonzini     return !target_type || type_is_ancestor(obj->class->type, target_type);
3982f28d2ffSAnthony Liguori }
3992f28d2ffSAnthony Liguori 
4002f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename)
4012f28d2ffSAnthony Liguori {
4029970bd88SPaolo Bonzini     TypeImpl *target_type = type_get_by_name(typename);
4032f28d2ffSAnthony Liguori     GSList *i;
4042f28d2ffSAnthony Liguori 
405acc4af3fSPaolo Bonzini     /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
406acc4af3fSPaolo Bonzini      * we want to go back from interfaces to the parent.
407acc4af3fSPaolo Bonzini     */
4089970bd88SPaolo Bonzini     if (target_type && object_is_type(obj, target_type)) {
409acc4af3fSPaolo Bonzini         return obj;
410acc4af3fSPaolo Bonzini     }
411acc4af3fSPaolo Bonzini 
412acc4af3fSPaolo Bonzini     /* Check if obj is an interface and its containing object is a direct
413acc4af3fSPaolo Bonzini      * ancestor of typename.  In principle we could do this test at the very
414acc4af3fSPaolo Bonzini      * beginning of object_dynamic_cast, avoiding a second call to
415acc4af3fSPaolo Bonzini      * object_is_type.  However, casting between interfaces is relatively
4169970bd88SPaolo Bonzini      * rare, and object_is_type(obj, type_interface) would fail almost always.
417acc4af3fSPaolo Bonzini      *
418acc4af3fSPaolo Bonzini      * Perhaps we could add a magic value to the object header for increased
419acc4af3fSPaolo Bonzini      * (run-time) type safety and to speed up tests like this one.  If we ever
420acc4af3fSPaolo Bonzini      * do that we can revisit the order here.
421acc4af3fSPaolo Bonzini      */
4229970bd88SPaolo Bonzini     if (object_is_type(obj, type_interface)) {
423acc4af3fSPaolo Bonzini         assert(!obj->interfaces);
424acc4af3fSPaolo Bonzini         obj = INTERFACE(obj)->obj;
4259970bd88SPaolo Bonzini         if (object_is_type(obj, target_type)) {
4262f28d2ffSAnthony Liguori             return obj;
4272f28d2ffSAnthony Liguori         }
428acc4af3fSPaolo Bonzini     }
429acc4af3fSPaolo Bonzini 
4309970bd88SPaolo Bonzini     if (!target_type) {
431acc4af3fSPaolo Bonzini         return obj;
432acc4af3fSPaolo Bonzini     }
4332f28d2ffSAnthony Liguori 
4342f28d2ffSAnthony Liguori     /* Check if obj has an interface of typename */
4352f28d2ffSAnthony Liguori     for (i = obj->interfaces; i; i = i->next) {
4362f28d2ffSAnthony Liguori         Interface *iface = i->data;
4372f28d2ffSAnthony Liguori 
4389970bd88SPaolo Bonzini         if (object_is_type(OBJECT(iface), target_type)) {
4392f28d2ffSAnthony Liguori             return OBJECT(iface);
4402f28d2ffSAnthony Liguori         }
4412f28d2ffSAnthony Liguori     }
4422f28d2ffSAnthony Liguori 
4432f28d2ffSAnthony Liguori     return NULL;
4442f28d2ffSAnthony Liguori }
4452f28d2ffSAnthony Liguori 
4462f28d2ffSAnthony Liguori 
4472f28d2ffSAnthony Liguori static void register_interface(void)
4482f28d2ffSAnthony Liguori {
4492f28d2ffSAnthony Liguori     static TypeInfo interface_info = {
4502f28d2ffSAnthony Liguori         .name = TYPE_INTERFACE,
4512f28d2ffSAnthony Liguori         .instance_size = sizeof(Interface),
4522f28d2ffSAnthony Liguori         .abstract = true,
4532f28d2ffSAnthony Liguori     };
4542f28d2ffSAnthony Liguori 
4559970bd88SPaolo Bonzini     type_interface = type_register_static(&interface_info);
4562f28d2ffSAnthony Liguori }
4572f28d2ffSAnthony Liguori 
4582f28d2ffSAnthony Liguori device_init(register_interface);
4592f28d2ffSAnthony Liguori 
4602f28d2ffSAnthony Liguori Object *object_dynamic_cast_assert(Object *obj, const char *typename)
4612f28d2ffSAnthony Liguori {
4622f28d2ffSAnthony Liguori     Object *inst;
4632f28d2ffSAnthony Liguori 
4642f28d2ffSAnthony Liguori     inst = object_dynamic_cast(obj, typename);
4652f28d2ffSAnthony Liguori 
4662f28d2ffSAnthony Liguori     if (!inst) {
4672f28d2ffSAnthony Liguori         fprintf(stderr, "Object %p is not an instance of type %s\n",
4682f28d2ffSAnthony Liguori                 obj, typename);
4692f28d2ffSAnthony Liguori         abort();
4702f28d2ffSAnthony Liguori     }
4712f28d2ffSAnthony Liguori 
4722f28d2ffSAnthony Liguori     return inst;
4732f28d2ffSAnthony Liguori }
4742f28d2ffSAnthony Liguori 
4752f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class,
4762f28d2ffSAnthony Liguori                                        const char *typename)
4772f28d2ffSAnthony Liguori {
4782f28d2ffSAnthony Liguori     TypeImpl *target_type = type_get_by_name(typename);
4792f28d2ffSAnthony Liguori     TypeImpl *type = class->type;
4802f28d2ffSAnthony Liguori 
4812f28d2ffSAnthony Liguori     while (type) {
4822f28d2ffSAnthony Liguori         if (type == target_type) {
4832f28d2ffSAnthony Liguori             return class;
4842f28d2ffSAnthony Liguori         }
4852f28d2ffSAnthony Liguori 
4862f28d2ffSAnthony Liguori         type = type_get_parent(type);
4872f28d2ffSAnthony Liguori     }
4882f28d2ffSAnthony Liguori 
4892f28d2ffSAnthony Liguori     return NULL;
4902f28d2ffSAnthony Liguori }
4912f28d2ffSAnthony Liguori 
4922f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
4932f28d2ffSAnthony Liguori                                               const char *typename)
4942f28d2ffSAnthony Liguori {
4952f28d2ffSAnthony Liguori     ObjectClass *ret = object_class_dynamic_cast(class, typename);
4962f28d2ffSAnthony Liguori 
4972f28d2ffSAnthony Liguori     if (!ret) {
4982f28d2ffSAnthony Liguori         fprintf(stderr, "Object %p is not an instance of type %s\n",
4992f28d2ffSAnthony Liguori                 class, typename);
5002f28d2ffSAnthony Liguori         abort();
5012f28d2ffSAnthony Liguori     }
5022f28d2ffSAnthony Liguori 
5032f28d2ffSAnthony Liguori     return ret;
5042f28d2ffSAnthony Liguori }
5052f28d2ffSAnthony Liguori 
5062f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj)
5072f28d2ffSAnthony Liguori {
5082f28d2ffSAnthony Liguori     return obj->class->type->name;
5092f28d2ffSAnthony Liguori }
5102f28d2ffSAnthony Liguori 
5112f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj)
5122f28d2ffSAnthony Liguori {
5132f28d2ffSAnthony Liguori     return obj->class;
5142f28d2ffSAnthony Liguori }
5152f28d2ffSAnthony Liguori 
5162f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass)
5172f28d2ffSAnthony Liguori {
5182f28d2ffSAnthony Liguori     return klass->type->name;
5192f28d2ffSAnthony Liguori }
5202f28d2ffSAnthony Liguori 
5212f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename)
5222f28d2ffSAnthony Liguori {
5232f28d2ffSAnthony Liguori     TypeImpl *type = type_get_by_name(typename);
5242f28d2ffSAnthony Liguori 
5252f28d2ffSAnthony Liguori     if (!type) {
5262f28d2ffSAnthony Liguori         return NULL;
5272f28d2ffSAnthony Liguori     }
5282f28d2ffSAnthony Liguori 
5292f28d2ffSAnthony Liguori     type_class_init(type);
5302f28d2ffSAnthony Liguori 
5312f28d2ffSAnthony Liguori     return type->class;
5322f28d2ffSAnthony Liguori }
5332f28d2ffSAnthony Liguori 
5342f28d2ffSAnthony Liguori typedef struct OCFData
5352f28d2ffSAnthony Liguori {
5362f28d2ffSAnthony Liguori     void (*fn)(ObjectClass *klass, void *opaque);
53793c511a1SAnthony Liguori     const char *implements_type;
53893c511a1SAnthony Liguori     bool include_abstract;
5392f28d2ffSAnthony Liguori     void *opaque;
5402f28d2ffSAnthony Liguori } OCFData;
5412f28d2ffSAnthony Liguori 
5422f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value,
5432f28d2ffSAnthony Liguori                                        gpointer opaque)
5442f28d2ffSAnthony Liguori {
5452f28d2ffSAnthony Liguori     OCFData *data = opaque;
5462f28d2ffSAnthony Liguori     TypeImpl *type = value;
54793c511a1SAnthony Liguori     ObjectClass *k;
5482f28d2ffSAnthony Liguori 
5492f28d2ffSAnthony Liguori     type_class_init(type);
55093c511a1SAnthony Liguori     k = type->class;
5512f28d2ffSAnthony Liguori 
55293c511a1SAnthony Liguori     if (!data->include_abstract && type->abstract) {
55393c511a1SAnthony Liguori         return;
55493c511a1SAnthony Liguori     }
55593c511a1SAnthony Liguori 
55693c511a1SAnthony Liguori     if (data->implements_type &&
55793c511a1SAnthony Liguori         !object_class_dynamic_cast(k, data->implements_type)) {
55893c511a1SAnthony Liguori         return;
55993c511a1SAnthony Liguori     }
56093c511a1SAnthony Liguori 
56193c511a1SAnthony Liguori     data->fn(k, data->opaque);
5622f28d2ffSAnthony Liguori }
5632f28d2ffSAnthony Liguori 
5642f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
56593c511a1SAnthony Liguori                           const char *implements_type, bool include_abstract,
5662f28d2ffSAnthony Liguori                           void *opaque)
5672f28d2ffSAnthony Liguori {
56893c511a1SAnthony Liguori     OCFData data = { fn, implements_type, include_abstract, opaque };
5692f28d2ffSAnthony Liguori 
5702f28d2ffSAnthony Liguori     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
5712f28d2ffSAnthony Liguori }
57257c9fafeSAnthony Liguori 
57357c9fafeSAnthony Liguori void object_ref(Object *obj)
57457c9fafeSAnthony Liguori {
57557c9fafeSAnthony Liguori     obj->ref++;
57657c9fafeSAnthony Liguori }
57757c9fafeSAnthony Liguori 
57857c9fafeSAnthony Liguori void object_unref(Object *obj)
57957c9fafeSAnthony Liguori {
58057c9fafeSAnthony Liguori     g_assert(obj->ref > 0);
58157c9fafeSAnthony Liguori     obj->ref--;
58257c9fafeSAnthony Liguori 
58357c9fafeSAnthony Liguori     /* parent always holds a reference to its children */
58457c9fafeSAnthony Liguori     if (obj->ref == 0) {
58557c9fafeSAnthony Liguori         object_finalize(obj);
58657c9fafeSAnthony Liguori     }
58757c9fafeSAnthony Liguori }
58857c9fafeSAnthony Liguori 
58957c9fafeSAnthony Liguori void object_property_add(Object *obj, const char *name, const char *type,
59057c9fafeSAnthony Liguori                          ObjectPropertyAccessor *get,
59157c9fafeSAnthony Liguori                          ObjectPropertyAccessor *set,
59257c9fafeSAnthony Liguori                          ObjectPropertyRelease *release,
59357c9fafeSAnthony Liguori                          void *opaque, Error **errp)
59457c9fafeSAnthony Liguori {
59557c9fafeSAnthony Liguori     ObjectProperty *prop = g_malloc0(sizeof(*prop));
59657c9fafeSAnthony Liguori 
59757c9fafeSAnthony Liguori     prop->name = g_strdup(name);
59857c9fafeSAnthony Liguori     prop->type = g_strdup(type);
59957c9fafeSAnthony Liguori 
60057c9fafeSAnthony Liguori     prop->get = get;
60157c9fafeSAnthony Liguori     prop->set = set;
60257c9fafeSAnthony Liguori     prop->release = release;
60357c9fafeSAnthony Liguori     prop->opaque = opaque;
60457c9fafeSAnthony Liguori 
60557c9fafeSAnthony Liguori     QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
60657c9fafeSAnthony Liguori }
60757c9fafeSAnthony Liguori 
60857c9fafeSAnthony Liguori static ObjectProperty *object_property_find(Object *obj, const char *name)
60957c9fafeSAnthony Liguori {
61057c9fafeSAnthony Liguori     ObjectProperty *prop;
61157c9fafeSAnthony Liguori 
61257c9fafeSAnthony Liguori     QTAILQ_FOREACH(prop, &obj->properties, node) {
61357c9fafeSAnthony Liguori         if (strcmp(prop->name, name) == 0) {
61457c9fafeSAnthony Liguori             return prop;
61557c9fafeSAnthony Liguori         }
61657c9fafeSAnthony Liguori     }
61757c9fafeSAnthony Liguori 
61857c9fafeSAnthony Liguori     return NULL;
61957c9fafeSAnthony Liguori }
62057c9fafeSAnthony Liguori 
62157c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp)
62257c9fafeSAnthony Liguori {
62357c9fafeSAnthony Liguori     ObjectProperty *prop = object_property_find(obj, name);
62457c9fafeSAnthony Liguori 
62557c9fafeSAnthony Liguori     QTAILQ_REMOVE(&obj->properties, prop, node);
62657c9fafeSAnthony Liguori 
62757c9fafeSAnthony Liguori     prop->release(obj, prop->name, prop->opaque);
62857c9fafeSAnthony Liguori 
62957c9fafeSAnthony Liguori     g_free(prop->name);
63057c9fafeSAnthony Liguori     g_free(prop->type);
63157c9fafeSAnthony Liguori     g_free(prop);
63257c9fafeSAnthony Liguori }
63357c9fafeSAnthony Liguori 
63457c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name,
63557c9fafeSAnthony Liguori                          Error **errp)
63657c9fafeSAnthony Liguori {
63757c9fafeSAnthony Liguori     ObjectProperty *prop = object_property_find(obj, name);
63857c9fafeSAnthony Liguori 
63957c9fafeSAnthony Liguori     if (prop == NULL) {
64057c9fafeSAnthony Liguori         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
64157c9fafeSAnthony Liguori         return;
64257c9fafeSAnthony Liguori     }
64357c9fafeSAnthony Liguori 
64457c9fafeSAnthony Liguori     if (!prop->get) {
64557c9fafeSAnthony Liguori         error_set(errp, QERR_PERMISSION_DENIED);
64657c9fafeSAnthony Liguori     } else {
64757c9fafeSAnthony Liguori         prop->get(obj, v, prop->opaque, name, errp);
64857c9fafeSAnthony Liguori     }
64957c9fafeSAnthony Liguori }
65057c9fafeSAnthony Liguori 
65157c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name,
65257c9fafeSAnthony Liguori                          Error **errp)
65357c9fafeSAnthony Liguori {
65457c9fafeSAnthony Liguori     ObjectProperty *prop = object_property_find(obj, name);
65557c9fafeSAnthony Liguori 
65657c9fafeSAnthony Liguori     if (prop == NULL) {
65757c9fafeSAnthony Liguori         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
65857c9fafeSAnthony Liguori         return;
65957c9fafeSAnthony Liguori     }
66057c9fafeSAnthony Liguori 
66157c9fafeSAnthony Liguori     if (!prop->set) {
66257c9fafeSAnthony Liguori         error_set(errp, QERR_PERMISSION_DENIED);
66357c9fafeSAnthony Liguori     } else {
66457c9fafeSAnthony Liguori         prop->set(obj, v, prop->opaque, name, errp);
66557c9fafeSAnthony Liguori     }
66657c9fafeSAnthony Liguori }
66757c9fafeSAnthony Liguori 
6687b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value,
6697b7b7d18SPaolo Bonzini                              const char *name, Error **errp)
6707b7b7d18SPaolo Bonzini {
6717b7b7d18SPaolo Bonzini     QString *qstr = qstring_from_str(value);
6727b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
6737b7b7d18SPaolo Bonzini 
6747b7b7d18SPaolo Bonzini     QDECREF(qstr);
6757b7b7d18SPaolo Bonzini }
6767b7b7d18SPaolo Bonzini 
6777b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name,
6787b7b7d18SPaolo Bonzini                               Error **errp)
6797b7b7d18SPaolo Bonzini {
6807b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
6817b7b7d18SPaolo Bonzini     QString *qstring;
6827b7b7d18SPaolo Bonzini     char *retval;
6837b7b7d18SPaolo Bonzini 
6847b7b7d18SPaolo Bonzini     if (!ret) {
6857b7b7d18SPaolo Bonzini         return NULL;
6867b7b7d18SPaolo Bonzini     }
6877b7b7d18SPaolo Bonzini     qstring = qobject_to_qstring(ret);
6887b7b7d18SPaolo Bonzini     if (!qstring) {
6897b7b7d18SPaolo Bonzini         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
6907b7b7d18SPaolo Bonzini         retval = NULL;
6917b7b7d18SPaolo Bonzini     } else {
6927b7b7d18SPaolo Bonzini         retval = g_strdup(qstring_get_str(qstring));
6937b7b7d18SPaolo Bonzini     }
6947b7b7d18SPaolo Bonzini 
6957b7b7d18SPaolo Bonzini     QDECREF(qstring);
6967b7b7d18SPaolo Bonzini     return retval;
6977b7b7d18SPaolo Bonzini }
6987b7b7d18SPaolo Bonzini 
6997b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value,
7007b7b7d18SPaolo Bonzini                               const char *name, Error **errp)
7017b7b7d18SPaolo Bonzini {
7027b7b7d18SPaolo Bonzini     QBool *qbool = qbool_from_int(value);
7037b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
7047b7b7d18SPaolo Bonzini 
7057b7b7d18SPaolo Bonzini     QDECREF(qbool);
7067b7b7d18SPaolo Bonzini }
7077b7b7d18SPaolo Bonzini 
7087b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name,
7097b7b7d18SPaolo Bonzini                               Error **errp)
7107b7b7d18SPaolo Bonzini {
7117b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
7127b7b7d18SPaolo Bonzini     QBool *qbool;
7137b7b7d18SPaolo Bonzini     bool retval;
7147b7b7d18SPaolo Bonzini 
7157b7b7d18SPaolo Bonzini     if (!ret) {
7167b7b7d18SPaolo Bonzini         return false;
7177b7b7d18SPaolo Bonzini     }
7187b7b7d18SPaolo Bonzini     qbool = qobject_to_qbool(ret);
7197b7b7d18SPaolo Bonzini     if (!qbool) {
7207b7b7d18SPaolo Bonzini         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
7217b7b7d18SPaolo Bonzini         retval = false;
7227b7b7d18SPaolo Bonzini     } else {
7237b7b7d18SPaolo Bonzini         retval = qbool_get_int(qbool);
7247b7b7d18SPaolo Bonzini     }
7257b7b7d18SPaolo Bonzini 
7267b7b7d18SPaolo Bonzini     QDECREF(qbool);
7277b7b7d18SPaolo Bonzini     return retval;
7287b7b7d18SPaolo Bonzini }
7297b7b7d18SPaolo Bonzini 
7307b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value,
7317b7b7d18SPaolo Bonzini                              const char *name, Error **errp)
7327b7b7d18SPaolo Bonzini {
7337b7b7d18SPaolo Bonzini     QInt *qint = qint_from_int(value);
7347b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qint), name, errp);
7357b7b7d18SPaolo Bonzini 
7367b7b7d18SPaolo Bonzini     QDECREF(qint);
7377b7b7d18SPaolo Bonzini }
7387b7b7d18SPaolo Bonzini 
7397b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name,
7407b7b7d18SPaolo Bonzini                                 Error **errp)
7417b7b7d18SPaolo Bonzini {
7427b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
7437b7b7d18SPaolo Bonzini     QInt *qint;
7447b7b7d18SPaolo Bonzini     int64_t retval;
7457b7b7d18SPaolo Bonzini 
7467b7b7d18SPaolo Bonzini     if (!ret) {
7477b7b7d18SPaolo Bonzini         return -1;
7487b7b7d18SPaolo Bonzini     }
7497b7b7d18SPaolo Bonzini     qint = qobject_to_qint(ret);
7507b7b7d18SPaolo Bonzini     if (!qint) {
7517b7b7d18SPaolo Bonzini         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
7527b7b7d18SPaolo Bonzini         retval = -1;
7537b7b7d18SPaolo Bonzini     } else {
7547b7b7d18SPaolo Bonzini         retval = qint_get_int(qint);
7557b7b7d18SPaolo Bonzini     }
7567b7b7d18SPaolo Bonzini 
7577b7b7d18SPaolo Bonzini     QDECREF(qint);
7587b7b7d18SPaolo Bonzini     return retval;
7597b7b7d18SPaolo Bonzini }
7607b7b7d18SPaolo Bonzini 
76157c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp)
76257c9fafeSAnthony Liguori {
76357c9fafeSAnthony Liguori     ObjectProperty *prop = object_property_find(obj, name);
76457c9fafeSAnthony Liguori 
76557c9fafeSAnthony Liguori     if (prop == NULL) {
76657c9fafeSAnthony Liguori         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
76757c9fafeSAnthony Liguori         return NULL;
76857c9fafeSAnthony Liguori     }
76957c9fafeSAnthony Liguori 
77057c9fafeSAnthony Liguori     return prop->type;
77157c9fafeSAnthony Liguori }
77257c9fafeSAnthony Liguori 
77357c9fafeSAnthony Liguori Object *object_get_root(void)
77457c9fafeSAnthony Liguori {
7758b45d447SAnthony Liguori     static Object *root;
77657c9fafeSAnthony Liguori 
7778b45d447SAnthony Liguori     if (!root) {
7788b45d447SAnthony Liguori         root = object_new("container");
77957c9fafeSAnthony Liguori     }
78057c9fafeSAnthony Liguori 
7818b45d447SAnthony Liguori     return root;
78257c9fafeSAnthony Liguori }
78357c9fafeSAnthony Liguori 
78457c9fafeSAnthony Liguori static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
78557c9fafeSAnthony Liguori                                       const char *name, Error **errp)
78657c9fafeSAnthony Liguori {
78757c9fafeSAnthony Liguori     Object *child = opaque;
78857c9fafeSAnthony Liguori     gchar *path;
78957c9fafeSAnthony Liguori 
79057c9fafeSAnthony Liguori     path = object_get_canonical_path(child);
79157c9fafeSAnthony Liguori     visit_type_str(v, &path, name, errp);
79257c9fafeSAnthony Liguori     g_free(path);
79357c9fafeSAnthony Liguori }
79457c9fafeSAnthony Liguori 
795db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name,
796db85b575SAnthony Liguori                                            void *opaque)
797db85b575SAnthony Liguori {
798db85b575SAnthony Liguori     Object *child = opaque;
799db85b575SAnthony Liguori 
800db85b575SAnthony Liguori     object_unref(child);
801db85b575SAnthony Liguori }
802db85b575SAnthony Liguori 
80357c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name,
80457c9fafeSAnthony Liguori                                Object *child, Error **errp)
80557c9fafeSAnthony Liguori {
80657c9fafeSAnthony Liguori     gchar *type;
80757c9fafeSAnthony Liguori 
80857c9fafeSAnthony Liguori     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
80957c9fafeSAnthony Liguori 
81057c9fafeSAnthony Liguori     object_property_add(obj, name, type, object_get_child_property,
811db85b575SAnthony Liguori                         NULL, object_finalize_child_property, child, errp);
81257c9fafeSAnthony Liguori 
81357c9fafeSAnthony Liguori     object_ref(child);
81457c9fafeSAnthony Liguori     g_assert(child->parent == NULL);
81557c9fafeSAnthony Liguori     child->parent = obj;
81657c9fafeSAnthony Liguori 
81757c9fafeSAnthony Liguori     g_free(type);
81857c9fafeSAnthony Liguori }
81957c9fafeSAnthony Liguori 
82057c9fafeSAnthony Liguori static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
82157c9fafeSAnthony Liguori                                      const char *name, Error **errp)
82257c9fafeSAnthony Liguori {
82357c9fafeSAnthony Liguori     Object **child = opaque;
82457c9fafeSAnthony Liguori     gchar *path;
82557c9fafeSAnthony Liguori 
82657c9fafeSAnthony Liguori     if (*child) {
82757c9fafeSAnthony Liguori         path = object_get_canonical_path(*child);
82857c9fafeSAnthony Liguori         visit_type_str(v, &path, name, errp);
82957c9fafeSAnthony Liguori         g_free(path);
83057c9fafeSAnthony Liguori     } else {
83157c9fafeSAnthony Liguori         path = (gchar *)"";
83257c9fafeSAnthony Liguori         visit_type_str(v, &path, name, errp);
83357c9fafeSAnthony Liguori     }
83457c9fafeSAnthony Liguori }
83557c9fafeSAnthony Liguori 
83657c9fafeSAnthony Liguori static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
83757c9fafeSAnthony Liguori                                      const char *name, Error **errp)
83857c9fafeSAnthony Liguori {
83957c9fafeSAnthony Liguori     Object **child = opaque;
84057c9fafeSAnthony Liguori     bool ambiguous = false;
84157c9fafeSAnthony Liguori     const char *type;
84257c9fafeSAnthony Liguori     char *path;
843*11e35bfdSPaolo Bonzini     gchar *target_type;
84457c9fafeSAnthony Liguori 
84557c9fafeSAnthony Liguori     type = object_property_get_type(obj, name, NULL);
84657c9fafeSAnthony Liguori 
84757c9fafeSAnthony Liguori     visit_type_str(v, &path, name, errp);
84857c9fafeSAnthony Liguori 
84957c9fafeSAnthony Liguori     if (*child) {
85057c9fafeSAnthony Liguori         object_unref(*child);
851*11e35bfdSPaolo Bonzini         *child = NULL;
85257c9fafeSAnthony Liguori     }
85357c9fafeSAnthony Liguori 
85457c9fafeSAnthony Liguori     if (strcmp(path, "") != 0) {
85557c9fafeSAnthony Liguori         Object *target;
85657c9fafeSAnthony Liguori 
8578f770d39SPaolo Bonzini         /* Go from link<FOO> to FOO.  */
858*11e35bfdSPaolo Bonzini         target_type = g_strndup(&type[5], strlen(type) - 6);
859*11e35bfdSPaolo Bonzini         target = object_resolve_path_type(path, target_type, &ambiguous);
860*11e35bfdSPaolo Bonzini 
861*11e35bfdSPaolo Bonzini         if (ambiguous) {
862*11e35bfdSPaolo Bonzini             error_set(errp, QERR_AMBIGUOUS_PATH, path);
863*11e35bfdSPaolo Bonzini         } else if (target) {
86457c9fafeSAnthony Liguori             object_ref(target);
865fe40e627SAnthony Liguori             *child = target;
86657c9fafeSAnthony Liguori         } else {
867*11e35bfdSPaolo Bonzini             target = object_resolve_path(path, &ambiguous);
868*11e35bfdSPaolo Bonzini             if (target || ambiguous) {
869*11e35bfdSPaolo Bonzini                 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
87057c9fafeSAnthony Liguori             } else {
87157c9fafeSAnthony Liguori                 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
87257c9fafeSAnthony Liguori             }
873*11e35bfdSPaolo Bonzini         }
874*11e35bfdSPaolo Bonzini         g_free(target_type);
87557c9fafeSAnthony Liguori     }
87657c9fafeSAnthony Liguori 
87757c9fafeSAnthony Liguori     g_free(path);
87857c9fafeSAnthony Liguori }
87957c9fafeSAnthony Liguori 
88057c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name,
88157c9fafeSAnthony Liguori                               const char *type, Object **child,
88257c9fafeSAnthony Liguori                               Error **errp)
88357c9fafeSAnthony Liguori {
88457c9fafeSAnthony Liguori     gchar *full_type;
88557c9fafeSAnthony Liguori 
88657c9fafeSAnthony Liguori     full_type = g_strdup_printf("link<%s>", type);
88757c9fafeSAnthony Liguori 
88857c9fafeSAnthony Liguori     object_property_add(obj, name, full_type,
88957c9fafeSAnthony Liguori                         object_get_link_property,
89057c9fafeSAnthony Liguori                         object_set_link_property,
89157c9fafeSAnthony Liguori                         NULL, child, errp);
89257c9fafeSAnthony Liguori 
89357c9fafeSAnthony Liguori     g_free(full_type);
89457c9fafeSAnthony Liguori }
89557c9fafeSAnthony Liguori 
89657c9fafeSAnthony Liguori gchar *object_get_canonical_path(Object *obj)
89757c9fafeSAnthony Liguori {
89857c9fafeSAnthony Liguori     Object *root = object_get_root();
89957c9fafeSAnthony Liguori     char *newpath = NULL, *path = NULL;
90057c9fafeSAnthony Liguori 
90157c9fafeSAnthony Liguori     while (obj != root) {
90257c9fafeSAnthony Liguori         ObjectProperty *prop = NULL;
90357c9fafeSAnthony Liguori 
90457c9fafeSAnthony Liguori         g_assert(obj->parent != NULL);
90557c9fafeSAnthony Liguori 
90657c9fafeSAnthony Liguori         QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
90757c9fafeSAnthony Liguori             if (!strstart(prop->type, "child<", NULL)) {
90857c9fafeSAnthony Liguori                 continue;
90957c9fafeSAnthony Liguori             }
91057c9fafeSAnthony Liguori 
91157c9fafeSAnthony Liguori             if (prop->opaque == obj) {
91257c9fafeSAnthony Liguori                 if (path) {
91357c9fafeSAnthony Liguori                     newpath = g_strdup_printf("%s/%s", prop->name, path);
91457c9fafeSAnthony Liguori                     g_free(path);
91557c9fafeSAnthony Liguori                     path = newpath;
91657c9fafeSAnthony Liguori                 } else {
91757c9fafeSAnthony Liguori                     path = g_strdup(prop->name);
91857c9fafeSAnthony Liguori                 }
91957c9fafeSAnthony Liguori                 break;
92057c9fafeSAnthony Liguori             }
92157c9fafeSAnthony Liguori         }
92257c9fafeSAnthony Liguori 
92357c9fafeSAnthony Liguori         g_assert(prop != NULL);
92457c9fafeSAnthony Liguori 
92557c9fafeSAnthony Liguori         obj = obj->parent;
92657c9fafeSAnthony Liguori     }
92757c9fafeSAnthony Liguori 
92857c9fafeSAnthony Liguori     newpath = g_strdup_printf("/%s", path);
92957c9fafeSAnthony Liguori     g_free(path);
93057c9fafeSAnthony Liguori 
93157c9fafeSAnthony Liguori     return newpath;
93257c9fafeSAnthony Liguori }
93357c9fafeSAnthony Liguori 
93457c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent,
93557c9fafeSAnthony Liguori                                           gchar **parts,
93602fe2db6SPaolo Bonzini                                           const char *typename,
93757c9fafeSAnthony Liguori                                           int index)
93857c9fafeSAnthony Liguori {
93957c9fafeSAnthony Liguori     ObjectProperty *prop;
94057c9fafeSAnthony Liguori     Object *child;
94157c9fafeSAnthony Liguori 
94257c9fafeSAnthony Liguori     if (parts[index] == NULL) {
94302fe2db6SPaolo Bonzini         return object_dynamic_cast(parent, typename);
94457c9fafeSAnthony Liguori     }
94557c9fafeSAnthony Liguori 
94657c9fafeSAnthony Liguori     if (strcmp(parts[index], "") == 0) {
94702fe2db6SPaolo Bonzini         return object_resolve_abs_path(parent, parts, typename, index + 1);
94857c9fafeSAnthony Liguori     }
94957c9fafeSAnthony Liguori 
95057c9fafeSAnthony Liguori     prop = object_property_find(parent, parts[index]);
95157c9fafeSAnthony Liguori     if (prop == NULL) {
95257c9fafeSAnthony Liguori         return NULL;
95357c9fafeSAnthony Liguori     }
95457c9fafeSAnthony Liguori 
95557c9fafeSAnthony Liguori     child = NULL;
95657c9fafeSAnthony Liguori     if (strstart(prop->type, "link<", NULL)) {
95757c9fafeSAnthony Liguori         Object **pchild = prop->opaque;
95857c9fafeSAnthony Liguori         if (*pchild) {
95957c9fafeSAnthony Liguori             child = *pchild;
96057c9fafeSAnthony Liguori         }
96157c9fafeSAnthony Liguori     } else if (strstart(prop->type, "child<", NULL)) {
96257c9fafeSAnthony Liguori         child = prop->opaque;
96357c9fafeSAnthony Liguori     }
96457c9fafeSAnthony Liguori 
96557c9fafeSAnthony Liguori     if (!child) {
96657c9fafeSAnthony Liguori         return NULL;
96757c9fafeSAnthony Liguori     }
96857c9fafeSAnthony Liguori 
96902fe2db6SPaolo Bonzini     return object_resolve_abs_path(child, parts, typename, index + 1);
97057c9fafeSAnthony Liguori }
97157c9fafeSAnthony Liguori 
97257c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent,
97357c9fafeSAnthony Liguori                                               gchar **parts,
97402fe2db6SPaolo Bonzini                                               const char *typename,
97557c9fafeSAnthony Liguori                                               bool *ambiguous)
97657c9fafeSAnthony Liguori {
97757c9fafeSAnthony Liguori     Object *obj;
97857c9fafeSAnthony Liguori     ObjectProperty *prop;
97957c9fafeSAnthony Liguori 
98002fe2db6SPaolo Bonzini     obj = object_resolve_abs_path(parent, parts, typename, 0);
98157c9fafeSAnthony Liguori 
98257c9fafeSAnthony Liguori     QTAILQ_FOREACH(prop, &parent->properties, node) {
98357c9fafeSAnthony Liguori         Object *found;
98457c9fafeSAnthony Liguori 
98557c9fafeSAnthony Liguori         if (!strstart(prop->type, "child<", NULL)) {
98657c9fafeSAnthony Liguori             continue;
98757c9fafeSAnthony Liguori         }
98857c9fafeSAnthony Liguori 
98902fe2db6SPaolo Bonzini         found = object_resolve_partial_path(prop->opaque, parts,
99002fe2db6SPaolo Bonzini                                             typename, ambiguous);
99157c9fafeSAnthony Liguori         if (found) {
99257c9fafeSAnthony Liguori             if (obj) {
99357c9fafeSAnthony Liguori                 if (ambiguous) {
99457c9fafeSAnthony Liguori                     *ambiguous = true;
99557c9fafeSAnthony Liguori                 }
99657c9fafeSAnthony Liguori                 return NULL;
99757c9fafeSAnthony Liguori             }
99857c9fafeSAnthony Liguori             obj = found;
99957c9fafeSAnthony Liguori         }
100057c9fafeSAnthony Liguori 
100157c9fafeSAnthony Liguori         if (ambiguous && *ambiguous) {
100257c9fafeSAnthony Liguori             return NULL;
100357c9fafeSAnthony Liguori         }
100457c9fafeSAnthony Liguori     }
100557c9fafeSAnthony Liguori 
100657c9fafeSAnthony Liguori     return obj;
100757c9fafeSAnthony Liguori }
100857c9fafeSAnthony Liguori 
100902fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename,
101002fe2db6SPaolo Bonzini                                  bool *ambiguous)
101157c9fafeSAnthony Liguori {
101257c9fafeSAnthony Liguori     bool partial_path = true;
101357c9fafeSAnthony Liguori     Object *obj;
101457c9fafeSAnthony Liguori     gchar **parts;
101557c9fafeSAnthony Liguori 
101657c9fafeSAnthony Liguori     parts = g_strsplit(path, "/", 0);
101757c9fafeSAnthony Liguori     if (parts == NULL || parts[0] == NULL) {
101857c9fafeSAnthony Liguori         g_strfreev(parts);
101957c9fafeSAnthony Liguori         return object_get_root();
102057c9fafeSAnthony Liguori     }
102157c9fafeSAnthony Liguori 
102257c9fafeSAnthony Liguori     if (strcmp(parts[0], "") == 0) {
102357c9fafeSAnthony Liguori         partial_path = false;
102457c9fafeSAnthony Liguori     }
102557c9fafeSAnthony Liguori 
102657c9fafeSAnthony Liguori     if (partial_path) {
102757c9fafeSAnthony Liguori         if (ambiguous) {
102857c9fafeSAnthony Liguori             *ambiguous = false;
102957c9fafeSAnthony Liguori         }
103002fe2db6SPaolo Bonzini         obj = object_resolve_partial_path(object_get_root(), parts,
103102fe2db6SPaolo Bonzini                                           typename, ambiguous);
103257c9fafeSAnthony Liguori     } else {
103302fe2db6SPaolo Bonzini         obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
103457c9fafeSAnthony Liguori     }
103557c9fafeSAnthony Liguori 
103657c9fafeSAnthony Liguori     g_strfreev(parts);
103757c9fafeSAnthony Liguori 
103857c9fafeSAnthony Liguori     return obj;
103957c9fafeSAnthony Liguori }
104057c9fafeSAnthony Liguori 
104102fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous)
104202fe2db6SPaolo Bonzini {
104302fe2db6SPaolo Bonzini     return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
104402fe2db6SPaolo Bonzini }
104502fe2db6SPaolo Bonzini 
104657c9fafeSAnthony Liguori typedef struct StringProperty
104757c9fafeSAnthony Liguori {
104857c9fafeSAnthony Liguori     char *(*get)(Object *, Error **);
104957c9fafeSAnthony Liguori     void (*set)(Object *, const char *, Error **);
105057c9fafeSAnthony Liguori } StringProperty;
105157c9fafeSAnthony Liguori 
10527b7b7d18SPaolo Bonzini static void property_get_str(Object *obj, Visitor *v, void *opaque,
105357c9fafeSAnthony Liguori                              const char *name, Error **errp)
105457c9fafeSAnthony Liguori {
105557c9fafeSAnthony Liguori     StringProperty *prop = opaque;
105657c9fafeSAnthony Liguori     char *value;
105757c9fafeSAnthony Liguori 
105857c9fafeSAnthony Liguori     value = prop->get(obj, errp);
105957c9fafeSAnthony Liguori     if (value) {
106057c9fafeSAnthony Liguori         visit_type_str(v, &value, name, errp);
106157c9fafeSAnthony Liguori         g_free(value);
106257c9fafeSAnthony Liguori     }
106357c9fafeSAnthony Liguori }
106457c9fafeSAnthony Liguori 
10657b7b7d18SPaolo Bonzini static void property_set_str(Object *obj, Visitor *v, void *opaque,
106657c9fafeSAnthony Liguori                              const char *name, Error **errp)
106757c9fafeSAnthony Liguori {
106857c9fafeSAnthony Liguori     StringProperty *prop = opaque;
106957c9fafeSAnthony Liguori     char *value;
107057c9fafeSAnthony Liguori     Error *local_err = NULL;
107157c9fafeSAnthony Liguori 
107257c9fafeSAnthony Liguori     visit_type_str(v, &value, name, &local_err);
107357c9fafeSAnthony Liguori     if (local_err) {
107457c9fafeSAnthony Liguori         error_propagate(errp, local_err);
107557c9fafeSAnthony Liguori         return;
107657c9fafeSAnthony Liguori     }
107757c9fafeSAnthony Liguori 
107857c9fafeSAnthony Liguori     prop->set(obj, value, errp);
107957c9fafeSAnthony Liguori     g_free(value);
108057c9fafeSAnthony Liguori }
108157c9fafeSAnthony Liguori 
10827b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name,
108357c9fafeSAnthony Liguori                                  void *opaque)
108457c9fafeSAnthony Liguori {
108557c9fafeSAnthony Liguori     StringProperty *prop = opaque;
108657c9fafeSAnthony Liguori     g_free(prop);
108757c9fafeSAnthony Liguori }
108857c9fafeSAnthony Liguori 
108957c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name,
109057c9fafeSAnthony Liguori                            char *(*get)(Object *, Error **),
109157c9fafeSAnthony Liguori                            void (*set)(Object *, const char *, Error **),
109257c9fafeSAnthony Liguori                            Error **errp)
109357c9fafeSAnthony Liguori {
109457c9fafeSAnthony Liguori     StringProperty *prop = g_malloc0(sizeof(*prop));
109557c9fafeSAnthony Liguori 
109657c9fafeSAnthony Liguori     prop->get = get;
109757c9fafeSAnthony Liguori     prop->set = set;
109857c9fafeSAnthony Liguori 
109957c9fafeSAnthony Liguori     object_property_add(obj, name, "string",
11007b7b7d18SPaolo Bonzini                         get ? property_get_str : NULL,
11017b7b7d18SPaolo Bonzini                         set ? property_set_str : NULL,
11027b7b7d18SPaolo Bonzini                         property_release_str,
110357c9fafeSAnthony Liguori                         prop, errp);
110457c9fafeSAnthony Liguori }
1105