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 1314cccb61SPaolo Bonzini #include "qom/object.h" 142f28d2ffSAnthony Liguori #include "qemu-common.h" 157b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 161f21772dSHu Tao #include "qapi-visit.h" 17b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h" 18b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h" 197b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 20fa131d94SPaolo Bonzini #include "trace.h" 212f28d2ffSAnthony Liguori 227b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency 237b7b7d18SPaolo Bonzini * of the QOM core on QObject? */ 2414cccb61SPaolo Bonzini #include "qom/qom-qobject.h" 257b1b5d19SPaolo Bonzini #include "qapi/qmp/qobject.h" 267b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h" 277b1b5d19SPaolo Bonzini #include "qapi/qmp/qint.h" 287b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h" 297b7b7d18SPaolo Bonzini 302f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 312f28d2ffSAnthony Liguori 322f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 332f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 342f28d2ffSAnthony Liguori 352f28d2ffSAnthony Liguori struct InterfaceImpl 362f28d2ffSAnthony Liguori { 3733e95c63SAnthony Liguori const char *typename; 382f28d2ffSAnthony Liguori }; 392f28d2ffSAnthony Liguori 402f28d2ffSAnthony Liguori struct TypeImpl 412f28d2ffSAnthony Liguori { 422f28d2ffSAnthony Liguori const char *name; 432f28d2ffSAnthony Liguori 442f28d2ffSAnthony Liguori size_t class_size; 452f28d2ffSAnthony Liguori 462f28d2ffSAnthony Liguori size_t instance_size; 472f28d2ffSAnthony Liguori 482f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 493b50e311SPaolo Bonzini void (*class_base_init)(ObjectClass *klass, void *data); 502f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 512f28d2ffSAnthony Liguori 522f28d2ffSAnthony Liguori void *class_data; 532f28d2ffSAnthony Liguori 542f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 558231c2ddSEduardo Habkost void (*instance_post_init)(Object *obj); 562f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 572f28d2ffSAnthony Liguori 582f28d2ffSAnthony Liguori bool abstract; 592f28d2ffSAnthony Liguori 602f28d2ffSAnthony Liguori const char *parent; 612f28d2ffSAnthony Liguori TypeImpl *parent_type; 622f28d2ffSAnthony Liguori 632f28d2ffSAnthony Liguori ObjectClass *class; 642f28d2ffSAnthony Liguori 652f28d2ffSAnthony Liguori int num_interfaces; 662f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 672f28d2ffSAnthony Liguori }; 682f28d2ffSAnthony Liguori 699970bd88SPaolo Bonzini static Type type_interface; 709970bd88SPaolo Bonzini 712f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 722f28d2ffSAnthony Liguori { 732f28d2ffSAnthony Liguori static GHashTable *type_table; 742f28d2ffSAnthony Liguori 752f28d2ffSAnthony Liguori if (type_table == NULL) { 762f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 772f28d2ffSAnthony Liguori } 782f28d2ffSAnthony Liguori 792f28d2ffSAnthony Liguori return type_table; 802f28d2ffSAnthony Liguori } 812f28d2ffSAnthony Liguori 82f54c19caSHervé Poussineau static bool enumerating_types; 83f54c19caSHervé Poussineau 842f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 852f28d2ffSAnthony Liguori { 86f54c19caSHervé Poussineau assert(!enumerating_types); 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 95b061dc41SPaolo Bonzini static TypeImpl *type_new(const TypeInfo *info) 962f28d2ffSAnthony Liguori { 972f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 9833e95c63SAnthony Liguori int i; 992f28d2ffSAnthony Liguori 1002f28d2ffSAnthony Liguori g_assert(info->name != NULL); 1012f28d2ffSAnthony Liguori 10273093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 10373093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 10473093354SAnthony Liguori abort(); 10573093354SAnthony Liguori } 10673093354SAnthony Liguori 1072f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1082f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1092f28d2ffSAnthony Liguori 1102f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1112f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1122f28d2ffSAnthony Liguori 1132f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1143b50e311SPaolo Bonzini ti->class_base_init = info->class_base_init; 1152f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1162f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1172f28d2ffSAnthony Liguori 1182f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1198231c2ddSEduardo Habkost ti->instance_post_init = info->instance_post_init; 1202f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1212f28d2ffSAnthony Liguori 1222f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1232f28d2ffSAnthony Liguori 12433e95c63SAnthony Liguori for (i = 0; info->interfaces && info->interfaces[i].type; i++) { 12533e95c63SAnthony Liguori ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); 1262f28d2ffSAnthony Liguori } 12733e95c63SAnthony Liguori ti->num_interfaces = i; 1282f28d2ffSAnthony Liguori 129b061dc41SPaolo Bonzini return ti; 130b061dc41SPaolo Bonzini } 1312f28d2ffSAnthony Liguori 132b061dc41SPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info) 133b061dc41SPaolo Bonzini { 134b061dc41SPaolo Bonzini TypeImpl *ti; 135b061dc41SPaolo Bonzini ti = type_new(info); 136b061dc41SPaolo Bonzini 137b061dc41SPaolo Bonzini type_table_add(ti); 1382f28d2ffSAnthony Liguori return ti; 1392f28d2ffSAnthony Liguori } 1402f28d2ffSAnthony Liguori 141049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info) 142049cb3cfSPaolo Bonzini { 143049cb3cfSPaolo Bonzini assert(info->parent); 144049cb3cfSPaolo Bonzini return type_register_internal(info); 145049cb3cfSPaolo Bonzini } 146049cb3cfSPaolo Bonzini 1472f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1482f28d2ffSAnthony Liguori { 1492f28d2ffSAnthony Liguori return type_register(info); 1502f28d2ffSAnthony Liguori } 1512f28d2ffSAnthony Liguori 1522f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1532f28d2ffSAnthony Liguori { 1542f28d2ffSAnthony Liguori if (name == NULL) { 1552f28d2ffSAnthony Liguori return NULL; 1562f28d2ffSAnthony Liguori } 1572f28d2ffSAnthony Liguori 1582f28d2ffSAnthony Liguori return type_table_lookup(name); 1592f28d2ffSAnthony Liguori } 1602f28d2ffSAnthony Liguori 1612f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1622f28d2ffSAnthony Liguori { 1632f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1642f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1652f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1662f28d2ffSAnthony Liguori } 1672f28d2ffSAnthony Liguori 1682f28d2ffSAnthony Liguori return type->parent_type; 1692f28d2ffSAnthony Liguori } 1702f28d2ffSAnthony Liguori 1712f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1722f28d2ffSAnthony Liguori { 1732f28d2ffSAnthony Liguori return (type->parent != NULL); 1742f28d2ffSAnthony Liguori } 1752f28d2ffSAnthony Liguori 1762f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1772f28d2ffSAnthony Liguori { 1782f28d2ffSAnthony Liguori if (ti->class_size) { 1792f28d2ffSAnthony Liguori return ti->class_size; 1802f28d2ffSAnthony Liguori } 1812f28d2ffSAnthony Liguori 1822f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1832f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1842f28d2ffSAnthony Liguori } 1852f28d2ffSAnthony Liguori 1862f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1872f28d2ffSAnthony Liguori } 1882f28d2ffSAnthony Liguori 189aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 190aca59af6SIgor Mitsyanko { 191aca59af6SIgor Mitsyanko if (ti->instance_size) { 192aca59af6SIgor Mitsyanko return ti->instance_size; 193aca59af6SIgor Mitsyanko } 194aca59af6SIgor Mitsyanko 195aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 196aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 197aca59af6SIgor Mitsyanko } 198aca59af6SIgor Mitsyanko 199aca59af6SIgor Mitsyanko return 0; 200aca59af6SIgor Mitsyanko } 201aca59af6SIgor Mitsyanko 20233e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 2032f28d2ffSAnthony Liguori { 20433e95c63SAnthony Liguori assert(target_type); 2052f28d2ffSAnthony Liguori 20633e95c63SAnthony Liguori /* Check if typename is a direct ancestor of type */ 20733e95c63SAnthony Liguori while (type) { 20833e95c63SAnthony Liguori if (type == target_type) { 20933e95c63SAnthony Liguori return true; 21033e95c63SAnthony Liguori } 21133e95c63SAnthony Liguori 21233e95c63SAnthony Liguori type = type_get_parent(type); 21333e95c63SAnthony Liguori } 21433e95c63SAnthony Liguori 21533e95c63SAnthony Liguori return false; 21633e95c63SAnthony Liguori } 21733e95c63SAnthony Liguori 21833e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti); 21933e95c63SAnthony Liguori 220b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, 221b061dc41SPaolo Bonzini TypeImpl *parent_type) 22233e95c63SAnthony Liguori { 22333e95c63SAnthony Liguori InterfaceClass *new_iface; 22433e95c63SAnthony Liguori TypeInfo info = { }; 22533e95c63SAnthony Liguori TypeImpl *iface_impl; 22633e95c63SAnthony Liguori 227b061dc41SPaolo Bonzini info.parent = parent_type->name; 228b061dc41SPaolo Bonzini info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); 22933e95c63SAnthony Liguori info.abstract = true; 23033e95c63SAnthony Liguori 231b061dc41SPaolo Bonzini iface_impl = type_new(&info); 232b061dc41SPaolo Bonzini iface_impl->parent_type = parent_type; 23333e95c63SAnthony Liguori type_initialize(iface_impl); 23433e95c63SAnthony Liguori g_free((char *)info.name); 23533e95c63SAnthony Liguori 23633e95c63SAnthony Liguori new_iface = (InterfaceClass *)iface_impl->class; 23733e95c63SAnthony Liguori new_iface->concrete_class = ti->class; 238b061dc41SPaolo Bonzini new_iface->interface_type = interface_type; 23933e95c63SAnthony Liguori 24033e95c63SAnthony Liguori ti->class->interfaces = g_slist_append(ti->class->interfaces, 24133e95c63SAnthony Liguori iface_impl->class); 2422f28d2ffSAnthony Liguori } 2432f28d2ffSAnthony Liguori 244ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2452f28d2ffSAnthony Liguori { 246745549c8SPaolo Bonzini TypeImpl *parent; 2472f28d2ffSAnthony Liguori 2482f28d2ffSAnthony Liguori if (ti->class) { 2492f28d2ffSAnthony Liguori return; 2502f28d2ffSAnthony Liguori } 2512f28d2ffSAnthony Liguori 2522f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 253aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2542f28d2ffSAnthony Liguori 2552f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 2562f28d2ffSAnthony Liguori 257745549c8SPaolo Bonzini parent = type_get_parent(ti); 258745549c8SPaolo Bonzini if (parent) { 259ac451033SIgor Mitsyanko type_initialize(parent); 26033e95c63SAnthony Liguori GSList *e; 26133e95c63SAnthony Liguori int i; 2622f28d2ffSAnthony Liguori 2632f28d2ffSAnthony Liguori g_assert(parent->class_size <= ti->class_size); 264745549c8SPaolo Bonzini memcpy(ti->class, parent->class, parent->class_size); 2653e407de4SPeter Crosthwaite ti->class->interfaces = NULL; 26633e95c63SAnthony Liguori 26733e95c63SAnthony Liguori for (e = parent->class->interfaces; e; e = e->next) { 268b061dc41SPaolo Bonzini InterfaceClass *iface = e->data; 269b061dc41SPaolo Bonzini ObjectClass *klass = OBJECT_CLASS(iface); 270b061dc41SPaolo Bonzini 271b061dc41SPaolo Bonzini type_initialize_interface(ti, iface->interface_type, klass->type); 27233e95c63SAnthony Liguori } 27333e95c63SAnthony Liguori 27433e95c63SAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 27533e95c63SAnthony Liguori TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); 27633e95c63SAnthony Liguori for (e = ti->class->interfaces; e; e = e->next) { 27733e95c63SAnthony Liguori TypeImpl *target_type = OBJECT_CLASS(e->data)->type; 27833e95c63SAnthony Liguori 27933e95c63SAnthony Liguori if (type_is_ancestor(target_type, t)) { 28033e95c63SAnthony Liguori break; 28133e95c63SAnthony Liguori } 28233e95c63SAnthony Liguori } 28333e95c63SAnthony Liguori 28433e95c63SAnthony Liguori if (e) { 28533e95c63SAnthony Liguori continue; 28633e95c63SAnthony Liguori } 28733e95c63SAnthony Liguori 288b061dc41SPaolo Bonzini type_initialize_interface(ti, t, t); 28933e95c63SAnthony Liguori } 290745549c8SPaolo Bonzini } 2912f28d2ffSAnthony Liguori 292745549c8SPaolo Bonzini ti->class->type = ti; 2933b50e311SPaolo Bonzini 2943b50e311SPaolo Bonzini while (parent) { 2953b50e311SPaolo Bonzini if (parent->class_base_init) { 2963b50e311SPaolo Bonzini parent->class_base_init(ti->class, ti->class_data); 2973b50e311SPaolo Bonzini } 2983b50e311SPaolo Bonzini parent = type_get_parent(parent); 2993b50e311SPaolo Bonzini } 3002f28d2ffSAnthony Liguori 3012f28d2ffSAnthony Liguori if (ti->class_init) { 3022f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 3032f28d2ffSAnthony Liguori } 3042f28d2ffSAnthony Liguori } 3052f28d2ffSAnthony Liguori 3062f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 3072f28d2ffSAnthony Liguori { 3082f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 3092f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 3102f28d2ffSAnthony Liguori } 3112f28d2ffSAnthony Liguori 3122f28d2ffSAnthony Liguori if (ti->instance_init) { 3132f28d2ffSAnthony Liguori ti->instance_init(obj); 3142f28d2ffSAnthony Liguori } 3152f28d2ffSAnthony Liguori } 3162f28d2ffSAnthony Liguori 3178231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti) 3188231c2ddSEduardo Habkost { 3198231c2ddSEduardo Habkost if (ti->instance_post_init) { 3208231c2ddSEduardo Habkost ti->instance_post_init(obj); 3218231c2ddSEduardo Habkost } 3228231c2ddSEduardo Habkost 3238231c2ddSEduardo Habkost if (type_has_parent(ti)) { 3248231c2ddSEduardo Habkost object_post_init_with_type(obj, type_get_parent(ti)); 3258231c2ddSEduardo Habkost } 3268231c2ddSEduardo Habkost } 3278231c2ddSEduardo Habkost 3285b9237f6SAndreas Färber void object_initialize_with_type(void *data, size_t size, TypeImpl *type) 3292f28d2ffSAnthony Liguori { 3302f28d2ffSAnthony Liguori Object *obj = data; 3312f28d2ffSAnthony Liguori 3322f28d2ffSAnthony Liguori g_assert(type != NULL); 333ac451033SIgor Mitsyanko type_initialize(type); 334aca59af6SIgor Mitsyanko 335aca59af6SIgor Mitsyanko g_assert(type->instance_size >= sizeof(Object)); 3362f28d2ffSAnthony Liguori g_assert(type->abstract == false); 3375b9237f6SAndreas Färber g_assert(size >= type->instance_size); 3382f28d2ffSAnthony Liguori 3392f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 3402f28d2ffSAnthony Liguori obj->class = type->class; 341764b6312SPaolo Bonzini object_ref(obj); 34257c9fafeSAnthony Liguori QTAILQ_INIT(&obj->properties); 3432f28d2ffSAnthony Liguori object_init_with_type(obj, type); 3448231c2ddSEduardo Habkost object_post_init_with_type(obj, type); 3452f28d2ffSAnthony Liguori } 3462f28d2ffSAnthony Liguori 347213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename) 3482f28d2ffSAnthony Liguori { 3492f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 3502f28d2ffSAnthony Liguori 3515b9237f6SAndreas Färber object_initialize_with_type(data, size, type); 3522f28d2ffSAnthony Liguori } 3532f28d2ffSAnthony Liguori 3545d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop) 3555d9d3f47SAndreas Färber { 3565d9d3f47SAndreas Färber return strstart(prop->type, "child<", NULL); 3575d9d3f47SAndreas Färber } 3585d9d3f47SAndreas Färber 35957c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 36057c9fafeSAnthony Liguori { 36157c9fafeSAnthony Liguori while (!QTAILQ_EMPTY(&obj->properties)) { 36257c9fafeSAnthony Liguori ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); 36357c9fafeSAnthony Liguori 36457c9fafeSAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 36557c9fafeSAnthony Liguori 36657c9fafeSAnthony Liguori if (prop->release) { 36757c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 36857c9fafeSAnthony Liguori } 36957c9fafeSAnthony Liguori 37057c9fafeSAnthony Liguori g_free(prop->name); 37157c9fafeSAnthony Liguori g_free(prop->type); 37257c9fafeSAnthony Liguori g_free(prop); 37357c9fafeSAnthony Liguori } 37457c9fafeSAnthony Liguori } 37557c9fafeSAnthony Liguori 37657c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 37757c9fafeSAnthony Liguori { 37857c9fafeSAnthony Liguori ObjectProperty *prop; 37957c9fafeSAnthony Liguori 38057c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 3815d9d3f47SAndreas Färber if (object_property_is_child(prop) && prop->opaque == child) { 38257c9fafeSAnthony Liguori object_property_del(obj, prop->name, errp); 3836c1fdcf9SPaolo Bonzini break; 38457c9fafeSAnthony Liguori } 38557c9fafeSAnthony Liguori } 38657c9fafeSAnthony Liguori } 38757c9fafeSAnthony Liguori 38857c9fafeSAnthony Liguori void object_unparent(Object *obj) 38957c9fafeSAnthony Liguori { 390e998fa8dSMichael S. Tsirkin if (obj->parent) { 391e998fa8dSMichael S. Tsirkin object_property_del_child(obj->parent, obj, NULL); 392e998fa8dSMichael S. Tsirkin } 39357c9fafeSAnthony Liguori } 39457c9fafeSAnthony Liguori 3952f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 3962f28d2ffSAnthony Liguori { 3972f28d2ffSAnthony Liguori if (type->instance_finalize) { 3982f28d2ffSAnthony Liguori type->instance_finalize(obj); 3992f28d2ffSAnthony Liguori } 4002f28d2ffSAnthony Liguori 4012f28d2ffSAnthony Liguori if (type_has_parent(type)) { 4022f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 4032f28d2ffSAnthony Liguori } 4042f28d2ffSAnthony Liguori } 4052f28d2ffSAnthony Liguori 406339c2708SPaolo Bonzini static void object_finalize(void *data) 4072f28d2ffSAnthony Liguori { 4082f28d2ffSAnthony Liguori Object *obj = data; 4092f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 4102f28d2ffSAnthony Liguori 41157c9fafeSAnthony Liguori object_property_del_all(obj); 41276a6e1ccSPaolo Bonzini object_deinit(obj, ti); 413db85b575SAnthony Liguori 414db85b575SAnthony Liguori g_assert(obj->ref == 0); 415fde9bf44SPaolo Bonzini if (obj->free) { 416fde9bf44SPaolo Bonzini obj->free(obj); 417fde9bf44SPaolo Bonzini } 4182f28d2ffSAnthony Liguori } 4192f28d2ffSAnthony Liguori 4202f28d2ffSAnthony Liguori Object *object_new_with_type(Type type) 4212f28d2ffSAnthony Liguori { 4222f28d2ffSAnthony Liguori Object *obj; 4232f28d2ffSAnthony Liguori 4242f28d2ffSAnthony Liguori g_assert(type != NULL); 425ac451033SIgor Mitsyanko type_initialize(type); 4262f28d2ffSAnthony Liguori 4272f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 4285b9237f6SAndreas Färber object_initialize_with_type(obj, type->instance_size, type); 429fde9bf44SPaolo Bonzini obj->free = g_free; 4302f28d2ffSAnthony Liguori 4312f28d2ffSAnthony Liguori return obj; 4322f28d2ffSAnthony Liguori } 4332f28d2ffSAnthony Liguori 4342f28d2ffSAnthony Liguori Object *object_new(const char *typename) 4352f28d2ffSAnthony Liguori { 4362f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 4372f28d2ffSAnthony Liguori 4382f28d2ffSAnthony Liguori return object_new_with_type(ti); 4392f28d2ffSAnthony Liguori } 4402f28d2ffSAnthony Liguori 4412f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 4422f28d2ffSAnthony Liguori { 443b7f43fe4SPaolo Bonzini if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { 444acc4af3fSPaolo Bonzini return obj; 445acc4af3fSPaolo Bonzini } 446acc4af3fSPaolo Bonzini 4472f28d2ffSAnthony Liguori return NULL; 4482f28d2ffSAnthony Liguori } 4492f28d2ffSAnthony Liguori 450be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename, 451be17f18bSPaolo Bonzini const char *file, int line, const char *func) 4522f28d2ffSAnthony Liguori { 453fa131d94SPaolo Bonzini trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", 454fa131d94SPaolo Bonzini typename, file, line, func); 455fa131d94SPaolo Bonzini 4563556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG 45703587328SAnthony Liguori int i; 45803587328SAnthony Liguori Object *inst; 45903587328SAnthony Liguori 46095916abcSPeter Crosthwaite for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { 4610ab4c94cSPeter Crosthwaite if (obj->class->object_cast_cache[i] == typename) { 46203587328SAnthony Liguori goto out; 46303587328SAnthony Liguori } 46403587328SAnthony Liguori } 46503587328SAnthony Liguori 46603587328SAnthony Liguori inst = object_dynamic_cast(obj, typename); 4672f28d2ffSAnthony Liguori 468b7f43fe4SPaolo Bonzini if (!inst && obj) { 469be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 470be17f18bSPaolo Bonzini file, line, func, obj, typename); 4712f28d2ffSAnthony Liguori abort(); 4722f28d2ffSAnthony Liguori } 4732f28d2ffSAnthony Liguori 4743556c233SPaolo Bonzini assert(obj == inst); 47503587328SAnthony Liguori 47695916abcSPeter Crosthwaite if (obj && obj == inst) { 47703587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 4780ab4c94cSPeter Crosthwaite obj->class->object_cast_cache[i - 1] = 4790ab4c94cSPeter Crosthwaite obj->class->object_cast_cache[i]; 48003587328SAnthony Liguori } 4810ab4c94cSPeter Crosthwaite obj->class->object_cast_cache[i - 1] = typename; 48203587328SAnthony Liguori } 48303587328SAnthony Liguori 48403587328SAnthony Liguori out: 4853556c233SPaolo Bonzini #endif 4863556c233SPaolo Bonzini return obj; 4872f28d2ffSAnthony Liguori } 4882f28d2ffSAnthony Liguori 4892f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 4902f28d2ffSAnthony Liguori const char *typename) 4912f28d2ffSAnthony Liguori { 49233e95c63SAnthony Liguori ObjectClass *ret = NULL; 493bf0fda34SPaolo Bonzini TypeImpl *target_type; 494bf0fda34SPaolo Bonzini TypeImpl *type; 4952f28d2ffSAnthony Liguori 496bf0fda34SPaolo Bonzini if (!class) { 497bf0fda34SPaolo Bonzini return NULL; 498bf0fda34SPaolo Bonzini } 499bf0fda34SPaolo Bonzini 500793c96b5SPaolo Bonzini /* A simple fast path that can trigger a lot for leaf classes. */ 501bf0fda34SPaolo Bonzini type = class->type; 502793c96b5SPaolo Bonzini if (type->name == typename) { 503793c96b5SPaolo Bonzini return class; 504793c96b5SPaolo Bonzini } 505793c96b5SPaolo Bonzini 506bf0fda34SPaolo Bonzini target_type = type_get_by_name(typename); 5079ab880b3SAlexander Graf if (!target_type) { 5089ab880b3SAlexander Graf /* target class type unknown, so fail the cast */ 5099ab880b3SAlexander Graf return NULL; 5109ab880b3SAlexander Graf } 5119ab880b3SAlexander Graf 51200e2ceaeSPeter Crosthwaite if (type->class->interfaces && 51300e2ceaeSPeter Crosthwaite type_is_ancestor(target_type, type_interface)) { 51433e95c63SAnthony Liguori int found = 0; 51533e95c63SAnthony Liguori GSList *i; 51633e95c63SAnthony Liguori 51733e95c63SAnthony Liguori for (i = class->interfaces; i; i = i->next) { 51833e95c63SAnthony Liguori ObjectClass *target_class = i->data; 51933e95c63SAnthony Liguori 52033e95c63SAnthony Liguori if (type_is_ancestor(target_class->type, target_type)) { 52133e95c63SAnthony Liguori ret = target_class; 52233e95c63SAnthony Liguori found++; 52333e95c63SAnthony Liguori } 5242f28d2ffSAnthony Liguori } 5252f28d2ffSAnthony Liguori 52633e95c63SAnthony Liguori /* The match was ambiguous, don't allow a cast */ 52733e95c63SAnthony Liguori if (found > 1) { 52833e95c63SAnthony Liguori ret = NULL; 52933e95c63SAnthony Liguori } 53033e95c63SAnthony Liguori } else if (type_is_ancestor(type, target_type)) { 53133e95c63SAnthony Liguori ret = class; 5322f28d2ffSAnthony Liguori } 5332f28d2ffSAnthony Liguori 53433e95c63SAnthony Liguori return ret; 5352f28d2ffSAnthony Liguori } 5362f28d2ffSAnthony Liguori 5372f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 538be17f18bSPaolo Bonzini const char *typename, 539be17f18bSPaolo Bonzini const char *file, int line, 540be17f18bSPaolo Bonzini const char *func) 5412f28d2ffSAnthony Liguori { 542fa131d94SPaolo Bonzini ObjectClass *ret; 5432f28d2ffSAnthony Liguori 544fa131d94SPaolo Bonzini trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", 545fa131d94SPaolo Bonzini typename, file, line, func); 546fa131d94SPaolo Bonzini 54703587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 54803587328SAnthony Liguori int i; 54903587328SAnthony Liguori 5509d6a3d58SPeter Crosthwaite for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { 5510ab4c94cSPeter Crosthwaite if (class->class_cast_cache[i] == typename) { 55203587328SAnthony Liguori ret = class; 55303587328SAnthony Liguori goto out; 55403587328SAnthony Liguori } 55503587328SAnthony Liguori } 55603587328SAnthony Liguori #else 5579d6a3d58SPeter Crosthwaite if (!class || !class->interfaces) { 5583556c233SPaolo Bonzini return class; 5593556c233SPaolo Bonzini } 5603556c233SPaolo Bonzini #endif 5613556c233SPaolo Bonzini 562fa131d94SPaolo Bonzini ret = object_class_dynamic_cast(class, typename); 563bf0fda34SPaolo Bonzini if (!ret && class) { 564be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 565be17f18bSPaolo Bonzini file, line, func, class, typename); 5662f28d2ffSAnthony Liguori abort(); 5672f28d2ffSAnthony Liguori } 5682f28d2ffSAnthony Liguori 56903587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 5709d6a3d58SPeter Crosthwaite if (class && ret == class) { 57103587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 5720ab4c94cSPeter Crosthwaite class->class_cast_cache[i - 1] = class->class_cast_cache[i]; 57303587328SAnthony Liguori } 5740ab4c94cSPeter Crosthwaite class->class_cast_cache[i - 1] = typename; 57503587328SAnthony Liguori } 57603587328SAnthony Liguori out: 57703587328SAnthony Liguori #endif 5782f28d2ffSAnthony Liguori return ret; 5792f28d2ffSAnthony Liguori } 5802f28d2ffSAnthony Liguori 5812f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj) 5822f28d2ffSAnthony Liguori { 5832f28d2ffSAnthony Liguori return obj->class->type->name; 5842f28d2ffSAnthony Liguori } 5852f28d2ffSAnthony Liguori 5862f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 5872f28d2ffSAnthony Liguori { 5882f28d2ffSAnthony Liguori return obj->class; 5892f28d2ffSAnthony Liguori } 5902f28d2ffSAnthony Liguori 59117862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass) 59217862378SAndreas Färber { 59317862378SAndreas Färber return klass->type->abstract; 59417862378SAndreas Färber } 59517862378SAndreas Färber 5962f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 5972f28d2ffSAnthony Liguori { 5982f28d2ffSAnthony Liguori return klass->type->name; 5992f28d2ffSAnthony Liguori } 6002f28d2ffSAnthony Liguori 6012f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 6022f28d2ffSAnthony Liguori { 6032f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 6042f28d2ffSAnthony Liguori 6052f28d2ffSAnthony Liguori if (!type) { 6062f28d2ffSAnthony Liguori return NULL; 6072f28d2ffSAnthony Liguori } 6082f28d2ffSAnthony Liguori 609ac451033SIgor Mitsyanko type_initialize(type); 6102f28d2ffSAnthony Liguori 6112f28d2ffSAnthony Liguori return type->class; 6122f28d2ffSAnthony Liguori } 6132f28d2ffSAnthony Liguori 614e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class) 615e7cce67fSPaolo Bonzini { 616e7cce67fSPaolo Bonzini TypeImpl *type = type_get_parent(class->type); 617e7cce67fSPaolo Bonzini 618e7cce67fSPaolo Bonzini if (!type) { 619e7cce67fSPaolo Bonzini return NULL; 620e7cce67fSPaolo Bonzini } 621e7cce67fSPaolo Bonzini 622e7cce67fSPaolo Bonzini type_initialize(type); 623e7cce67fSPaolo Bonzini 624e7cce67fSPaolo Bonzini return type->class; 625e7cce67fSPaolo Bonzini } 626e7cce67fSPaolo Bonzini 6272f28d2ffSAnthony Liguori typedef struct OCFData 6282f28d2ffSAnthony Liguori { 6292f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 63093c511a1SAnthony Liguori const char *implements_type; 63193c511a1SAnthony Liguori bool include_abstract; 6322f28d2ffSAnthony Liguori void *opaque; 6332f28d2ffSAnthony Liguori } OCFData; 6342f28d2ffSAnthony Liguori 6352f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 6362f28d2ffSAnthony Liguori gpointer opaque) 6372f28d2ffSAnthony Liguori { 6382f28d2ffSAnthony Liguori OCFData *data = opaque; 6392f28d2ffSAnthony Liguori TypeImpl *type = value; 64093c511a1SAnthony Liguori ObjectClass *k; 6412f28d2ffSAnthony Liguori 642ac451033SIgor Mitsyanko type_initialize(type); 64393c511a1SAnthony Liguori k = type->class; 6442f28d2ffSAnthony Liguori 64593c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 64693c511a1SAnthony Liguori return; 64793c511a1SAnthony Liguori } 64893c511a1SAnthony Liguori 64993c511a1SAnthony Liguori if (data->implements_type && 65093c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 65193c511a1SAnthony Liguori return; 65293c511a1SAnthony Liguori } 65393c511a1SAnthony Liguori 65493c511a1SAnthony Liguori data->fn(k, data->opaque); 6552f28d2ffSAnthony Liguori } 6562f28d2ffSAnthony Liguori 6572f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 65893c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 6592f28d2ffSAnthony Liguori void *opaque) 6602f28d2ffSAnthony Liguori { 66193c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 6622f28d2ffSAnthony Liguori 663f54c19caSHervé Poussineau enumerating_types = true; 6642f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 665f54c19caSHervé Poussineau enumerating_types = false; 6662f28d2ffSAnthony Liguori } 66757c9fafeSAnthony Liguori 66832efc535SPaolo Bonzini int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), 66932efc535SPaolo Bonzini void *opaque) 67032efc535SPaolo Bonzini { 6718af734caSAlexey Kardashevskiy ObjectProperty *prop, *next; 67232efc535SPaolo Bonzini int ret = 0; 67332efc535SPaolo Bonzini 6748af734caSAlexey Kardashevskiy QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) { 67532efc535SPaolo Bonzini if (object_property_is_child(prop)) { 67632efc535SPaolo Bonzini ret = fn(prop->opaque, opaque); 67732efc535SPaolo Bonzini if (ret != 0) { 67832efc535SPaolo Bonzini break; 67932efc535SPaolo Bonzini } 68032efc535SPaolo Bonzini } 68132efc535SPaolo Bonzini } 68232efc535SPaolo Bonzini return ret; 68332efc535SPaolo Bonzini } 68432efc535SPaolo Bonzini 685418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 686418ba9e5SAndreas Färber { 687418ba9e5SAndreas Färber GSList **list = opaque; 688418ba9e5SAndreas Färber 689418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 690418ba9e5SAndreas Färber } 691418ba9e5SAndreas Färber 692418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 693418ba9e5SAndreas Färber bool include_abstract) 694418ba9e5SAndreas Färber { 695418ba9e5SAndreas Färber GSList *list = NULL; 696418ba9e5SAndreas Färber 697418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 698418ba9e5SAndreas Färber implements_type, include_abstract, &list); 699418ba9e5SAndreas Färber return list; 700418ba9e5SAndreas Färber } 701418ba9e5SAndreas Färber 70257c9fafeSAnthony Liguori void object_ref(Object *obj) 70357c9fafeSAnthony Liguori { 7048ffad850SPeter Crosthwaite if (!obj) { 7058ffad850SPeter Crosthwaite return; 7068ffad850SPeter Crosthwaite } 707f08c03f3SJan Kiszka atomic_inc(&obj->ref); 70857c9fafeSAnthony Liguori } 70957c9fafeSAnthony Liguori 71057c9fafeSAnthony Liguori void object_unref(Object *obj) 71157c9fafeSAnthony Liguori { 7128ffad850SPeter Crosthwaite if (!obj) { 7138ffad850SPeter Crosthwaite return; 7148ffad850SPeter Crosthwaite } 71557c9fafeSAnthony Liguori g_assert(obj->ref > 0); 71657c9fafeSAnthony Liguori 71757c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 718f08c03f3SJan Kiszka if (atomic_fetch_dec(&obj->ref) == 1) { 71957c9fafeSAnthony Liguori object_finalize(obj); 72057c9fafeSAnthony Liguori } 72157c9fafeSAnthony Liguori } 72257c9fafeSAnthony Liguori 72364607d08SPaolo Bonzini ObjectProperty * 72464607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type, 72557c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 72657c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 72757c9fafeSAnthony Liguori ObjectPropertyRelease *release, 72857c9fafeSAnthony Liguori void *opaque, Error **errp) 72957c9fafeSAnthony Liguori { 73054852b03SPeter Maydell ObjectProperty *prop; 73133965904SPeter Crosthwaite size_t name_len = strlen(name); 73233965904SPeter Crosthwaite 73333965904SPeter Crosthwaite if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { 73433965904SPeter Crosthwaite int i; 73533965904SPeter Crosthwaite ObjectProperty *ret; 73633965904SPeter Crosthwaite char *name_no_array = g_strdup(name); 73733965904SPeter Crosthwaite 73833965904SPeter Crosthwaite name_no_array[name_len - 3] = '\0'; 73933965904SPeter Crosthwaite for (i = 0; ; ++i) { 74033965904SPeter Crosthwaite char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); 74133965904SPeter Crosthwaite 74233965904SPeter Crosthwaite ret = object_property_add(obj, full_name, type, get, set, 74333965904SPeter Crosthwaite release, opaque, NULL); 74433965904SPeter Crosthwaite g_free(full_name); 74533965904SPeter Crosthwaite if (ret) { 74633965904SPeter Crosthwaite break; 74733965904SPeter Crosthwaite } 74833965904SPeter Crosthwaite } 74933965904SPeter Crosthwaite g_free(name_no_array); 75033965904SPeter Crosthwaite return ret; 75133965904SPeter Crosthwaite } 75254852b03SPeter Maydell 75354852b03SPeter Maydell QTAILQ_FOREACH(prop, &obj->properties, node) { 75454852b03SPeter Maydell if (strcmp(prop->name, name) == 0) { 75554852b03SPeter Maydell error_setg(errp, "attempt to add duplicate property '%s'" 75654852b03SPeter Maydell " to object (type '%s')", name, 75754852b03SPeter Maydell object_get_typename(obj)); 75864607d08SPaolo Bonzini return NULL; 75954852b03SPeter Maydell } 76054852b03SPeter Maydell } 76154852b03SPeter Maydell 76254852b03SPeter Maydell prop = g_malloc0(sizeof(*prop)); 76357c9fafeSAnthony Liguori 76457c9fafeSAnthony Liguori prop->name = g_strdup(name); 76557c9fafeSAnthony Liguori prop->type = g_strdup(type); 76657c9fafeSAnthony Liguori 76757c9fafeSAnthony Liguori prop->get = get; 76857c9fafeSAnthony Liguori prop->set = set; 76957c9fafeSAnthony Liguori prop->release = release; 77057c9fafeSAnthony Liguori prop->opaque = opaque; 77157c9fafeSAnthony Liguori 77257c9fafeSAnthony Liguori QTAILQ_INSERT_TAIL(&obj->properties, prop, node); 77364607d08SPaolo Bonzini return prop; 77457c9fafeSAnthony Liguori } 77557c9fafeSAnthony Liguori 77689bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name, 77789bfe000SPaolo Bonzini Error **errp) 77857c9fafeSAnthony Liguori { 77957c9fafeSAnthony Liguori ObjectProperty *prop; 78057c9fafeSAnthony Liguori 78157c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 78257c9fafeSAnthony Liguori if (strcmp(prop->name, name) == 0) { 78357c9fafeSAnthony Liguori return prop; 78457c9fafeSAnthony Liguori } 78557c9fafeSAnthony Liguori } 78657c9fafeSAnthony Liguori 787f231b88dSCole Robinson error_setg(errp, "Property '.%s' not found", name); 78857c9fafeSAnthony Liguori return NULL; 78957c9fafeSAnthony Liguori } 79057c9fafeSAnthony Liguori 79157c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 79257c9fafeSAnthony Liguori { 79389bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 7940866aca1SAnthony Liguori if (prop == NULL) { 7950866aca1SAnthony Liguori return; 7960866aca1SAnthony Liguori } 79757c9fafeSAnthony Liguori 7980866aca1SAnthony Liguori if (prop->release) { 7990866aca1SAnthony Liguori prop->release(obj, name, prop->opaque); 8000866aca1SAnthony Liguori } 8010866aca1SAnthony Liguori 8020866aca1SAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 80357c9fafeSAnthony Liguori 80457c9fafeSAnthony Liguori g_free(prop->name); 80557c9fafeSAnthony Liguori g_free(prop->type); 80657c9fafeSAnthony Liguori g_free(prop); 80757c9fafeSAnthony Liguori } 80857c9fafeSAnthony Liguori 80957c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 81057c9fafeSAnthony Liguori Error **errp) 81157c9fafeSAnthony Liguori { 81289bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 81357c9fafeSAnthony Liguori if (prop == NULL) { 81457c9fafeSAnthony Liguori return; 81557c9fafeSAnthony Liguori } 81657c9fafeSAnthony Liguori 81757c9fafeSAnthony Liguori if (!prop->get) { 81857c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 81957c9fafeSAnthony Liguori } else { 82057c9fafeSAnthony Liguori prop->get(obj, v, prop->opaque, name, errp); 82157c9fafeSAnthony Liguori } 82257c9fafeSAnthony Liguori } 82357c9fafeSAnthony Liguori 82457c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 82557c9fafeSAnthony Liguori Error **errp) 82657c9fafeSAnthony Liguori { 82789bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 82857c9fafeSAnthony Liguori if (prop == NULL) { 82957c9fafeSAnthony Liguori return; 83057c9fafeSAnthony Liguori } 83157c9fafeSAnthony Liguori 83257c9fafeSAnthony Liguori if (!prop->set) { 83357c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 83457c9fafeSAnthony Liguori } else { 83557c9fafeSAnthony Liguori prop->set(obj, v, prop->opaque, name, errp); 83657c9fafeSAnthony Liguori } 83757c9fafeSAnthony Liguori } 83857c9fafeSAnthony Liguori 8397b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 8407b7b7d18SPaolo Bonzini const char *name, Error **errp) 8417b7b7d18SPaolo Bonzini { 8427b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 8437b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 8447b7b7d18SPaolo Bonzini 8457b7b7d18SPaolo Bonzini QDECREF(qstr); 8467b7b7d18SPaolo Bonzini } 8477b7b7d18SPaolo Bonzini 8487b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 8497b7b7d18SPaolo Bonzini Error **errp) 8507b7b7d18SPaolo Bonzini { 8517b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 8527b7b7d18SPaolo Bonzini QString *qstring; 8537b7b7d18SPaolo Bonzini char *retval; 8547b7b7d18SPaolo Bonzini 8557b7b7d18SPaolo Bonzini if (!ret) { 8567b7b7d18SPaolo Bonzini return NULL; 8577b7b7d18SPaolo Bonzini } 8587b7b7d18SPaolo Bonzini qstring = qobject_to_qstring(ret); 8597b7b7d18SPaolo Bonzini if (!qstring) { 8607b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 8617b7b7d18SPaolo Bonzini retval = NULL; 8627b7b7d18SPaolo Bonzini } else { 8637b7b7d18SPaolo Bonzini retval = g_strdup(qstring_get_str(qstring)); 8647b7b7d18SPaolo Bonzini } 8657b7b7d18SPaolo Bonzini 8667b7b7d18SPaolo Bonzini QDECREF(qstring); 8677b7b7d18SPaolo Bonzini return retval; 8687b7b7d18SPaolo Bonzini } 8697b7b7d18SPaolo Bonzini 8701d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 8711d9c5a12SPaolo Bonzini const char *name, Error **errp) 8721d9c5a12SPaolo Bonzini { 8732d3aa28cSVlad Yasevich gchar *path = object_get_canonical_path(value); 8742d3aa28cSVlad Yasevich object_property_set_str(obj, path, name, errp); 8752d3aa28cSVlad Yasevich g_free(path); 8761d9c5a12SPaolo Bonzini } 8771d9c5a12SPaolo Bonzini 8781d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 8791d9c5a12SPaolo Bonzini Error **errp) 8801d9c5a12SPaolo Bonzini { 8811d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 8821d9c5a12SPaolo Bonzini Object *target = NULL; 8831d9c5a12SPaolo Bonzini 8841d9c5a12SPaolo Bonzini if (str && *str) { 8851d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 8861d9c5a12SPaolo Bonzini if (!target) { 8871d9c5a12SPaolo Bonzini error_set(errp, QERR_DEVICE_NOT_FOUND, str); 8881d9c5a12SPaolo Bonzini } 8891d9c5a12SPaolo Bonzini } 8901d9c5a12SPaolo Bonzini 8911d9c5a12SPaolo Bonzini g_free(str); 8921d9c5a12SPaolo Bonzini return target; 8931d9c5a12SPaolo Bonzini } 8941d9c5a12SPaolo Bonzini 8957b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 8967b7b7d18SPaolo Bonzini const char *name, Error **errp) 8977b7b7d18SPaolo Bonzini { 8987b7b7d18SPaolo Bonzini QBool *qbool = qbool_from_int(value); 8997b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 9007b7b7d18SPaolo Bonzini 9017b7b7d18SPaolo Bonzini QDECREF(qbool); 9027b7b7d18SPaolo Bonzini } 9037b7b7d18SPaolo Bonzini 9047b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 9057b7b7d18SPaolo Bonzini Error **errp) 9067b7b7d18SPaolo Bonzini { 9077b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 9087b7b7d18SPaolo Bonzini QBool *qbool; 9097b7b7d18SPaolo Bonzini bool retval; 9107b7b7d18SPaolo Bonzini 9117b7b7d18SPaolo Bonzini if (!ret) { 9127b7b7d18SPaolo Bonzini return false; 9137b7b7d18SPaolo Bonzini } 9147b7b7d18SPaolo Bonzini qbool = qobject_to_qbool(ret); 9157b7b7d18SPaolo Bonzini if (!qbool) { 9167b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 9177b7b7d18SPaolo Bonzini retval = false; 9187b7b7d18SPaolo Bonzini } else { 9197b7b7d18SPaolo Bonzini retval = qbool_get_int(qbool); 9207b7b7d18SPaolo Bonzini } 9217b7b7d18SPaolo Bonzini 9227b7b7d18SPaolo Bonzini QDECREF(qbool); 9237b7b7d18SPaolo Bonzini return retval; 9247b7b7d18SPaolo Bonzini } 9257b7b7d18SPaolo Bonzini 9267b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 9277b7b7d18SPaolo Bonzini const char *name, Error **errp) 9287b7b7d18SPaolo Bonzini { 9297b7b7d18SPaolo Bonzini QInt *qint = qint_from_int(value); 9307b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qint), name, errp); 9317b7b7d18SPaolo Bonzini 9327b7b7d18SPaolo Bonzini QDECREF(qint); 9337b7b7d18SPaolo Bonzini } 9347b7b7d18SPaolo Bonzini 9357b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 9367b7b7d18SPaolo Bonzini Error **errp) 9377b7b7d18SPaolo Bonzini { 9387b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 9397b7b7d18SPaolo Bonzini QInt *qint; 9407b7b7d18SPaolo Bonzini int64_t retval; 9417b7b7d18SPaolo Bonzini 9427b7b7d18SPaolo Bonzini if (!ret) { 9437b7b7d18SPaolo Bonzini return -1; 9447b7b7d18SPaolo Bonzini } 9457b7b7d18SPaolo Bonzini qint = qobject_to_qint(ret); 9467b7b7d18SPaolo Bonzini if (!qint) { 9477b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 9487b7b7d18SPaolo Bonzini retval = -1; 9497b7b7d18SPaolo Bonzini } else { 9507b7b7d18SPaolo Bonzini retval = qint_get_int(qint); 9517b7b7d18SPaolo Bonzini } 9527b7b7d18SPaolo Bonzini 9537b7b7d18SPaolo Bonzini QDECREF(qint); 9547b7b7d18SPaolo Bonzini return retval; 9557b7b7d18SPaolo Bonzini } 9567b7b7d18SPaolo Bonzini 9571f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name, 9581f21772dSHu Tao const char *strings[], Error **errp) 9591f21772dSHu Tao { 9601f21772dSHu Tao StringOutputVisitor *sov; 9611f21772dSHu Tao StringInputVisitor *siv; 962976620acSChen Fan char *str; 9631f21772dSHu Tao int ret; 9641f21772dSHu Tao 9651f21772dSHu Tao sov = string_output_visitor_new(false); 9661f21772dSHu Tao object_property_get(obj, string_output_get_visitor(sov), name, errp); 967976620acSChen Fan str = string_output_get_string(sov); 968976620acSChen Fan siv = string_input_visitor_new(str); 9691f21772dSHu Tao string_output_visitor_cleanup(sov); 9701f21772dSHu Tao visit_type_enum(string_input_get_visitor(siv), 9711f21772dSHu Tao &ret, strings, NULL, name, errp); 972976620acSChen Fan 973976620acSChen Fan g_free(str); 9741f21772dSHu Tao string_input_visitor_cleanup(siv); 9751f21772dSHu Tao 9761f21772dSHu Tao return ret; 9771f21772dSHu Tao } 9781f21772dSHu Tao 9791f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name, 9801f21772dSHu Tao uint16List **list, Error **errp) 9811f21772dSHu Tao { 9821f21772dSHu Tao StringOutputVisitor *ov; 9831f21772dSHu Tao StringInputVisitor *iv; 984976620acSChen Fan char *str; 9851f21772dSHu Tao 9861f21772dSHu Tao ov = string_output_visitor_new(false); 9871f21772dSHu Tao object_property_get(obj, string_output_get_visitor(ov), 9881f21772dSHu Tao name, errp); 989976620acSChen Fan str = string_output_get_string(ov); 990976620acSChen Fan iv = string_input_visitor_new(str); 9911f21772dSHu Tao visit_type_uint16List(string_input_get_visitor(iv), 9921f21772dSHu Tao list, NULL, errp); 993976620acSChen Fan 994976620acSChen Fan g_free(str); 9951f21772dSHu Tao string_output_visitor_cleanup(ov); 9961f21772dSHu Tao string_input_visitor_cleanup(iv); 9971f21772dSHu Tao } 9981f21772dSHu Tao 999b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 1000b2cd7deeSPaolo Bonzini const char *name, Error **errp) 1001b2cd7deeSPaolo Bonzini { 1002b2cd7deeSPaolo Bonzini StringInputVisitor *mi; 1003b2cd7deeSPaolo Bonzini mi = string_input_visitor_new(string); 1004b2cd7deeSPaolo Bonzini object_property_set(obj, string_input_get_visitor(mi), name, errp); 1005b2cd7deeSPaolo Bonzini 1006b2cd7deeSPaolo Bonzini string_input_visitor_cleanup(mi); 1007b2cd7deeSPaolo Bonzini } 1008b2cd7deeSPaolo Bonzini 10090b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human, 1010b2cd7deeSPaolo Bonzini Error **errp) 1011b2cd7deeSPaolo Bonzini { 1012b2cd7deeSPaolo Bonzini StringOutputVisitor *mo; 10133a53009fSGonglei char *string = NULL; 10143a53009fSGonglei Error *local_err = NULL; 1015b2cd7deeSPaolo Bonzini 10160b7593e0SPaolo Bonzini mo = string_output_visitor_new(human); 10173a53009fSGonglei object_property_get(obj, string_output_get_visitor(mo), name, &local_err); 10183a53009fSGonglei if (local_err) { 10193a53009fSGonglei error_propagate(errp, local_err); 10203a53009fSGonglei goto out; 10213a53009fSGonglei } 10223a53009fSGonglei 1023b2cd7deeSPaolo Bonzini string = string_output_get_string(mo); 10243a53009fSGonglei 10253a53009fSGonglei out: 1026b2cd7deeSPaolo Bonzini string_output_visitor_cleanup(mo); 1027b2cd7deeSPaolo Bonzini return string; 1028b2cd7deeSPaolo Bonzini } 1029b2cd7deeSPaolo Bonzini 103057c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 103157c9fafeSAnthony Liguori { 103289bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 103357c9fafeSAnthony Liguori if (prop == NULL) { 103457c9fafeSAnthony Liguori return NULL; 103557c9fafeSAnthony Liguori } 103657c9fafeSAnthony Liguori 103757c9fafeSAnthony Liguori return prop->type; 103857c9fafeSAnthony Liguori } 103957c9fafeSAnthony Liguori 104057c9fafeSAnthony Liguori Object *object_get_root(void) 104157c9fafeSAnthony Liguori { 10428b45d447SAnthony Liguori static Object *root; 104357c9fafeSAnthony Liguori 10448b45d447SAnthony Liguori if (!root) { 10458b45d447SAnthony Liguori root = object_new("container"); 104657c9fafeSAnthony Liguori } 104757c9fafeSAnthony Liguori 10488b45d447SAnthony Liguori return root; 104957c9fafeSAnthony Liguori } 105057c9fafeSAnthony Liguori 105157c9fafeSAnthony Liguori static void object_get_child_property(Object *obj, Visitor *v, void *opaque, 105257c9fafeSAnthony Liguori const char *name, Error **errp) 105357c9fafeSAnthony Liguori { 105457c9fafeSAnthony Liguori Object *child = opaque; 105557c9fafeSAnthony Liguori gchar *path; 105657c9fafeSAnthony Liguori 105757c9fafeSAnthony Liguori path = object_get_canonical_path(child); 105857c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 105957c9fafeSAnthony Liguori g_free(path); 106057c9fafeSAnthony Liguori } 106157c9fafeSAnthony Liguori 106264607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) 106364607d08SPaolo Bonzini { 106464607d08SPaolo Bonzini return opaque; 106564607d08SPaolo Bonzini } 106664607d08SPaolo Bonzini 1067db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 1068db85b575SAnthony Liguori void *opaque) 1069db85b575SAnthony Liguori { 1070db85b575SAnthony Liguori Object *child = opaque; 1071db85b575SAnthony Liguori 1072bffc687dSPaolo Bonzini if (child->class->unparent) { 1073bffc687dSPaolo Bonzini (child->class->unparent)(child); 1074bffc687dSPaolo Bonzini } 1075bffc687dSPaolo Bonzini child->parent = NULL; 1076db85b575SAnthony Liguori object_unref(child); 1077db85b575SAnthony Liguori } 1078db85b575SAnthony Liguori 107957c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 108057c9fafeSAnthony Liguori Object *child, Error **errp) 108157c9fafeSAnthony Liguori { 1082b0ed5e9fSPaolo Bonzini Error *local_err = NULL; 108357c9fafeSAnthony Liguori gchar *type; 108464607d08SPaolo Bonzini ObjectProperty *op; 108557c9fafeSAnthony Liguori 108657c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 108757c9fafeSAnthony Liguori 108864607d08SPaolo Bonzini op = object_property_add(obj, name, type, object_get_child_property, NULL, 1089b0ed5e9fSPaolo Bonzini object_finalize_child_property, child, &local_err); 1090b0ed5e9fSPaolo Bonzini if (local_err) { 1091b0ed5e9fSPaolo Bonzini error_propagate(errp, local_err); 1092b0ed5e9fSPaolo Bonzini goto out; 1093b0ed5e9fSPaolo Bonzini } 109464607d08SPaolo Bonzini 109564607d08SPaolo Bonzini op->resolve = object_resolve_child_property; 109657c9fafeSAnthony Liguori object_ref(child); 109757c9fafeSAnthony Liguori g_assert(child->parent == NULL); 109857c9fafeSAnthony Liguori child->parent = obj; 109957c9fafeSAnthony Liguori 1100b0ed5e9fSPaolo Bonzini out: 110157c9fafeSAnthony Liguori g_free(type); 110257c9fafeSAnthony Liguori } 110357c9fafeSAnthony Liguori 110439f72ef9SStefan Hajnoczi void object_property_allow_set_link(Object *obj, const char *name, 110539f72ef9SStefan Hajnoczi Object *val, Error **errp) 110639f72ef9SStefan Hajnoczi { 110739f72ef9SStefan Hajnoczi /* Allow the link to be set, always */ 110839f72ef9SStefan Hajnoczi } 110939f72ef9SStefan Hajnoczi 11109561fda8SStefan Hajnoczi typedef struct { 11119561fda8SStefan Hajnoczi Object **child; 111239f72ef9SStefan Hajnoczi void (*check)(Object *, const char *, Object *, Error **); 11139561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags; 11149561fda8SStefan Hajnoczi } LinkProperty; 11159561fda8SStefan Hajnoczi 111657c9fafeSAnthony Liguori static void object_get_link_property(Object *obj, Visitor *v, void *opaque, 111757c9fafeSAnthony Liguori const char *name, Error **errp) 111857c9fafeSAnthony Liguori { 11199561fda8SStefan Hajnoczi LinkProperty *lprop = opaque; 11209561fda8SStefan Hajnoczi Object **child = lprop->child; 112157c9fafeSAnthony Liguori gchar *path; 112257c9fafeSAnthony Liguori 112357c9fafeSAnthony Liguori if (*child) { 112457c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 112557c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 112657c9fafeSAnthony Liguori g_free(path); 112757c9fafeSAnthony Liguori } else { 112857c9fafeSAnthony Liguori path = (gchar *)""; 112957c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 113057c9fafeSAnthony Liguori } 113157c9fafeSAnthony Liguori } 113257c9fafeSAnthony Liguori 1133f5ec6704SStefan Hajnoczi /* 1134f5ec6704SStefan Hajnoczi * object_resolve_link: 1135f5ec6704SStefan Hajnoczi * 1136f5ec6704SStefan Hajnoczi * Lookup an object and ensure its type matches the link property type. This 1137f5ec6704SStefan Hajnoczi * is similar to object_resolve_path() except type verification against the 1138f5ec6704SStefan Hajnoczi * link property is performed. 1139f5ec6704SStefan Hajnoczi * 1140f5ec6704SStefan Hajnoczi * Returns: The matched object or NULL on path lookup failures. 1141f5ec6704SStefan Hajnoczi */ 1142f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name, 1143f5ec6704SStefan Hajnoczi const char *path, Error **errp) 1144f5ec6704SStefan Hajnoczi { 1145f5ec6704SStefan Hajnoczi const char *type; 1146f5ec6704SStefan Hajnoczi gchar *target_type; 1147f5ec6704SStefan Hajnoczi bool ambiguous = false; 1148f5ec6704SStefan Hajnoczi Object *target; 1149f5ec6704SStefan Hajnoczi 1150f5ec6704SStefan Hajnoczi /* Go from link<FOO> to FOO. */ 1151f5ec6704SStefan Hajnoczi type = object_property_get_type(obj, name, NULL); 1152f5ec6704SStefan Hajnoczi target_type = g_strndup(&type[5], strlen(type) - 6); 1153f5ec6704SStefan Hajnoczi target = object_resolve_path_type(path, target_type, &ambiguous); 1154f5ec6704SStefan Hajnoczi 1155f5ec6704SStefan Hajnoczi if (ambiguous) { 1156f231b88dSCole Robinson error_set(errp, ERROR_CLASS_GENERIC_ERROR, 1157f231b88dSCole Robinson "Path '%s' does not uniquely identify an object", path); 1158f5ec6704SStefan Hajnoczi } else if (!target) { 1159f5ec6704SStefan Hajnoczi target = object_resolve_path(path, &ambiguous); 1160f5ec6704SStefan Hajnoczi if (target || ambiguous) { 1161f5ec6704SStefan Hajnoczi error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 1162f5ec6704SStefan Hajnoczi } else { 1163f5ec6704SStefan Hajnoczi error_set(errp, QERR_DEVICE_NOT_FOUND, path); 1164f5ec6704SStefan Hajnoczi } 1165f5ec6704SStefan Hajnoczi target = NULL; 1166f5ec6704SStefan Hajnoczi } 1167f5ec6704SStefan Hajnoczi g_free(target_type); 1168f5ec6704SStefan Hajnoczi 1169f5ec6704SStefan Hajnoczi return target; 1170f5ec6704SStefan Hajnoczi } 1171f5ec6704SStefan Hajnoczi 117257c9fafeSAnthony Liguori static void object_set_link_property(Object *obj, Visitor *v, void *opaque, 117357c9fafeSAnthony Liguori const char *name, Error **errp) 117457c9fafeSAnthony Liguori { 1175c6aed983SStefan Hajnoczi Error *local_err = NULL; 11769561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 11779561fda8SStefan Hajnoczi Object **child = prop->child; 1178c6aed983SStefan Hajnoczi Object *old_target = *child; 1179c6aed983SStefan Hajnoczi Object *new_target = NULL; 1180c6aed983SStefan Hajnoczi char *path = NULL; 118157c9fafeSAnthony Liguori 1182c6aed983SStefan Hajnoczi visit_type_str(v, &path, name, &local_err); 118357c9fafeSAnthony Liguori 1184c6aed983SStefan Hajnoczi if (!local_err && strcmp(path, "") != 0) { 1185c6aed983SStefan Hajnoczi new_target = object_resolve_link(obj, name, path, &local_err); 118611e35bfdSPaolo Bonzini } 118757c9fafeSAnthony Liguori 118857c9fafeSAnthony Liguori g_free(path); 1189c6aed983SStefan Hajnoczi if (local_err) { 1190c6aed983SStefan Hajnoczi error_propagate(errp, local_err); 1191c6aed983SStefan Hajnoczi return; 1192c6aed983SStefan Hajnoczi } 1193f0cdc966SAlexander Barabash 119439f72ef9SStefan Hajnoczi prop->check(obj, name, new_target, &local_err); 119539f72ef9SStefan Hajnoczi if (local_err) { 119639f72ef9SStefan Hajnoczi error_propagate(errp, local_err); 119739f72ef9SStefan Hajnoczi return; 119839f72ef9SStefan Hajnoczi } 119939f72ef9SStefan Hajnoczi 1200c6aed983SStefan Hajnoczi object_ref(new_target); 1201c6aed983SStefan Hajnoczi *child = new_target; 1202f0cdc966SAlexander Barabash object_unref(old_target); 1203f0cdc966SAlexander Barabash } 120457c9fafeSAnthony Liguori 120564607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) 120664607d08SPaolo Bonzini { 120764607d08SPaolo Bonzini LinkProperty *lprop = opaque; 120864607d08SPaolo Bonzini 120964607d08SPaolo Bonzini return *lprop->child; 121064607d08SPaolo Bonzini } 121164607d08SPaolo Bonzini 12129561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name, 12139561fda8SStefan Hajnoczi void *opaque) 12149561fda8SStefan Hajnoczi { 12159561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 12169561fda8SStefan Hajnoczi 12179561fda8SStefan Hajnoczi if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { 12189561fda8SStefan Hajnoczi object_unref(*prop->child); 12199561fda8SStefan Hajnoczi } 12209561fda8SStefan Hajnoczi g_free(prop); 12219561fda8SStefan Hajnoczi } 12229561fda8SStefan Hajnoczi 122357c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 122457c9fafeSAnthony Liguori const char *type, Object **child, 122539f72ef9SStefan Hajnoczi void (*check)(Object *, const char *, 122639f72ef9SStefan Hajnoczi Object *, Error **), 12279561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags, 122857c9fafeSAnthony Liguori Error **errp) 122957c9fafeSAnthony Liguori { 12309561fda8SStefan Hajnoczi Error *local_err = NULL; 12319561fda8SStefan Hajnoczi LinkProperty *prop = g_malloc(sizeof(*prop)); 123257c9fafeSAnthony Liguori gchar *full_type; 123364607d08SPaolo Bonzini ObjectProperty *op; 123457c9fafeSAnthony Liguori 12359561fda8SStefan Hajnoczi prop->child = child; 123639f72ef9SStefan Hajnoczi prop->check = check; 12379561fda8SStefan Hajnoczi prop->flags = flags; 12389561fda8SStefan Hajnoczi 123957c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 124057c9fafeSAnthony Liguori 124164607d08SPaolo Bonzini op = object_property_add(obj, name, full_type, 124257c9fafeSAnthony Liguori object_get_link_property, 124339f72ef9SStefan Hajnoczi check ? object_set_link_property : NULL, 12449561fda8SStefan Hajnoczi object_release_link_property, 12459561fda8SStefan Hajnoczi prop, 12469561fda8SStefan Hajnoczi &local_err); 12479561fda8SStefan Hajnoczi if (local_err) { 12489561fda8SStefan Hajnoczi error_propagate(errp, local_err); 12499561fda8SStefan Hajnoczi g_free(prop); 125064607d08SPaolo Bonzini goto out; 12519561fda8SStefan Hajnoczi } 125257c9fafeSAnthony Liguori 125364607d08SPaolo Bonzini op->resolve = object_resolve_link_property; 125464607d08SPaolo Bonzini 125564607d08SPaolo Bonzini out: 125657c9fafeSAnthony Liguori g_free(full_type); 125757c9fafeSAnthony Liguori } 125857c9fafeSAnthony Liguori 125911f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj) 126057c9fafeSAnthony Liguori { 126157c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 126257c9fafeSAnthony Liguori 126311f590b1SStefan Hajnoczi g_assert(obj); 126457c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 126557c9fafeSAnthony Liguori 126657c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->parent->properties, node) { 12675d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 126857c9fafeSAnthony Liguori continue; 126957c9fafeSAnthony Liguori } 127057c9fafeSAnthony Liguori 127157c9fafeSAnthony Liguori if (prop->opaque == obj) { 127211f590b1SStefan Hajnoczi return g_strdup(prop->name); 127357c9fafeSAnthony Liguori } 127457c9fafeSAnthony Liguori } 127557c9fafeSAnthony Liguori 127611f590b1SStefan Hajnoczi /* obj had a parent but was not a child, should never happen */ 127711f590b1SStefan Hajnoczi g_assert_not_reached(); 127811f590b1SStefan Hajnoczi return NULL; 127911f590b1SStefan Hajnoczi } 128011f590b1SStefan Hajnoczi 128111f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj) 128211f590b1SStefan Hajnoczi { 128311f590b1SStefan Hajnoczi Object *root = object_get_root(); 128411f590b1SStefan Hajnoczi char *newpath, *path = NULL; 128511f590b1SStefan Hajnoczi 128611f590b1SStefan Hajnoczi while (obj != root) { 128711f590b1SStefan Hajnoczi char *component = object_get_canonical_path_component(obj); 128811f590b1SStefan Hajnoczi 128911f590b1SStefan Hajnoczi if (path) { 129011f590b1SStefan Hajnoczi newpath = g_strdup_printf("%s/%s", component, path); 129111f590b1SStefan Hajnoczi g_free(component); 129211f590b1SStefan Hajnoczi g_free(path); 129311f590b1SStefan Hajnoczi path = newpath; 129411f590b1SStefan Hajnoczi } else { 129511f590b1SStefan Hajnoczi path = component; 129611f590b1SStefan Hajnoczi } 129757c9fafeSAnthony Liguori 129857c9fafeSAnthony Liguori obj = obj->parent; 129957c9fafeSAnthony Liguori } 130057c9fafeSAnthony Liguori 130111f590b1SStefan Hajnoczi newpath = g_strdup_printf("/%s", path ? path : ""); 130257c9fafeSAnthony Liguori g_free(path); 130357c9fafeSAnthony Liguori 130457c9fafeSAnthony Liguori return newpath; 130557c9fafeSAnthony Liguori } 130657c9fafeSAnthony Liguori 13073e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part) 1308a612b2a6SPaolo Bonzini { 130989bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part, NULL); 1310a612b2a6SPaolo Bonzini if (prop == NULL) { 1311a612b2a6SPaolo Bonzini return NULL; 1312a612b2a6SPaolo Bonzini } 1313a612b2a6SPaolo Bonzini 131464607d08SPaolo Bonzini if (prop->resolve) { 131564607d08SPaolo Bonzini return prop->resolve(parent, prop->opaque, part); 1316a612b2a6SPaolo Bonzini } else { 1317a612b2a6SPaolo Bonzini return NULL; 1318a612b2a6SPaolo Bonzini } 1319a612b2a6SPaolo Bonzini } 1320a612b2a6SPaolo Bonzini 132157c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 132257c9fafeSAnthony Liguori gchar **parts, 132302fe2db6SPaolo Bonzini const char *typename, 132457c9fafeSAnthony Liguori int index) 132557c9fafeSAnthony Liguori { 132657c9fafeSAnthony Liguori Object *child; 132757c9fafeSAnthony Liguori 132857c9fafeSAnthony Liguori if (parts[index] == NULL) { 132902fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 133057c9fafeSAnthony Liguori } 133157c9fafeSAnthony Liguori 133257c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 133302fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 133457c9fafeSAnthony Liguori } 133557c9fafeSAnthony Liguori 1336a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 133757c9fafeSAnthony Liguori if (!child) { 133857c9fafeSAnthony Liguori return NULL; 133957c9fafeSAnthony Liguori } 134057c9fafeSAnthony Liguori 134102fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 134257c9fafeSAnthony Liguori } 134357c9fafeSAnthony Liguori 134457c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 134557c9fafeSAnthony Liguori gchar **parts, 134602fe2db6SPaolo Bonzini const char *typename, 134757c9fafeSAnthony Liguori bool *ambiguous) 134857c9fafeSAnthony Liguori { 134957c9fafeSAnthony Liguori Object *obj; 135057c9fafeSAnthony Liguori ObjectProperty *prop; 135157c9fafeSAnthony Liguori 135202fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 135357c9fafeSAnthony Liguori 135457c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &parent->properties, node) { 135557c9fafeSAnthony Liguori Object *found; 135657c9fafeSAnthony Liguori 13575d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 135857c9fafeSAnthony Liguori continue; 135957c9fafeSAnthony Liguori } 136057c9fafeSAnthony Liguori 136102fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 136202fe2db6SPaolo Bonzini typename, ambiguous); 136357c9fafeSAnthony Liguori if (found) { 136457c9fafeSAnthony Liguori if (obj) { 136557c9fafeSAnthony Liguori if (ambiguous) { 136657c9fafeSAnthony Liguori *ambiguous = true; 136757c9fafeSAnthony Liguori } 136857c9fafeSAnthony Liguori return NULL; 136957c9fafeSAnthony Liguori } 137057c9fafeSAnthony Liguori obj = found; 137157c9fafeSAnthony Liguori } 137257c9fafeSAnthony Liguori 137357c9fafeSAnthony Liguori if (ambiguous && *ambiguous) { 137457c9fafeSAnthony Liguori return NULL; 137557c9fafeSAnthony Liguori } 137657c9fafeSAnthony Liguori } 137757c9fafeSAnthony Liguori 137857c9fafeSAnthony Liguori return obj; 137957c9fafeSAnthony Liguori } 138057c9fafeSAnthony Liguori 138102fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 138202fe2db6SPaolo Bonzini bool *ambiguous) 138357c9fafeSAnthony Liguori { 138457c9fafeSAnthony Liguori Object *obj; 138557c9fafeSAnthony Liguori gchar **parts; 138657c9fafeSAnthony Liguori 138757c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 13882e1103f6SPaolo Bonzini assert(parts); 138957c9fafeSAnthony Liguori 13902e1103f6SPaolo Bonzini if (parts[0] == NULL || strcmp(parts[0], "") != 0) { 139157c9fafeSAnthony Liguori if (ambiguous) { 139257c9fafeSAnthony Liguori *ambiguous = false; 139357c9fafeSAnthony Liguori } 139402fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 139502fe2db6SPaolo Bonzini typename, ambiguous); 139657c9fafeSAnthony Liguori } else { 139702fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 139857c9fafeSAnthony Liguori } 139957c9fafeSAnthony Liguori 140057c9fafeSAnthony Liguori g_strfreev(parts); 140157c9fafeSAnthony Liguori 140257c9fafeSAnthony Liguori return obj; 140357c9fafeSAnthony Liguori } 140457c9fafeSAnthony Liguori 140502fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 140602fe2db6SPaolo Bonzini { 140702fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 140802fe2db6SPaolo Bonzini } 140902fe2db6SPaolo Bonzini 141057c9fafeSAnthony Liguori typedef struct StringProperty 141157c9fafeSAnthony Liguori { 141257c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 141357c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 141457c9fafeSAnthony Liguori } StringProperty; 141557c9fafeSAnthony Liguori 14167b7b7d18SPaolo Bonzini static void property_get_str(Object *obj, Visitor *v, void *opaque, 141757c9fafeSAnthony Liguori const char *name, Error **errp) 141857c9fafeSAnthony Liguori { 141957c9fafeSAnthony Liguori StringProperty *prop = opaque; 142057c9fafeSAnthony Liguori char *value; 142157c9fafeSAnthony Liguori 142257c9fafeSAnthony Liguori value = prop->get(obj, errp); 142357c9fafeSAnthony Liguori if (value) { 142457c9fafeSAnthony Liguori visit_type_str(v, &value, name, errp); 142557c9fafeSAnthony Liguori g_free(value); 142657c9fafeSAnthony Liguori } 142757c9fafeSAnthony Liguori } 142857c9fafeSAnthony Liguori 14297b7b7d18SPaolo Bonzini static void property_set_str(Object *obj, Visitor *v, void *opaque, 143057c9fafeSAnthony Liguori const char *name, Error **errp) 143157c9fafeSAnthony Liguori { 143257c9fafeSAnthony Liguori StringProperty *prop = opaque; 143357c9fafeSAnthony Liguori char *value; 143457c9fafeSAnthony Liguori Error *local_err = NULL; 143557c9fafeSAnthony Liguori 143657c9fafeSAnthony Liguori visit_type_str(v, &value, name, &local_err); 143757c9fafeSAnthony Liguori if (local_err) { 143857c9fafeSAnthony Liguori error_propagate(errp, local_err); 143957c9fafeSAnthony Liguori return; 144057c9fafeSAnthony Liguori } 144157c9fafeSAnthony Liguori 144257c9fafeSAnthony Liguori prop->set(obj, value, errp); 144357c9fafeSAnthony Liguori g_free(value); 144457c9fafeSAnthony Liguori } 144557c9fafeSAnthony Liguori 14467b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 144757c9fafeSAnthony Liguori void *opaque) 144857c9fafeSAnthony Liguori { 144957c9fafeSAnthony Liguori StringProperty *prop = opaque; 145057c9fafeSAnthony Liguori g_free(prop); 145157c9fafeSAnthony Liguori } 145257c9fafeSAnthony Liguori 145357c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 145457c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 145557c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 145657c9fafeSAnthony Liguori Error **errp) 145757c9fafeSAnthony Liguori { 1458a01aedc8SStefan Hajnoczi Error *local_err = NULL; 145957c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 146057c9fafeSAnthony Liguori 146157c9fafeSAnthony Liguori prop->get = get; 146257c9fafeSAnthony Liguori prop->set = set; 146357c9fafeSAnthony Liguori 146457c9fafeSAnthony Liguori object_property_add(obj, name, "string", 14657b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 14667b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 14677b7b7d18SPaolo Bonzini property_release_str, 1468a01aedc8SStefan Hajnoczi prop, &local_err); 1469a01aedc8SStefan Hajnoczi if (local_err) { 1470a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1471a01aedc8SStefan Hajnoczi g_free(prop); 1472a01aedc8SStefan Hajnoczi } 147357c9fafeSAnthony Liguori } 1474745549c8SPaolo Bonzini 14750e558843SAnthony Liguori typedef struct BoolProperty 14760e558843SAnthony Liguori { 14770e558843SAnthony Liguori bool (*get)(Object *, Error **); 14780e558843SAnthony Liguori void (*set)(Object *, bool, Error **); 14790e558843SAnthony Liguori } BoolProperty; 14800e558843SAnthony Liguori 14810e558843SAnthony Liguori static void property_get_bool(Object *obj, Visitor *v, void *opaque, 14820e558843SAnthony Liguori const char *name, Error **errp) 14830e558843SAnthony Liguori { 14840e558843SAnthony Liguori BoolProperty *prop = opaque; 14850e558843SAnthony Liguori bool value; 14860e558843SAnthony Liguori 14870e558843SAnthony Liguori value = prop->get(obj, errp); 14880e558843SAnthony Liguori visit_type_bool(v, &value, name, errp); 14890e558843SAnthony Liguori } 14900e558843SAnthony Liguori 14910e558843SAnthony Liguori static void property_set_bool(Object *obj, Visitor *v, void *opaque, 14920e558843SAnthony Liguori const char *name, Error **errp) 14930e558843SAnthony Liguori { 14940e558843SAnthony Liguori BoolProperty *prop = opaque; 14950e558843SAnthony Liguori bool value; 14960e558843SAnthony Liguori Error *local_err = NULL; 14970e558843SAnthony Liguori 14980e558843SAnthony Liguori visit_type_bool(v, &value, name, &local_err); 14990e558843SAnthony Liguori if (local_err) { 15000e558843SAnthony Liguori error_propagate(errp, local_err); 15010e558843SAnthony Liguori return; 15020e558843SAnthony Liguori } 15030e558843SAnthony Liguori 15040e558843SAnthony Liguori prop->set(obj, value, errp); 15050e558843SAnthony Liguori } 15060e558843SAnthony Liguori 15070e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name, 15080e558843SAnthony Liguori void *opaque) 15090e558843SAnthony Liguori { 15100e558843SAnthony Liguori BoolProperty *prop = opaque; 15110e558843SAnthony Liguori g_free(prop); 15120e558843SAnthony Liguori } 15130e558843SAnthony Liguori 15140e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name, 15150e558843SAnthony Liguori bool (*get)(Object *, Error **), 15160e558843SAnthony Liguori void (*set)(Object *, bool, Error **), 15170e558843SAnthony Liguori Error **errp) 15180e558843SAnthony Liguori { 1519a01aedc8SStefan Hajnoczi Error *local_err = NULL; 15200e558843SAnthony Liguori BoolProperty *prop = g_malloc0(sizeof(*prop)); 15210e558843SAnthony Liguori 15220e558843SAnthony Liguori prop->get = get; 15230e558843SAnthony Liguori prop->set = set; 15240e558843SAnthony Liguori 15250e558843SAnthony Liguori object_property_add(obj, name, "bool", 15260e558843SAnthony Liguori get ? property_get_bool : NULL, 15270e558843SAnthony Liguori set ? property_set_bool : NULL, 15280e558843SAnthony Liguori property_release_bool, 1529a01aedc8SStefan Hajnoczi prop, &local_err); 1530a01aedc8SStefan Hajnoczi if (local_err) { 1531a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1532a01aedc8SStefan Hajnoczi g_free(prop); 1533a01aedc8SStefan Hajnoczi } 15340e558843SAnthony Liguori } 15350e558843SAnthony Liguori 15362f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp) 15372f262e06SPaolo Bonzini { 15382f262e06SPaolo Bonzini return g_strdup(object_get_typename(obj)); 15392f262e06SPaolo Bonzini } 15402f262e06SPaolo Bonzini 1541e732ea63SMichael S. Tsirkin static void property_get_uint8_ptr(Object *obj, Visitor *v, 1542e732ea63SMichael S. Tsirkin void *opaque, const char *name, 1543e732ea63SMichael S. Tsirkin Error **errp) 1544e732ea63SMichael S. Tsirkin { 1545e732ea63SMichael S. Tsirkin uint8_t value = *(uint8_t *)opaque; 1546e732ea63SMichael S. Tsirkin visit_type_uint8(v, &value, name, errp); 1547e732ea63SMichael S. Tsirkin } 1548e732ea63SMichael S. Tsirkin 1549e732ea63SMichael S. Tsirkin static void property_get_uint16_ptr(Object *obj, Visitor *v, 1550e732ea63SMichael S. Tsirkin void *opaque, const char *name, 1551e732ea63SMichael S. Tsirkin Error **errp) 1552e732ea63SMichael S. Tsirkin { 1553e732ea63SMichael S. Tsirkin uint16_t value = *(uint16_t *)opaque; 1554e732ea63SMichael S. Tsirkin visit_type_uint16(v, &value, name, errp); 1555e732ea63SMichael S. Tsirkin } 1556e732ea63SMichael S. Tsirkin 1557e732ea63SMichael S. Tsirkin static void property_get_uint32_ptr(Object *obj, Visitor *v, 1558e732ea63SMichael S. Tsirkin void *opaque, const char *name, 1559e732ea63SMichael S. Tsirkin Error **errp) 1560e732ea63SMichael S. Tsirkin { 1561e732ea63SMichael S. Tsirkin uint32_t value = *(uint32_t *)opaque; 1562e732ea63SMichael S. Tsirkin visit_type_uint32(v, &value, name, errp); 1563e732ea63SMichael S. Tsirkin } 1564e732ea63SMichael S. Tsirkin 1565e732ea63SMichael S. Tsirkin static void property_get_uint64_ptr(Object *obj, Visitor *v, 1566e732ea63SMichael S. Tsirkin void *opaque, const char *name, 1567e732ea63SMichael S. Tsirkin Error **errp) 1568e732ea63SMichael S. Tsirkin { 1569e732ea63SMichael S. Tsirkin uint64_t value = *(uint64_t *)opaque; 1570e732ea63SMichael S. Tsirkin visit_type_uint64(v, &value, name, errp); 1571e732ea63SMichael S. Tsirkin } 1572e732ea63SMichael S. Tsirkin 1573e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name, 1574e732ea63SMichael S. Tsirkin const uint8_t *v, Error **errp) 1575e732ea63SMichael S. Tsirkin { 1576e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint8", property_get_uint8_ptr, 1577e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 1578e732ea63SMichael S. Tsirkin } 1579e732ea63SMichael S. Tsirkin 1580e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name, 1581e732ea63SMichael S. Tsirkin const uint16_t *v, Error **errp) 1582e732ea63SMichael S. Tsirkin { 1583e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint16", property_get_uint16_ptr, 1584e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 1585e732ea63SMichael S. Tsirkin } 1586e732ea63SMichael S. Tsirkin 1587e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name, 1588e732ea63SMichael S. Tsirkin const uint32_t *v, Error **errp) 1589e732ea63SMichael S. Tsirkin { 1590e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint32", property_get_uint32_ptr, 1591e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 1592e732ea63SMichael S. Tsirkin } 1593e732ea63SMichael S. Tsirkin 1594e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name, 1595e732ea63SMichael S. Tsirkin const uint64_t *v, Error **errp) 1596e732ea63SMichael S. Tsirkin { 1597e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint64", property_get_uint64_ptr, 1598e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 1599e732ea63SMichael S. Tsirkin } 1600e732ea63SMichael S. Tsirkin 1601ef7c7ff6SStefan Hajnoczi typedef struct { 1602ef7c7ff6SStefan Hajnoczi Object *target_obj; 1603ef7c7ff6SStefan Hajnoczi const char *target_name; 1604ef7c7ff6SStefan Hajnoczi } AliasProperty; 1605ef7c7ff6SStefan Hajnoczi 1606ef7c7ff6SStefan Hajnoczi static void property_get_alias(Object *obj, struct Visitor *v, void *opaque, 1607ef7c7ff6SStefan Hajnoczi const char *name, Error **errp) 1608ef7c7ff6SStefan Hajnoczi { 1609ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 1610ef7c7ff6SStefan Hajnoczi 1611ef7c7ff6SStefan Hajnoczi object_property_get(prop->target_obj, v, prop->target_name, errp); 1612ef7c7ff6SStefan Hajnoczi } 1613ef7c7ff6SStefan Hajnoczi 1614ef7c7ff6SStefan Hajnoczi static void property_set_alias(Object *obj, struct Visitor *v, void *opaque, 1615ef7c7ff6SStefan Hajnoczi const char *name, Error **errp) 1616ef7c7ff6SStefan Hajnoczi { 1617ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 1618ef7c7ff6SStefan Hajnoczi 1619ef7c7ff6SStefan Hajnoczi object_property_set(prop->target_obj, v, prop->target_name, errp); 1620ef7c7ff6SStefan Hajnoczi } 1621ef7c7ff6SStefan Hajnoczi 162264607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque, 162364607d08SPaolo Bonzini const gchar *part) 162464607d08SPaolo Bonzini { 162564607d08SPaolo Bonzini AliasProperty *prop = opaque; 162664607d08SPaolo Bonzini 162764607d08SPaolo Bonzini return object_resolve_path_component(prop->target_obj, prop->target_name); 162864607d08SPaolo Bonzini } 162964607d08SPaolo Bonzini 1630ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque) 1631ef7c7ff6SStefan Hajnoczi { 1632ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 1633ef7c7ff6SStefan Hajnoczi 1634ef7c7ff6SStefan Hajnoczi g_free(prop); 1635ef7c7ff6SStefan Hajnoczi } 1636ef7c7ff6SStefan Hajnoczi 1637ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name, 1638ef7c7ff6SStefan Hajnoczi Object *target_obj, const char *target_name, 1639ef7c7ff6SStefan Hajnoczi Error **errp) 1640ef7c7ff6SStefan Hajnoczi { 1641ef7c7ff6SStefan Hajnoczi AliasProperty *prop; 164264607d08SPaolo Bonzini ObjectProperty *op; 1643ef7c7ff6SStefan Hajnoczi ObjectProperty *target_prop; 1644d190698eSPaolo Bonzini gchar *prop_type; 1645*8ae9a9efSGonglei Error *local_err = NULL; 1646ef7c7ff6SStefan Hajnoczi 1647ef7c7ff6SStefan Hajnoczi target_prop = object_property_find(target_obj, target_name, errp); 1648ef7c7ff6SStefan Hajnoczi if (!target_prop) { 1649ef7c7ff6SStefan Hajnoczi return; 1650ef7c7ff6SStefan Hajnoczi } 1651ef7c7ff6SStefan Hajnoczi 1652d190698eSPaolo Bonzini if (object_property_is_child(target_prop)) { 1653d190698eSPaolo Bonzini prop_type = g_strdup_printf("link%s", 1654d190698eSPaolo Bonzini target_prop->type + strlen("child")); 1655d190698eSPaolo Bonzini } else { 1656d190698eSPaolo Bonzini prop_type = g_strdup(target_prop->type); 1657d190698eSPaolo Bonzini } 1658d190698eSPaolo Bonzini 1659ef7c7ff6SStefan Hajnoczi prop = g_malloc(sizeof(*prop)); 1660ef7c7ff6SStefan Hajnoczi prop->target_obj = target_obj; 1661ef7c7ff6SStefan Hajnoczi prop->target_name = target_name; 1662ef7c7ff6SStefan Hajnoczi 1663d190698eSPaolo Bonzini op = object_property_add(obj, name, prop_type, 1664ef7c7ff6SStefan Hajnoczi property_get_alias, 1665ef7c7ff6SStefan Hajnoczi property_set_alias, 1666ef7c7ff6SStefan Hajnoczi property_release_alias, 1667*8ae9a9efSGonglei prop, &local_err); 1668*8ae9a9efSGonglei if (local_err) { 1669*8ae9a9efSGonglei error_propagate(errp, local_err); 1670*8ae9a9efSGonglei g_free(prop); 1671*8ae9a9efSGonglei goto out; 1672*8ae9a9efSGonglei } 167364607d08SPaolo Bonzini op->resolve = property_resolve_alias; 1674d190698eSPaolo Bonzini 1675*8ae9a9efSGonglei out: 1676d190698eSPaolo Bonzini g_free(prop_type); 1677ef7c7ff6SStefan Hajnoczi } 1678ef7c7ff6SStefan Hajnoczi 16792f262e06SPaolo Bonzini static void object_instance_init(Object *obj) 16802f262e06SPaolo Bonzini { 16812f262e06SPaolo Bonzini object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); 16822f262e06SPaolo Bonzini } 16832f262e06SPaolo Bonzini 1684745549c8SPaolo Bonzini static void register_types(void) 1685745549c8SPaolo Bonzini { 1686745549c8SPaolo Bonzini static TypeInfo interface_info = { 1687745549c8SPaolo Bonzini .name = TYPE_INTERFACE, 168833e95c63SAnthony Liguori .class_size = sizeof(InterfaceClass), 1689745549c8SPaolo Bonzini .abstract = true, 1690745549c8SPaolo Bonzini }; 1691745549c8SPaolo Bonzini 1692745549c8SPaolo Bonzini static TypeInfo object_info = { 1693745549c8SPaolo Bonzini .name = TYPE_OBJECT, 1694745549c8SPaolo Bonzini .instance_size = sizeof(Object), 16952f262e06SPaolo Bonzini .instance_init = object_instance_init, 1696745549c8SPaolo Bonzini .abstract = true, 1697745549c8SPaolo Bonzini }; 1698745549c8SPaolo Bonzini 1699049cb3cfSPaolo Bonzini type_interface = type_register_internal(&interface_info); 1700049cb3cfSPaolo Bonzini type_register_internal(&object_info); 1701745549c8SPaolo Bonzini } 1702745549c8SPaolo Bonzini 1703745549c8SPaolo Bonzini type_init(register_types) 1704