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 139bbc853bSPeter Maydell #include "qemu/osdep.h" 14da34e65cSMarkus Armbruster #include "qapi/error.h" 1514cccb61SPaolo Bonzini #include "qom/object.h" 16a31bdae5SDaniel P. Berrange #include "qom/object_interfaces.h" 17f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 187b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 191f21772dSHu Tao #include "qapi-visit.h" 20b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h" 21b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h" 227b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 23fa131d94SPaolo Bonzini #include "trace.h" 242f28d2ffSAnthony Liguori 257b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency 267b7b7d18SPaolo Bonzini * of the QOM core on QObject? */ 2714cccb61SPaolo Bonzini #include "qom/qom-qobject.h" 287b1b5d19SPaolo Bonzini #include "qapi/qmp/qobject.h" 297b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h" 307b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h" 317b7b7d18SPaolo Bonzini 322f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 332f28d2ffSAnthony Liguori 342f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 352f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 362f28d2ffSAnthony Liguori 372f28d2ffSAnthony Liguori struct InterfaceImpl 382f28d2ffSAnthony Liguori { 3933e95c63SAnthony Liguori const char *typename; 402f28d2ffSAnthony Liguori }; 412f28d2ffSAnthony Liguori 422f28d2ffSAnthony Liguori struct TypeImpl 432f28d2ffSAnthony Liguori { 442f28d2ffSAnthony Liguori const char *name; 452f28d2ffSAnthony Liguori 462f28d2ffSAnthony Liguori size_t class_size; 472f28d2ffSAnthony Liguori 482f28d2ffSAnthony Liguori size_t instance_size; 492f28d2ffSAnthony Liguori 502f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 513b50e311SPaolo Bonzini void (*class_base_init)(ObjectClass *klass, void *data); 522f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 532f28d2ffSAnthony Liguori 542f28d2ffSAnthony Liguori void *class_data; 552f28d2ffSAnthony Liguori 562f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 578231c2ddSEduardo Habkost void (*instance_post_init)(Object *obj); 582f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 592f28d2ffSAnthony Liguori 602f28d2ffSAnthony Liguori bool abstract; 612f28d2ffSAnthony Liguori 622f28d2ffSAnthony Liguori const char *parent; 632f28d2ffSAnthony Liguori TypeImpl *parent_type; 642f28d2ffSAnthony Liguori 652f28d2ffSAnthony Liguori ObjectClass *class; 662f28d2ffSAnthony Liguori 672f28d2ffSAnthony Liguori int num_interfaces; 682f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 692f28d2ffSAnthony Liguori }; 702f28d2ffSAnthony Liguori 719970bd88SPaolo Bonzini static Type type_interface; 729970bd88SPaolo Bonzini 732f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 742f28d2ffSAnthony Liguori { 752f28d2ffSAnthony Liguori static GHashTable *type_table; 762f28d2ffSAnthony Liguori 772f28d2ffSAnthony Liguori if (type_table == NULL) { 782f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 792f28d2ffSAnthony Liguori } 802f28d2ffSAnthony Liguori 812f28d2ffSAnthony Liguori return type_table; 822f28d2ffSAnthony Liguori } 832f28d2ffSAnthony Liguori 84f54c19caSHervé Poussineau static bool enumerating_types; 85f54c19caSHervé Poussineau 862f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 872f28d2ffSAnthony Liguori { 88f54c19caSHervé Poussineau assert(!enumerating_types); 892f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 902f28d2ffSAnthony Liguori } 912f28d2ffSAnthony Liguori 922f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 932f28d2ffSAnthony Liguori { 942f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 952f28d2ffSAnthony Liguori } 962f28d2ffSAnthony Liguori 97b061dc41SPaolo Bonzini static TypeImpl *type_new(const TypeInfo *info) 982f28d2ffSAnthony Liguori { 992f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 10033e95c63SAnthony Liguori int i; 1012f28d2ffSAnthony Liguori 1022f28d2ffSAnthony Liguori g_assert(info->name != NULL); 1032f28d2ffSAnthony Liguori 10473093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 10573093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 10673093354SAnthony Liguori abort(); 10773093354SAnthony Liguori } 10873093354SAnthony Liguori 1092f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1102f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1112f28d2ffSAnthony Liguori 1122f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1132f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1142f28d2ffSAnthony Liguori 1152f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1163b50e311SPaolo Bonzini ti->class_base_init = info->class_base_init; 1172f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1182f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1192f28d2ffSAnthony Liguori 1202f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1218231c2ddSEduardo Habkost ti->instance_post_init = info->instance_post_init; 1222f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1232f28d2ffSAnthony Liguori 1242f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1252f28d2ffSAnthony Liguori 12633e95c63SAnthony Liguori for (i = 0; info->interfaces && info->interfaces[i].type; i++) { 12733e95c63SAnthony Liguori ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); 1282f28d2ffSAnthony Liguori } 12933e95c63SAnthony Liguori ti->num_interfaces = i; 1302f28d2ffSAnthony Liguori 131b061dc41SPaolo Bonzini return ti; 132b061dc41SPaolo Bonzini } 1332f28d2ffSAnthony Liguori 134b061dc41SPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info) 135b061dc41SPaolo Bonzini { 136b061dc41SPaolo Bonzini TypeImpl *ti; 137b061dc41SPaolo Bonzini ti = type_new(info); 138b061dc41SPaolo Bonzini 139b061dc41SPaolo Bonzini type_table_add(ti); 1402f28d2ffSAnthony Liguori return ti; 1412f28d2ffSAnthony Liguori } 1422f28d2ffSAnthony Liguori 143049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info) 144049cb3cfSPaolo Bonzini { 145049cb3cfSPaolo Bonzini assert(info->parent); 146049cb3cfSPaolo Bonzini return type_register_internal(info); 147049cb3cfSPaolo Bonzini } 148049cb3cfSPaolo Bonzini 1492f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1502f28d2ffSAnthony Liguori { 1512f28d2ffSAnthony Liguori return type_register(info); 1522f28d2ffSAnthony Liguori } 1532f28d2ffSAnthony Liguori 1542f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1552f28d2ffSAnthony Liguori { 1562f28d2ffSAnthony Liguori if (name == NULL) { 1572f28d2ffSAnthony Liguori return NULL; 1582f28d2ffSAnthony Liguori } 1592f28d2ffSAnthony Liguori 1602f28d2ffSAnthony Liguori return type_table_lookup(name); 1612f28d2ffSAnthony Liguori } 1622f28d2ffSAnthony Liguori 1632f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1642f28d2ffSAnthony Liguori { 1652f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1662f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1672f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1682f28d2ffSAnthony Liguori } 1692f28d2ffSAnthony Liguori 1702f28d2ffSAnthony Liguori return type->parent_type; 1712f28d2ffSAnthony Liguori } 1722f28d2ffSAnthony Liguori 1732f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1742f28d2ffSAnthony Liguori { 1752f28d2ffSAnthony Liguori return (type->parent != NULL); 1762f28d2ffSAnthony Liguori } 1772f28d2ffSAnthony Liguori 1782f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1792f28d2ffSAnthony Liguori { 1802f28d2ffSAnthony Liguori if (ti->class_size) { 1812f28d2ffSAnthony Liguori return ti->class_size; 1822f28d2ffSAnthony Liguori } 1832f28d2ffSAnthony Liguori 1842f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1852f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1862f28d2ffSAnthony Liguori } 1872f28d2ffSAnthony Liguori 1882f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1892f28d2ffSAnthony Liguori } 1902f28d2ffSAnthony Liguori 191aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 192aca59af6SIgor Mitsyanko { 193aca59af6SIgor Mitsyanko if (ti->instance_size) { 194aca59af6SIgor Mitsyanko return ti->instance_size; 195aca59af6SIgor Mitsyanko } 196aca59af6SIgor Mitsyanko 197aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 198aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 199aca59af6SIgor Mitsyanko } 200aca59af6SIgor Mitsyanko 201aca59af6SIgor Mitsyanko return 0; 202aca59af6SIgor Mitsyanko } 203aca59af6SIgor Mitsyanko 2043f97b53aSBharata B Rao size_t object_type_get_instance_size(const char *typename) 2053f97b53aSBharata B Rao { 2063f97b53aSBharata B Rao TypeImpl *type = type_get_by_name(typename); 2073f97b53aSBharata B Rao 2083f97b53aSBharata B Rao g_assert(type != NULL); 2093f97b53aSBharata B Rao return type_object_get_size(type); 2103f97b53aSBharata B Rao } 2113f97b53aSBharata B Rao 21233e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 2132f28d2ffSAnthony Liguori { 21433e95c63SAnthony Liguori assert(target_type); 2152f28d2ffSAnthony Liguori 216b30d8054SCao jin /* Check if target_type is a direct ancestor of type */ 21733e95c63SAnthony Liguori while (type) { 21833e95c63SAnthony Liguori if (type == target_type) { 21933e95c63SAnthony Liguori return true; 22033e95c63SAnthony Liguori } 22133e95c63SAnthony Liguori 22233e95c63SAnthony Liguori type = type_get_parent(type); 22333e95c63SAnthony Liguori } 22433e95c63SAnthony Liguori 22533e95c63SAnthony Liguori return false; 22633e95c63SAnthony Liguori } 22733e95c63SAnthony Liguori 22833e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti); 22933e95c63SAnthony Liguori 230b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, 231b061dc41SPaolo Bonzini TypeImpl *parent_type) 23233e95c63SAnthony Liguori { 23333e95c63SAnthony Liguori InterfaceClass *new_iface; 23433e95c63SAnthony Liguori TypeInfo info = { }; 23533e95c63SAnthony Liguori TypeImpl *iface_impl; 23633e95c63SAnthony Liguori 237b061dc41SPaolo Bonzini info.parent = parent_type->name; 238b061dc41SPaolo Bonzini info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); 23933e95c63SAnthony Liguori info.abstract = true; 24033e95c63SAnthony Liguori 241b061dc41SPaolo Bonzini iface_impl = type_new(&info); 242b061dc41SPaolo Bonzini iface_impl->parent_type = parent_type; 24333e95c63SAnthony Liguori type_initialize(iface_impl); 24433e95c63SAnthony Liguori g_free((char *)info.name); 24533e95c63SAnthony Liguori 24633e95c63SAnthony Liguori new_iface = (InterfaceClass *)iface_impl->class; 24733e95c63SAnthony Liguori new_iface->concrete_class = ti->class; 248b061dc41SPaolo Bonzini new_iface->interface_type = interface_type; 24933e95c63SAnthony Liguori 25033e95c63SAnthony Liguori ti->class->interfaces = g_slist_append(ti->class->interfaces, 25133e95c63SAnthony Liguori iface_impl->class); 2522f28d2ffSAnthony Liguori } 2532f28d2ffSAnthony Liguori 25416bf7f52SDaniel P. Berrange static void object_property_free(gpointer data) 25516bf7f52SDaniel P. Berrange { 25616bf7f52SDaniel P. Berrange ObjectProperty *prop = data; 25716bf7f52SDaniel P. Berrange 25816bf7f52SDaniel P. Berrange g_free(prop->name); 25916bf7f52SDaniel P. Berrange g_free(prop->type); 26016bf7f52SDaniel P. Berrange g_free(prop->description); 26116bf7f52SDaniel P. Berrange g_free(prop); 26216bf7f52SDaniel P. Berrange } 26316bf7f52SDaniel P. Berrange 264ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2652f28d2ffSAnthony Liguori { 266745549c8SPaolo Bonzini TypeImpl *parent; 2672f28d2ffSAnthony Liguori 2682f28d2ffSAnthony Liguori if (ti->class) { 2692f28d2ffSAnthony Liguori return; 2702f28d2ffSAnthony Liguori } 2712f28d2ffSAnthony Liguori 2722f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 273aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2741c6d75d5SEduardo Habkost /* Any type with zero instance_size is implicitly abstract. 2751c6d75d5SEduardo Habkost * This means interface types are all abstract. 2761c6d75d5SEduardo Habkost */ 2771c6d75d5SEduardo Habkost if (ti->instance_size == 0) { 2781c6d75d5SEduardo Habkost ti->abstract = true; 2791c6d75d5SEduardo Habkost } 2802f28d2ffSAnthony Liguori 2812f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 2822f28d2ffSAnthony Liguori 283745549c8SPaolo Bonzini parent = type_get_parent(ti); 284745549c8SPaolo Bonzini if (parent) { 285ac451033SIgor Mitsyanko type_initialize(parent); 28633e95c63SAnthony Liguori GSList *e; 28733e95c63SAnthony Liguori int i; 2882f28d2ffSAnthony Liguori 2898438a135SAndreas Färber g_assert_cmpint(parent->class_size, <=, ti->class_size); 290745549c8SPaolo Bonzini memcpy(ti->class, parent->class, parent->class_size); 2913e407de4SPeter Crosthwaite ti->class->interfaces = NULL; 29216bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 29316bf7f52SDaniel P. Berrange g_str_hash, g_str_equal, g_free, object_property_free); 29433e95c63SAnthony Liguori 29533e95c63SAnthony Liguori for (e = parent->class->interfaces; e; e = e->next) { 296b061dc41SPaolo Bonzini InterfaceClass *iface = e->data; 297b061dc41SPaolo Bonzini ObjectClass *klass = OBJECT_CLASS(iface); 298b061dc41SPaolo Bonzini 299b061dc41SPaolo Bonzini type_initialize_interface(ti, iface->interface_type, klass->type); 30033e95c63SAnthony Liguori } 30133e95c63SAnthony Liguori 30233e95c63SAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 30333e95c63SAnthony Liguori TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); 30433e95c63SAnthony Liguori for (e = ti->class->interfaces; e; e = e->next) { 30533e95c63SAnthony Liguori TypeImpl *target_type = OBJECT_CLASS(e->data)->type; 30633e95c63SAnthony Liguori 30733e95c63SAnthony Liguori if (type_is_ancestor(target_type, t)) { 30833e95c63SAnthony Liguori break; 30933e95c63SAnthony Liguori } 31033e95c63SAnthony Liguori } 31133e95c63SAnthony Liguori 31233e95c63SAnthony Liguori if (e) { 31333e95c63SAnthony Liguori continue; 31433e95c63SAnthony Liguori } 31533e95c63SAnthony Liguori 316b061dc41SPaolo Bonzini type_initialize_interface(ti, t, t); 31733e95c63SAnthony Liguori } 31816bf7f52SDaniel P. Berrange } else { 31916bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 32016bf7f52SDaniel P. Berrange g_str_hash, g_str_equal, g_free, object_property_free); 321745549c8SPaolo Bonzini } 3222f28d2ffSAnthony Liguori 323745549c8SPaolo Bonzini ti->class->type = ti; 3243b50e311SPaolo Bonzini 3253b50e311SPaolo Bonzini while (parent) { 3263b50e311SPaolo Bonzini if (parent->class_base_init) { 3273b50e311SPaolo Bonzini parent->class_base_init(ti->class, ti->class_data); 3283b50e311SPaolo Bonzini } 3293b50e311SPaolo Bonzini parent = type_get_parent(parent); 3303b50e311SPaolo Bonzini } 3312f28d2ffSAnthony Liguori 3322f28d2ffSAnthony Liguori if (ti->class_init) { 3332f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 3342f28d2ffSAnthony Liguori } 3352f28d2ffSAnthony Liguori } 3362f28d2ffSAnthony Liguori 3372f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 3382f28d2ffSAnthony Liguori { 3392f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 3402f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 3412f28d2ffSAnthony Liguori } 3422f28d2ffSAnthony Liguori 3432f28d2ffSAnthony Liguori if (ti->instance_init) { 3442f28d2ffSAnthony Liguori ti->instance_init(obj); 3452f28d2ffSAnthony Liguori } 3462f28d2ffSAnthony Liguori } 3472f28d2ffSAnthony Liguori 3488231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti) 3498231c2ddSEduardo Habkost { 3508231c2ddSEduardo Habkost if (ti->instance_post_init) { 3518231c2ddSEduardo Habkost ti->instance_post_init(obj); 3528231c2ddSEduardo Habkost } 3538231c2ddSEduardo Habkost 3548231c2ddSEduardo Habkost if (type_has_parent(ti)) { 3558231c2ddSEduardo Habkost object_post_init_with_type(obj, type_get_parent(ti)); 3568231c2ddSEduardo Habkost } 3578231c2ddSEduardo Habkost } 3588231c2ddSEduardo Habkost 35963f7b10bSMarc-André Lureau static void object_initialize_with_type(void *data, size_t size, TypeImpl *type) 3602f28d2ffSAnthony Liguori { 3612f28d2ffSAnthony Liguori Object *obj = data; 3622f28d2ffSAnthony Liguori 3632f28d2ffSAnthony Liguori g_assert(type != NULL); 364ac451033SIgor Mitsyanko type_initialize(type); 365aca59af6SIgor Mitsyanko 3668438a135SAndreas Färber g_assert_cmpint(type->instance_size, >=, sizeof(Object)); 3672f28d2ffSAnthony Liguori g_assert(type->abstract == false); 3688438a135SAndreas Färber g_assert_cmpint(size, >=, type->instance_size); 3692f28d2ffSAnthony Liguori 3702f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 3712f28d2ffSAnthony Liguori obj->class = type->class; 372764b6312SPaolo Bonzini object_ref(obj); 373b604a854SPavel Fedin obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal, 374b604a854SPavel Fedin NULL, object_property_free); 3752f28d2ffSAnthony Liguori object_init_with_type(obj, type); 3768231c2ddSEduardo Habkost object_post_init_with_type(obj, type); 3772f28d2ffSAnthony Liguori } 3782f28d2ffSAnthony Liguori 379213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename) 3802f28d2ffSAnthony Liguori { 3812f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 3822f28d2ffSAnthony Liguori 3835b9237f6SAndreas Färber object_initialize_with_type(data, size, type); 3842f28d2ffSAnthony Liguori } 3852f28d2ffSAnthony Liguori 3865d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop) 3875d9d3f47SAndreas Färber { 3885d9d3f47SAndreas Färber return strstart(prop->type, "child<", NULL); 3895d9d3f47SAndreas Färber } 3905d9d3f47SAndreas Färber 39157c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 39257c9fafeSAnthony Liguori { 393b604a854SPavel Fedin ObjectProperty *prop; 394b604a854SPavel Fedin GHashTableIter iter; 395b604a854SPavel Fedin gpointer key, value; 396b604a854SPavel Fedin bool released; 39757c9fafeSAnthony Liguori 398b604a854SPavel Fedin do { 399b604a854SPavel Fedin released = false; 400b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 401b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 402b604a854SPavel Fedin prop = value; 40357c9fafeSAnthony Liguori if (prop->release) { 40457c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 405b604a854SPavel Fedin prop->release = NULL; 406b604a854SPavel Fedin released = true; 407b604a854SPavel Fedin break; 40857c9fafeSAnthony Liguori } 409b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 410b604a854SPavel Fedin } 411b604a854SPavel Fedin } while (released); 41257c9fafeSAnthony Liguori 413b604a854SPavel Fedin g_hash_table_unref(obj->properties); 41457c9fafeSAnthony Liguori } 41557c9fafeSAnthony Liguori 41657c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 41757c9fafeSAnthony Liguori { 41857c9fafeSAnthony Liguori ObjectProperty *prop; 419b604a854SPavel Fedin GHashTableIter iter; 420b604a854SPavel Fedin gpointer key, value; 42157c9fafeSAnthony Liguori 422b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 423b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 424b604a854SPavel Fedin prop = value; 4255d9d3f47SAndreas Färber if (object_property_is_child(prop) && prop->opaque == child) { 426b604a854SPavel Fedin if (prop->release) { 427b604a854SPavel Fedin prop->release(obj, prop->name, prop->opaque); 428b604a854SPavel Fedin prop->release = NULL; 429b604a854SPavel Fedin } 430b604a854SPavel Fedin break; 431b604a854SPavel Fedin } 432b604a854SPavel Fedin } 433b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 434b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 435b604a854SPavel Fedin prop = value; 436b604a854SPavel Fedin if (object_property_is_child(prop) && prop->opaque == child) { 437b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 4386c1fdcf9SPaolo Bonzini break; 43957c9fafeSAnthony Liguori } 44057c9fafeSAnthony Liguori } 44157c9fafeSAnthony Liguori } 44257c9fafeSAnthony Liguori 44357c9fafeSAnthony Liguori void object_unparent(Object *obj) 44457c9fafeSAnthony Liguori { 445e998fa8dSMichael S. Tsirkin if (obj->parent) { 446e998fa8dSMichael S. Tsirkin object_property_del_child(obj->parent, obj, NULL); 447e998fa8dSMichael S. Tsirkin } 44857c9fafeSAnthony Liguori } 44957c9fafeSAnthony Liguori 4502f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 4512f28d2ffSAnthony Liguori { 4522f28d2ffSAnthony Liguori if (type->instance_finalize) { 4532f28d2ffSAnthony Liguori type->instance_finalize(obj); 4542f28d2ffSAnthony Liguori } 4552f28d2ffSAnthony Liguori 4562f28d2ffSAnthony Liguori if (type_has_parent(type)) { 4572f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 4582f28d2ffSAnthony Liguori } 4592f28d2ffSAnthony Liguori } 4602f28d2ffSAnthony Liguori 461339c2708SPaolo Bonzini static void object_finalize(void *data) 4622f28d2ffSAnthony Liguori { 4632f28d2ffSAnthony Liguori Object *obj = data; 4642f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 4652f28d2ffSAnthony Liguori 46657c9fafeSAnthony Liguori object_property_del_all(obj); 46776a6e1ccSPaolo Bonzini object_deinit(obj, ti); 468db85b575SAnthony Liguori 4698438a135SAndreas Färber g_assert_cmpint(obj->ref, ==, 0); 470fde9bf44SPaolo Bonzini if (obj->free) { 471fde9bf44SPaolo Bonzini obj->free(obj); 472fde9bf44SPaolo Bonzini } 4732f28d2ffSAnthony Liguori } 4742f28d2ffSAnthony Liguori 47563f7b10bSMarc-André Lureau static Object *object_new_with_type(Type type) 4762f28d2ffSAnthony Liguori { 4772f28d2ffSAnthony Liguori Object *obj; 4782f28d2ffSAnthony Liguori 4792f28d2ffSAnthony Liguori g_assert(type != NULL); 480ac451033SIgor Mitsyanko type_initialize(type); 4812f28d2ffSAnthony Liguori 4822f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 4835b9237f6SAndreas Färber object_initialize_with_type(obj, type->instance_size, type); 484fde9bf44SPaolo Bonzini obj->free = g_free; 4852f28d2ffSAnthony Liguori 4862f28d2ffSAnthony Liguori return obj; 4872f28d2ffSAnthony Liguori } 4882f28d2ffSAnthony Liguori 4892f28d2ffSAnthony Liguori Object *object_new(const char *typename) 4902f28d2ffSAnthony Liguori { 4912f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 4922f28d2ffSAnthony Liguori 4932f28d2ffSAnthony Liguori return object_new_with_type(ti); 4942f28d2ffSAnthony Liguori } 4952f28d2ffSAnthony Liguori 496a31bdae5SDaniel P. Berrange 497a31bdae5SDaniel P. Berrange Object *object_new_with_props(const char *typename, 498a31bdae5SDaniel P. Berrange Object *parent, 499a31bdae5SDaniel P. Berrange const char *id, 500a31bdae5SDaniel P. Berrange Error **errp, 501a31bdae5SDaniel P. Berrange ...) 502a31bdae5SDaniel P. Berrange { 503a31bdae5SDaniel P. Berrange va_list vargs; 504a31bdae5SDaniel P. Berrange Object *obj; 505a31bdae5SDaniel P. Berrange 506a31bdae5SDaniel P. Berrange va_start(vargs, errp); 507a31bdae5SDaniel P. Berrange obj = object_new_with_propv(typename, parent, id, errp, vargs); 508a31bdae5SDaniel P. Berrange va_end(vargs); 509a31bdae5SDaniel P. Berrange 510a31bdae5SDaniel P. Berrange return obj; 511a31bdae5SDaniel P. Berrange } 512a31bdae5SDaniel P. Berrange 513a31bdae5SDaniel P. Berrange 514a31bdae5SDaniel P. Berrange Object *object_new_with_propv(const char *typename, 515a31bdae5SDaniel P. Berrange Object *parent, 516a31bdae5SDaniel P. Berrange const char *id, 517a31bdae5SDaniel P. Berrange Error **errp, 518a31bdae5SDaniel P. Berrange va_list vargs) 519a31bdae5SDaniel P. Berrange { 520a31bdae5SDaniel P. Berrange Object *obj; 521a31bdae5SDaniel P. Berrange ObjectClass *klass; 522a31bdae5SDaniel P. Berrange Error *local_err = NULL; 523a31bdae5SDaniel P. Berrange 524a31bdae5SDaniel P. Berrange klass = object_class_by_name(typename); 525a31bdae5SDaniel P. Berrange if (!klass) { 526a31bdae5SDaniel P. Berrange error_setg(errp, "invalid object type: %s", typename); 527a31bdae5SDaniel P. Berrange return NULL; 528a31bdae5SDaniel P. Berrange } 529a31bdae5SDaniel P. Berrange 530a31bdae5SDaniel P. Berrange if (object_class_is_abstract(klass)) { 531a31bdae5SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", typename); 532a31bdae5SDaniel P. Berrange return NULL; 533a31bdae5SDaniel P. Berrange } 534a31bdae5SDaniel P. Berrange obj = object_new(typename); 535a31bdae5SDaniel P. Berrange 536a31bdae5SDaniel P. Berrange if (object_set_propv(obj, &local_err, vargs) < 0) { 537a31bdae5SDaniel P. Berrange goto error; 538a31bdae5SDaniel P. Berrange } 539a31bdae5SDaniel P. Berrange 540a31bdae5SDaniel P. Berrange object_property_add_child(parent, id, obj, &local_err); 541a31bdae5SDaniel P. Berrange if (local_err) { 542a31bdae5SDaniel P. Berrange goto error; 543a31bdae5SDaniel P. Berrange } 544a31bdae5SDaniel P. Berrange 545a31bdae5SDaniel P. Berrange if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { 546a31bdae5SDaniel P. Berrange user_creatable_complete(obj, &local_err); 547a31bdae5SDaniel P. Berrange if (local_err) { 548a31bdae5SDaniel P. Berrange object_unparent(obj); 549a31bdae5SDaniel P. Berrange goto error; 550a31bdae5SDaniel P. Berrange } 551a31bdae5SDaniel P. Berrange } 552a31bdae5SDaniel P. Berrange 553a31bdae5SDaniel P. Berrange object_unref(OBJECT(obj)); 554a31bdae5SDaniel P. Berrange return obj; 555a31bdae5SDaniel P. Berrange 556a31bdae5SDaniel P. Berrange error: 557a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 558a31bdae5SDaniel P. Berrange object_unref(obj); 559a31bdae5SDaniel P. Berrange return NULL; 560a31bdae5SDaniel P. Berrange } 561a31bdae5SDaniel P. Berrange 562a31bdae5SDaniel P. Berrange 563a31bdae5SDaniel P. Berrange int object_set_props(Object *obj, 564a31bdae5SDaniel P. Berrange Error **errp, 565a31bdae5SDaniel P. Berrange ...) 566a31bdae5SDaniel P. Berrange { 567a31bdae5SDaniel P. Berrange va_list vargs; 568a31bdae5SDaniel P. Berrange int ret; 569a31bdae5SDaniel P. Berrange 570a31bdae5SDaniel P. Berrange va_start(vargs, errp); 571a31bdae5SDaniel P. Berrange ret = object_set_propv(obj, errp, vargs); 572a31bdae5SDaniel P. Berrange va_end(vargs); 573a31bdae5SDaniel P. Berrange 574a31bdae5SDaniel P. Berrange return ret; 575a31bdae5SDaniel P. Berrange } 576a31bdae5SDaniel P. Berrange 577a31bdae5SDaniel P. Berrange 578a31bdae5SDaniel P. Berrange int object_set_propv(Object *obj, 579a31bdae5SDaniel P. Berrange Error **errp, 580a31bdae5SDaniel P. Berrange va_list vargs) 581a31bdae5SDaniel P. Berrange { 582a31bdae5SDaniel P. Berrange const char *propname; 583a31bdae5SDaniel P. Berrange Error *local_err = NULL; 584a31bdae5SDaniel P. Berrange 585a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 586a31bdae5SDaniel P. Berrange while (propname != NULL) { 587a31bdae5SDaniel P. Berrange const char *value = va_arg(vargs, char *); 588a31bdae5SDaniel P. Berrange 589a31bdae5SDaniel P. Berrange g_assert(value != NULL); 590a31bdae5SDaniel P. Berrange object_property_parse(obj, value, propname, &local_err); 591a31bdae5SDaniel P. Berrange if (local_err) { 592a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 593a31bdae5SDaniel P. Berrange return -1; 594a31bdae5SDaniel P. Berrange } 595a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 596a31bdae5SDaniel P. Berrange } 597a31bdae5SDaniel P. Berrange 598a31bdae5SDaniel P. Berrange return 0; 599a31bdae5SDaniel P. Berrange } 600a31bdae5SDaniel P. Berrange 601a31bdae5SDaniel P. Berrange 6022f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 6032f28d2ffSAnthony Liguori { 604b7f43fe4SPaolo Bonzini if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { 605acc4af3fSPaolo Bonzini return obj; 606acc4af3fSPaolo Bonzini } 607acc4af3fSPaolo Bonzini 6082f28d2ffSAnthony Liguori return NULL; 6092f28d2ffSAnthony Liguori } 6102f28d2ffSAnthony Liguori 611be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename, 612be17f18bSPaolo Bonzini const char *file, int line, const char *func) 6132f28d2ffSAnthony Liguori { 614fa131d94SPaolo Bonzini trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", 615fa131d94SPaolo Bonzini typename, file, line, func); 616fa131d94SPaolo Bonzini 6173556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG 61803587328SAnthony Liguori int i; 61903587328SAnthony Liguori Object *inst; 62003587328SAnthony Liguori 62195916abcSPeter Crosthwaite for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { 622b6b3ccfdSAlex Bennée if (atomic_read(&obj->class->object_cast_cache[i]) == typename) { 62303587328SAnthony Liguori goto out; 62403587328SAnthony Liguori } 62503587328SAnthony Liguori } 62603587328SAnthony Liguori 62703587328SAnthony Liguori inst = object_dynamic_cast(obj, typename); 6282f28d2ffSAnthony Liguori 629b7f43fe4SPaolo Bonzini if (!inst && obj) { 630be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 631be17f18bSPaolo Bonzini file, line, func, obj, typename); 6322f28d2ffSAnthony Liguori abort(); 6332f28d2ffSAnthony Liguori } 6342f28d2ffSAnthony Liguori 6353556c233SPaolo Bonzini assert(obj == inst); 63603587328SAnthony Liguori 63795916abcSPeter Crosthwaite if (obj && obj == inst) { 63803587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 639b6b3ccfdSAlex Bennée atomic_set(&obj->class->object_cast_cache[i - 1], 640b6b3ccfdSAlex Bennée atomic_read(&obj->class->object_cast_cache[i])); 64103587328SAnthony Liguori } 642b6b3ccfdSAlex Bennée atomic_set(&obj->class->object_cast_cache[i - 1], typename); 64303587328SAnthony Liguori } 64403587328SAnthony Liguori 64503587328SAnthony Liguori out: 6463556c233SPaolo Bonzini #endif 6473556c233SPaolo Bonzini return obj; 6482f28d2ffSAnthony Liguori } 6492f28d2ffSAnthony Liguori 6502f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 6512f28d2ffSAnthony Liguori const char *typename) 6522f28d2ffSAnthony Liguori { 65333e95c63SAnthony Liguori ObjectClass *ret = NULL; 654bf0fda34SPaolo Bonzini TypeImpl *target_type; 655bf0fda34SPaolo Bonzini TypeImpl *type; 6562f28d2ffSAnthony Liguori 657bf0fda34SPaolo Bonzini if (!class) { 658bf0fda34SPaolo Bonzini return NULL; 659bf0fda34SPaolo Bonzini } 660bf0fda34SPaolo Bonzini 661793c96b5SPaolo Bonzini /* A simple fast path that can trigger a lot for leaf classes. */ 662bf0fda34SPaolo Bonzini type = class->type; 663793c96b5SPaolo Bonzini if (type->name == typename) { 664793c96b5SPaolo Bonzini return class; 665793c96b5SPaolo Bonzini } 666793c96b5SPaolo Bonzini 667bf0fda34SPaolo Bonzini target_type = type_get_by_name(typename); 6689ab880b3SAlexander Graf if (!target_type) { 6699ab880b3SAlexander Graf /* target class type unknown, so fail the cast */ 6709ab880b3SAlexander Graf return NULL; 6719ab880b3SAlexander Graf } 6729ab880b3SAlexander Graf 67300e2ceaeSPeter Crosthwaite if (type->class->interfaces && 67400e2ceaeSPeter Crosthwaite type_is_ancestor(target_type, type_interface)) { 67533e95c63SAnthony Liguori int found = 0; 67633e95c63SAnthony Liguori GSList *i; 67733e95c63SAnthony Liguori 67833e95c63SAnthony Liguori for (i = class->interfaces; i; i = i->next) { 67933e95c63SAnthony Liguori ObjectClass *target_class = i->data; 68033e95c63SAnthony Liguori 68133e95c63SAnthony Liguori if (type_is_ancestor(target_class->type, target_type)) { 68233e95c63SAnthony Liguori ret = target_class; 68333e95c63SAnthony Liguori found++; 68433e95c63SAnthony Liguori } 6852f28d2ffSAnthony Liguori } 6862f28d2ffSAnthony Liguori 68733e95c63SAnthony Liguori /* The match was ambiguous, don't allow a cast */ 68833e95c63SAnthony Liguori if (found > 1) { 68933e95c63SAnthony Liguori ret = NULL; 69033e95c63SAnthony Liguori } 69133e95c63SAnthony Liguori } else if (type_is_ancestor(type, target_type)) { 69233e95c63SAnthony Liguori ret = class; 6932f28d2ffSAnthony Liguori } 6942f28d2ffSAnthony Liguori 69533e95c63SAnthony Liguori return ret; 6962f28d2ffSAnthony Liguori } 6972f28d2ffSAnthony Liguori 6982f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 699be17f18bSPaolo Bonzini const char *typename, 700be17f18bSPaolo Bonzini const char *file, int line, 701be17f18bSPaolo Bonzini const char *func) 7022f28d2ffSAnthony Liguori { 703fa131d94SPaolo Bonzini ObjectClass *ret; 7042f28d2ffSAnthony Liguori 705fa131d94SPaolo Bonzini trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", 706fa131d94SPaolo Bonzini typename, file, line, func); 707fa131d94SPaolo Bonzini 70803587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 70903587328SAnthony Liguori int i; 71003587328SAnthony Liguori 7119d6a3d58SPeter Crosthwaite for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { 712b6b3ccfdSAlex Bennée if (atomic_read(&class->class_cast_cache[i]) == typename) { 71303587328SAnthony Liguori ret = class; 71403587328SAnthony Liguori goto out; 71503587328SAnthony Liguori } 71603587328SAnthony Liguori } 71703587328SAnthony Liguori #else 7189d6a3d58SPeter Crosthwaite if (!class || !class->interfaces) { 7193556c233SPaolo Bonzini return class; 7203556c233SPaolo Bonzini } 7213556c233SPaolo Bonzini #endif 7223556c233SPaolo Bonzini 723fa131d94SPaolo Bonzini ret = object_class_dynamic_cast(class, typename); 724bf0fda34SPaolo Bonzini if (!ret && class) { 725be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 726be17f18bSPaolo Bonzini file, line, func, class, typename); 7272f28d2ffSAnthony Liguori abort(); 7282f28d2ffSAnthony Liguori } 7292f28d2ffSAnthony Liguori 73003587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 7319d6a3d58SPeter Crosthwaite if (class && ret == class) { 73203587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 733b6b3ccfdSAlex Bennée atomic_set(&class->class_cast_cache[i - 1], 734b6b3ccfdSAlex Bennée atomic_read(&class->class_cast_cache[i])); 73503587328SAnthony Liguori } 736b6b3ccfdSAlex Bennée atomic_set(&class->class_cast_cache[i - 1], typename); 73703587328SAnthony Liguori } 73803587328SAnthony Liguori out: 73903587328SAnthony Liguori #endif 7402f28d2ffSAnthony Liguori return ret; 7412f28d2ffSAnthony Liguori } 7422f28d2ffSAnthony Liguori 7438f5d58efSIgor Mammedov const char *object_get_typename(const Object *obj) 7442f28d2ffSAnthony Liguori { 7452f28d2ffSAnthony Liguori return obj->class->type->name; 7462f28d2ffSAnthony Liguori } 7472f28d2ffSAnthony Liguori 7482f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 7492f28d2ffSAnthony Liguori { 7502f28d2ffSAnthony Liguori return obj->class; 7512f28d2ffSAnthony Liguori } 7522f28d2ffSAnthony Liguori 75317862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass) 75417862378SAndreas Färber { 75517862378SAndreas Färber return klass->type->abstract; 75617862378SAndreas Färber } 75717862378SAndreas Färber 7582f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 7592f28d2ffSAnthony Liguori { 7602f28d2ffSAnthony Liguori return klass->type->name; 7612f28d2ffSAnthony Liguori } 7622f28d2ffSAnthony Liguori 7632f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 7642f28d2ffSAnthony Liguori { 7652f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 7662f28d2ffSAnthony Liguori 7672f28d2ffSAnthony Liguori if (!type) { 7682f28d2ffSAnthony Liguori return NULL; 7692f28d2ffSAnthony Liguori } 7702f28d2ffSAnthony Liguori 771ac451033SIgor Mitsyanko type_initialize(type); 7722f28d2ffSAnthony Liguori 7732f28d2ffSAnthony Liguori return type->class; 7742f28d2ffSAnthony Liguori } 7752f28d2ffSAnthony Liguori 776e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class) 777e7cce67fSPaolo Bonzini { 778e7cce67fSPaolo Bonzini TypeImpl *type = type_get_parent(class->type); 779e7cce67fSPaolo Bonzini 780e7cce67fSPaolo Bonzini if (!type) { 781e7cce67fSPaolo Bonzini return NULL; 782e7cce67fSPaolo Bonzini } 783e7cce67fSPaolo Bonzini 784e7cce67fSPaolo Bonzini type_initialize(type); 785e7cce67fSPaolo Bonzini 786e7cce67fSPaolo Bonzini return type->class; 787e7cce67fSPaolo Bonzini } 788e7cce67fSPaolo Bonzini 7892f28d2ffSAnthony Liguori typedef struct OCFData 7902f28d2ffSAnthony Liguori { 7912f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 79293c511a1SAnthony Liguori const char *implements_type; 79393c511a1SAnthony Liguori bool include_abstract; 7942f28d2ffSAnthony Liguori void *opaque; 7952f28d2ffSAnthony Liguori } OCFData; 7962f28d2ffSAnthony Liguori 7972f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 7982f28d2ffSAnthony Liguori gpointer opaque) 7992f28d2ffSAnthony Liguori { 8002f28d2ffSAnthony Liguori OCFData *data = opaque; 8012f28d2ffSAnthony Liguori TypeImpl *type = value; 80293c511a1SAnthony Liguori ObjectClass *k; 8032f28d2ffSAnthony Liguori 804ac451033SIgor Mitsyanko type_initialize(type); 80593c511a1SAnthony Liguori k = type->class; 8062f28d2ffSAnthony Liguori 80793c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 80893c511a1SAnthony Liguori return; 80993c511a1SAnthony Liguori } 81093c511a1SAnthony Liguori 81193c511a1SAnthony Liguori if (data->implements_type && 81293c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 81393c511a1SAnthony Liguori return; 81493c511a1SAnthony Liguori } 81593c511a1SAnthony Liguori 81693c511a1SAnthony Liguori data->fn(k, data->opaque); 8172f28d2ffSAnthony Liguori } 8182f28d2ffSAnthony Liguori 8192f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 82093c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 8212f28d2ffSAnthony Liguori void *opaque) 8222f28d2ffSAnthony Liguori { 82393c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 8242f28d2ffSAnthony Liguori 825f54c19caSHervé Poussineau enumerating_types = true; 8262f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 827f54c19caSHervé Poussineau enumerating_types = false; 8282f28d2ffSAnthony Liguori } 82957c9fafeSAnthony Liguori 830d714b8deSPeter Crosthwaite static int do_object_child_foreach(Object *obj, 831d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 832d714b8deSPeter Crosthwaite void *opaque, bool recurse) 83332efc535SPaolo Bonzini { 834b604a854SPavel Fedin GHashTableIter iter; 835b604a854SPavel Fedin ObjectProperty *prop; 83632efc535SPaolo Bonzini int ret = 0; 83732efc535SPaolo Bonzini 838b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 839b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 84032efc535SPaolo Bonzini if (object_property_is_child(prop)) { 841d714b8deSPeter Crosthwaite Object *child = prop->opaque; 842d714b8deSPeter Crosthwaite 843d714b8deSPeter Crosthwaite ret = fn(child, opaque); 84432efc535SPaolo Bonzini if (ret != 0) { 84532efc535SPaolo Bonzini break; 84632efc535SPaolo Bonzini } 847d714b8deSPeter Crosthwaite if (recurse) { 848d714b8deSPeter Crosthwaite do_object_child_foreach(child, fn, opaque, true); 849d714b8deSPeter Crosthwaite } 85032efc535SPaolo Bonzini } 85132efc535SPaolo Bonzini } 85232efc535SPaolo Bonzini return ret; 85332efc535SPaolo Bonzini } 85432efc535SPaolo Bonzini 855d714b8deSPeter Crosthwaite int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), 856d714b8deSPeter Crosthwaite void *opaque) 857d714b8deSPeter Crosthwaite { 858d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, false); 859d714b8deSPeter Crosthwaite } 860d714b8deSPeter Crosthwaite 861d714b8deSPeter Crosthwaite int object_child_foreach_recursive(Object *obj, 862d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 863d714b8deSPeter Crosthwaite void *opaque) 864d714b8deSPeter Crosthwaite { 865d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, true); 866d714b8deSPeter Crosthwaite } 867d714b8deSPeter Crosthwaite 868418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 869418ba9e5SAndreas Färber { 870418ba9e5SAndreas Färber GSList **list = opaque; 871418ba9e5SAndreas Färber 872418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 873418ba9e5SAndreas Färber } 874418ba9e5SAndreas Färber 875418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 876418ba9e5SAndreas Färber bool include_abstract) 877418ba9e5SAndreas Färber { 878418ba9e5SAndreas Färber GSList *list = NULL; 879418ba9e5SAndreas Färber 880418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 881418ba9e5SAndreas Färber implements_type, include_abstract, &list); 882418ba9e5SAndreas Färber return list; 883418ba9e5SAndreas Färber } 884418ba9e5SAndreas Färber 88557c9fafeSAnthony Liguori void object_ref(Object *obj) 88657c9fafeSAnthony Liguori { 8878ffad850SPeter Crosthwaite if (!obj) { 8888ffad850SPeter Crosthwaite return; 8898ffad850SPeter Crosthwaite } 890f08c03f3SJan Kiszka atomic_inc(&obj->ref); 89157c9fafeSAnthony Liguori } 89257c9fafeSAnthony Liguori 89357c9fafeSAnthony Liguori void object_unref(Object *obj) 89457c9fafeSAnthony Liguori { 8958ffad850SPeter Crosthwaite if (!obj) { 8968ffad850SPeter Crosthwaite return; 8978ffad850SPeter Crosthwaite } 8988438a135SAndreas Färber g_assert_cmpint(obj->ref, >, 0); 89957c9fafeSAnthony Liguori 90057c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 901f08c03f3SJan Kiszka if (atomic_fetch_dec(&obj->ref) == 1) { 90257c9fafeSAnthony Liguori object_finalize(obj); 90357c9fafeSAnthony Liguori } 90457c9fafeSAnthony Liguori } 90557c9fafeSAnthony Liguori 90664607d08SPaolo Bonzini ObjectProperty * 90764607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type, 90857c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 90957c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 91057c9fafeSAnthony Liguori ObjectPropertyRelease *release, 91157c9fafeSAnthony Liguori void *opaque, Error **errp) 91257c9fafeSAnthony Liguori { 91354852b03SPeter Maydell ObjectProperty *prop; 91433965904SPeter Crosthwaite size_t name_len = strlen(name); 91533965904SPeter Crosthwaite 91633965904SPeter Crosthwaite if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { 91733965904SPeter Crosthwaite int i; 91833965904SPeter Crosthwaite ObjectProperty *ret; 91933965904SPeter Crosthwaite char *name_no_array = g_strdup(name); 92033965904SPeter Crosthwaite 92133965904SPeter Crosthwaite name_no_array[name_len - 3] = '\0'; 92233965904SPeter Crosthwaite for (i = 0; ; ++i) { 92333965904SPeter Crosthwaite char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); 92433965904SPeter Crosthwaite 92533965904SPeter Crosthwaite ret = object_property_add(obj, full_name, type, get, set, 92633965904SPeter Crosthwaite release, opaque, NULL); 92733965904SPeter Crosthwaite g_free(full_name); 92833965904SPeter Crosthwaite if (ret) { 92933965904SPeter Crosthwaite break; 93033965904SPeter Crosthwaite } 93133965904SPeter Crosthwaite } 93233965904SPeter Crosthwaite g_free(name_no_array); 93333965904SPeter Crosthwaite return ret; 93433965904SPeter Crosthwaite } 93554852b03SPeter Maydell 93616bf7f52SDaniel P. Berrange if (object_property_find(obj, name, NULL) != NULL) { 93754852b03SPeter Maydell error_setg(errp, "attempt to add duplicate property '%s'" 93854852b03SPeter Maydell " to object (type '%s')", name, 93954852b03SPeter Maydell object_get_typename(obj)); 94064607d08SPaolo Bonzini return NULL; 94154852b03SPeter Maydell } 94254852b03SPeter Maydell 94354852b03SPeter Maydell prop = g_malloc0(sizeof(*prop)); 94457c9fafeSAnthony Liguori 94557c9fafeSAnthony Liguori prop->name = g_strdup(name); 94657c9fafeSAnthony Liguori prop->type = g_strdup(type); 94757c9fafeSAnthony Liguori 94857c9fafeSAnthony Liguori prop->get = get; 94957c9fafeSAnthony Liguori prop->set = set; 95057c9fafeSAnthony Liguori prop->release = release; 95157c9fafeSAnthony Liguori prop->opaque = opaque; 95257c9fafeSAnthony Liguori 953b604a854SPavel Fedin g_hash_table_insert(obj->properties, prop->name, prop); 95464607d08SPaolo Bonzini return prop; 95557c9fafeSAnthony Liguori } 95657c9fafeSAnthony Liguori 95716bf7f52SDaniel P. Berrange ObjectProperty * 95816bf7f52SDaniel P. Berrange object_class_property_add(ObjectClass *klass, 95916bf7f52SDaniel P. Berrange const char *name, 96016bf7f52SDaniel P. Berrange const char *type, 96116bf7f52SDaniel P. Berrange ObjectPropertyAccessor *get, 96216bf7f52SDaniel P. Berrange ObjectPropertyAccessor *set, 96316bf7f52SDaniel P. Berrange ObjectPropertyRelease *release, 96416bf7f52SDaniel P. Berrange void *opaque, 96516bf7f52SDaniel P. Berrange Error **errp) 96616bf7f52SDaniel P. Berrange { 96716bf7f52SDaniel P. Berrange ObjectProperty *prop; 96816bf7f52SDaniel P. Berrange 96916bf7f52SDaniel P. Berrange if (object_class_property_find(klass, name, NULL) != NULL) { 97016bf7f52SDaniel P. Berrange error_setg(errp, "attempt to add duplicate property '%s'" 97116bf7f52SDaniel P. Berrange " to object (type '%s')", name, 97216bf7f52SDaniel P. Berrange object_class_get_name(klass)); 97316bf7f52SDaniel P. Berrange return NULL; 97416bf7f52SDaniel P. Berrange } 97516bf7f52SDaniel P. Berrange 97616bf7f52SDaniel P. Berrange prop = g_malloc0(sizeof(*prop)); 97716bf7f52SDaniel P. Berrange 97816bf7f52SDaniel P. Berrange prop->name = g_strdup(name); 97916bf7f52SDaniel P. Berrange prop->type = g_strdup(type); 98016bf7f52SDaniel P. Berrange 98116bf7f52SDaniel P. Berrange prop->get = get; 98216bf7f52SDaniel P. Berrange prop->set = set; 98316bf7f52SDaniel P. Berrange prop->release = release; 98416bf7f52SDaniel P. Berrange prop->opaque = opaque; 98516bf7f52SDaniel P. Berrange 98616bf7f52SDaniel P. Berrange g_hash_table_insert(klass->properties, g_strdup(name), prop); 98716bf7f52SDaniel P. Berrange 98816bf7f52SDaniel P. Berrange return prop; 98916bf7f52SDaniel P. Berrange } 99016bf7f52SDaniel P. Berrange 99189bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name, 99289bfe000SPaolo Bonzini Error **errp) 99357c9fafeSAnthony Liguori { 99457c9fafeSAnthony Liguori ObjectProperty *prop; 99516bf7f52SDaniel P. Berrange ObjectClass *klass = object_get_class(obj); 99616bf7f52SDaniel P. Berrange 99716bf7f52SDaniel P. Berrange prop = object_class_property_find(klass, name, NULL); 99816bf7f52SDaniel P. Berrange if (prop) { 99916bf7f52SDaniel P. Berrange return prop; 100016bf7f52SDaniel P. Berrange } 100157c9fafeSAnthony Liguori 1002b604a854SPavel Fedin prop = g_hash_table_lookup(obj->properties, name); 1003b604a854SPavel Fedin if (prop) { 100457c9fafeSAnthony Liguori return prop; 100557c9fafeSAnthony Liguori } 100657c9fafeSAnthony Liguori 1007f231b88dSCole Robinson error_setg(errp, "Property '.%s' not found", name); 100857c9fafeSAnthony Liguori return NULL; 100957c9fafeSAnthony Liguori } 101057c9fafeSAnthony Liguori 10117746abd8SDaniel P. Berrange void object_property_iter_init(ObjectPropertyIterator *iter, 10127746abd8SDaniel P. Berrange Object *obj) 1013a00c9482SDaniel P. Berrange { 10147746abd8SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, obj->properties); 10157746abd8SDaniel P. Berrange iter->nextclass = object_get_class(obj); 1016a00c9482SDaniel P. Berrange } 1017a00c9482SDaniel P. Berrange 1018a00c9482SDaniel P. Berrange ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) 1019a00c9482SDaniel P. Berrange { 1020b604a854SPavel Fedin gpointer key, val; 102116bf7f52SDaniel P. Berrange while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { 102216bf7f52SDaniel P. Berrange if (!iter->nextclass) { 1023b604a854SPavel Fedin return NULL; 1024a00c9482SDaniel P. Berrange } 102516bf7f52SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, iter->nextclass->properties); 102616bf7f52SDaniel P. Berrange iter->nextclass = object_class_get_parent(iter->nextclass); 102716bf7f52SDaniel P. Berrange } 1028b604a854SPavel Fedin return val; 1029a00c9482SDaniel P. Berrange } 1030a00c9482SDaniel P. Berrange 103116bf7f52SDaniel P. Berrange ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, 103216bf7f52SDaniel P. Berrange Error **errp) 103316bf7f52SDaniel P. Berrange { 103416bf7f52SDaniel P. Berrange ObjectProperty *prop; 103516bf7f52SDaniel P. Berrange ObjectClass *parent_klass; 103616bf7f52SDaniel P. Berrange 103716bf7f52SDaniel P. Berrange parent_klass = object_class_get_parent(klass); 103816bf7f52SDaniel P. Berrange if (parent_klass) { 103916bf7f52SDaniel P. Berrange prop = object_class_property_find(parent_klass, name, NULL); 104016bf7f52SDaniel P. Berrange if (prop) { 104116bf7f52SDaniel P. Berrange return prop; 104216bf7f52SDaniel P. Berrange } 104316bf7f52SDaniel P. Berrange } 104416bf7f52SDaniel P. Berrange 104516bf7f52SDaniel P. Berrange prop = g_hash_table_lookup(klass->properties, name); 104616bf7f52SDaniel P. Berrange if (!prop) { 104716bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 104816bf7f52SDaniel P. Berrange } 104916bf7f52SDaniel P. Berrange return prop; 105016bf7f52SDaniel P. Berrange } 105116bf7f52SDaniel P. Berrange 105257c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 105357c9fafeSAnthony Liguori { 1054b604a854SPavel Fedin ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); 1055b604a854SPavel Fedin 1056b604a854SPavel Fedin if (!prop) { 1057b604a854SPavel Fedin error_setg(errp, "Property '.%s' not found", name); 10580866aca1SAnthony Liguori return; 10590866aca1SAnthony Liguori } 106057c9fafeSAnthony Liguori 10610866aca1SAnthony Liguori if (prop->release) { 10620866aca1SAnthony Liguori prop->release(obj, name, prop->opaque); 10630866aca1SAnthony Liguori } 1064b604a854SPavel Fedin g_hash_table_remove(obj->properties, name); 106557c9fafeSAnthony Liguori } 106657c9fafeSAnthony Liguori 106757c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 106857c9fafeSAnthony Liguori Error **errp) 106957c9fafeSAnthony Liguori { 107089bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 107157c9fafeSAnthony Liguori if (prop == NULL) { 107257c9fafeSAnthony Liguori return; 107357c9fafeSAnthony Liguori } 107457c9fafeSAnthony Liguori 107557c9fafeSAnthony Liguori if (!prop->get) { 1076c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 107757c9fafeSAnthony Liguori } else { 1078d7bce999SEric Blake prop->get(obj, v, name, prop->opaque, errp); 107957c9fafeSAnthony Liguori } 108057c9fafeSAnthony Liguori } 108157c9fafeSAnthony Liguori 108257c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 108357c9fafeSAnthony Liguori Error **errp) 108457c9fafeSAnthony Liguori { 108589bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 108657c9fafeSAnthony Liguori if (prop == NULL) { 108757c9fafeSAnthony Liguori return; 108857c9fafeSAnthony Liguori } 108957c9fafeSAnthony Liguori 109057c9fafeSAnthony Liguori if (!prop->set) { 1091c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 109257c9fafeSAnthony Liguori } else { 1093d7bce999SEric Blake prop->set(obj, v, name, prop->opaque, errp); 109457c9fafeSAnthony Liguori } 109557c9fafeSAnthony Liguori } 109657c9fafeSAnthony Liguori 10977b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 10987b7b7d18SPaolo Bonzini const char *name, Error **errp) 10997b7b7d18SPaolo Bonzini { 11007b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 11017b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 11027b7b7d18SPaolo Bonzini 11037b7b7d18SPaolo Bonzini QDECREF(qstr); 11047b7b7d18SPaolo Bonzini } 11057b7b7d18SPaolo Bonzini 11067b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 11077b7b7d18SPaolo Bonzini Error **errp) 11087b7b7d18SPaolo Bonzini { 11097b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11107b7b7d18SPaolo Bonzini QString *qstring; 11117b7b7d18SPaolo Bonzini char *retval; 11127b7b7d18SPaolo Bonzini 11137b7b7d18SPaolo Bonzini if (!ret) { 11147b7b7d18SPaolo Bonzini return NULL; 11157b7b7d18SPaolo Bonzini } 11167b7b7d18SPaolo Bonzini qstring = qobject_to_qstring(ret); 11177b7b7d18SPaolo Bonzini if (!qstring) { 1118c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 11197b7b7d18SPaolo Bonzini retval = NULL; 11207b7b7d18SPaolo Bonzini } else { 11217b7b7d18SPaolo Bonzini retval = g_strdup(qstring_get_str(qstring)); 11227b7b7d18SPaolo Bonzini } 11237b7b7d18SPaolo Bonzini 1124560f19f1SMarc-André Lureau qobject_decref(ret); 11257b7b7d18SPaolo Bonzini return retval; 11267b7b7d18SPaolo Bonzini } 11277b7b7d18SPaolo Bonzini 11281d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 11291d9c5a12SPaolo Bonzini const char *name, Error **errp) 11301d9c5a12SPaolo Bonzini { 1131d3c49316SPeter Crosthwaite if (value) { 11322d3aa28cSVlad Yasevich gchar *path = object_get_canonical_path(value); 11332d3aa28cSVlad Yasevich object_property_set_str(obj, path, name, errp); 11342d3aa28cSVlad Yasevich g_free(path); 1135d3c49316SPeter Crosthwaite } else { 1136d3c49316SPeter Crosthwaite object_property_set_str(obj, "", name, errp); 1137d3c49316SPeter Crosthwaite } 11381d9c5a12SPaolo Bonzini } 11391d9c5a12SPaolo Bonzini 11401d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 11411d9c5a12SPaolo Bonzini Error **errp) 11421d9c5a12SPaolo Bonzini { 11431d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 11441d9c5a12SPaolo Bonzini Object *target = NULL; 11451d9c5a12SPaolo Bonzini 11461d9c5a12SPaolo Bonzini if (str && *str) { 11471d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 11481d9c5a12SPaolo Bonzini if (!target) { 114975158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 115075158ebbSMarkus Armbruster "Device '%s' not found", str); 11511d9c5a12SPaolo Bonzini } 11521d9c5a12SPaolo Bonzini } 11531d9c5a12SPaolo Bonzini 11541d9c5a12SPaolo Bonzini g_free(str); 11551d9c5a12SPaolo Bonzini return target; 11561d9c5a12SPaolo Bonzini } 11571d9c5a12SPaolo Bonzini 11587b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 11597b7b7d18SPaolo Bonzini const char *name, Error **errp) 11607b7b7d18SPaolo Bonzini { 1161fc48ffc3SEric Blake QBool *qbool = qbool_from_bool(value); 11627b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 11637b7b7d18SPaolo Bonzini 11647b7b7d18SPaolo Bonzini QDECREF(qbool); 11657b7b7d18SPaolo Bonzini } 11667b7b7d18SPaolo Bonzini 11677b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 11687b7b7d18SPaolo Bonzini Error **errp) 11697b7b7d18SPaolo Bonzini { 11707b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11717b7b7d18SPaolo Bonzini QBool *qbool; 11727b7b7d18SPaolo Bonzini bool retval; 11737b7b7d18SPaolo Bonzini 11747b7b7d18SPaolo Bonzini if (!ret) { 11757b7b7d18SPaolo Bonzini return false; 11767b7b7d18SPaolo Bonzini } 11777b7b7d18SPaolo Bonzini qbool = qobject_to_qbool(ret); 11787b7b7d18SPaolo Bonzini if (!qbool) { 1179c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 11807b7b7d18SPaolo Bonzini retval = false; 11817b7b7d18SPaolo Bonzini } else { 1182fc48ffc3SEric Blake retval = qbool_get_bool(qbool); 11837b7b7d18SPaolo Bonzini } 11847b7b7d18SPaolo Bonzini 1185560f19f1SMarc-André Lureau qobject_decref(ret); 11867b7b7d18SPaolo Bonzini return retval; 11877b7b7d18SPaolo Bonzini } 11887b7b7d18SPaolo Bonzini 11897b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 11907b7b7d18SPaolo Bonzini const char *name, Error **errp) 11917b7b7d18SPaolo Bonzini { 119201b2ffceSMarc-André Lureau QNum *qnum = qnum_from_int(value); 119301b2ffceSMarc-André Lureau object_property_set_qobject(obj, QOBJECT(qnum), name, errp); 11947b7b7d18SPaolo Bonzini 119501b2ffceSMarc-André Lureau QDECREF(qnum); 11967b7b7d18SPaolo Bonzini } 11977b7b7d18SPaolo Bonzini 11987b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 11997b7b7d18SPaolo Bonzini Error **errp) 12007b7b7d18SPaolo Bonzini { 12017b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 120201b2ffceSMarc-André Lureau QNum *qnum; 12037b7b7d18SPaolo Bonzini int64_t retval; 12047b7b7d18SPaolo Bonzini 12057b7b7d18SPaolo Bonzini if (!ret) { 12067b7b7d18SPaolo Bonzini return -1; 12077b7b7d18SPaolo Bonzini } 120801b2ffceSMarc-André Lureau 120901b2ffceSMarc-André Lureau qnum = qobject_to_qnum(ret); 121001b2ffceSMarc-André Lureau if (!qnum || !qnum_get_try_int(qnum, &retval)) { 1211c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 12127b7b7d18SPaolo Bonzini retval = -1; 12137b7b7d18SPaolo Bonzini } 12147b7b7d18SPaolo Bonzini 1215560f19f1SMarc-André Lureau qobject_decref(ret); 12167b7b7d18SPaolo Bonzini return retval; 12177b7b7d18SPaolo Bonzini } 12187b7b7d18SPaolo Bonzini 12193152779cSMarc-André Lureau void object_property_set_uint(Object *obj, uint64_t value, 12203152779cSMarc-André Lureau const char *name, Error **errp) 12213152779cSMarc-André Lureau { 12223152779cSMarc-André Lureau QNum *qnum = qnum_from_uint(value); 12233152779cSMarc-André Lureau 12243152779cSMarc-André Lureau object_property_set_qobject(obj, QOBJECT(qnum), name, errp); 12253152779cSMarc-André Lureau QDECREF(qnum); 12263152779cSMarc-André Lureau } 12273152779cSMarc-André Lureau 12283152779cSMarc-André Lureau uint64_t object_property_get_uint(Object *obj, const char *name, 12293152779cSMarc-André Lureau Error **errp) 12303152779cSMarc-André Lureau { 12313152779cSMarc-André Lureau QObject *ret = object_property_get_qobject(obj, name, errp); 12323152779cSMarc-André Lureau QNum *qnum; 12333152779cSMarc-André Lureau uint64_t retval; 12343152779cSMarc-André Lureau 12353152779cSMarc-André Lureau if (!ret) { 12363152779cSMarc-André Lureau return 0; 12373152779cSMarc-André Lureau } 12383152779cSMarc-André Lureau qnum = qobject_to_qnum(ret); 12393152779cSMarc-André Lureau if (!qnum || !qnum_get_try_uint(qnum, &retval)) { 12403152779cSMarc-André Lureau error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "uint"); 12413152779cSMarc-André Lureau retval = 0; 12423152779cSMarc-André Lureau } 12433152779cSMarc-André Lureau 12443152779cSMarc-André Lureau qobject_decref(ret); 12453152779cSMarc-André Lureau return retval; 12463152779cSMarc-André Lureau } 12473152779cSMarc-André Lureau 1248a8e3fbedSDaniel P. Berrange typedef struct EnumProperty { 1249f7abe0ecSMarc-André Lureau const QEnumLookup *lookup; 1250a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **); 1251a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **); 1252a8e3fbedSDaniel P. Berrange } EnumProperty; 1253a8e3fbedSDaniel P. Berrange 12541f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name, 1255a3590dacSDaniel P. Berrange const char *typename, Error **errp) 12561f21772dSHu Tao { 12574715d42eSMarkus Armbruster Error *err = NULL; 12587a0525c7SEric Blake Visitor *v; 1259976620acSChen Fan char *str; 12601f21772dSHu Tao int ret; 1261a3590dacSDaniel P. Berrange ObjectProperty *prop = object_property_find(obj, name, errp); 1262a3590dacSDaniel P. Berrange EnumProperty *enumprop; 1263a3590dacSDaniel P. Berrange 1264a3590dacSDaniel P. Berrange if (prop == NULL) { 1265a3590dacSDaniel P. Berrange return 0; 1266a3590dacSDaniel P. Berrange } 1267a3590dacSDaniel P. Berrange 1268a3590dacSDaniel P. Berrange if (!g_str_equal(prop->type, typename)) { 1269a3590dacSDaniel P. Berrange error_setg(errp, "Property %s on %s is not '%s' enum type", 1270a3590dacSDaniel P. Berrange name, object_class_get_name( 1271a3590dacSDaniel P. Berrange object_get_class(obj)), typename); 1272a3590dacSDaniel P. Berrange return 0; 1273a3590dacSDaniel P. Berrange } 1274a3590dacSDaniel P. Berrange 1275a3590dacSDaniel P. Berrange enumprop = prop->opaque; 12761f21772dSHu Tao 12773b098d56SEric Blake v = string_output_visitor_new(false, &str); 1278e7ca5656SEric Blake object_property_get(obj, v, name, &err); 12794715d42eSMarkus Armbruster if (err) { 12804715d42eSMarkus Armbruster error_propagate(errp, err); 1281e7ca5656SEric Blake visit_free(v); 12824715d42eSMarkus Armbruster return 0; 12834715d42eSMarkus Armbruster } 12843b098d56SEric Blake visit_complete(v, &str); 1285e7ca5656SEric Blake visit_free(v); 12867a0525c7SEric Blake v = string_input_visitor_new(str); 1287f7abe0ecSMarc-André Lureau visit_type_enum(v, name, &ret, enumprop->lookup, errp); 1288976620acSChen Fan 1289976620acSChen Fan g_free(str); 12907a0525c7SEric Blake visit_free(v); 12911f21772dSHu Tao 12921f21772dSHu Tao return ret; 12931f21772dSHu Tao } 12941f21772dSHu Tao 12951f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name, 12961f21772dSHu Tao uint16List **list, Error **errp) 12971f21772dSHu Tao { 12984715d42eSMarkus Armbruster Error *err = NULL; 12997a0525c7SEric Blake Visitor *v; 1300976620acSChen Fan char *str; 13011f21772dSHu Tao 13023b098d56SEric Blake v = string_output_visitor_new(false, &str); 13033b098d56SEric Blake object_property_get(obj, v, name, &err); 13044715d42eSMarkus Armbruster if (err) { 13054715d42eSMarkus Armbruster error_propagate(errp, err); 13064715d42eSMarkus Armbruster goto out; 13074715d42eSMarkus Armbruster } 13083b098d56SEric Blake visit_complete(v, &str); 13093b098d56SEric Blake visit_free(v); 13107a0525c7SEric Blake v = string_input_visitor_new(str); 13117a0525c7SEric Blake visit_type_uint16List(v, NULL, list, errp); 1312976620acSChen Fan 1313976620acSChen Fan g_free(str); 13144715d42eSMarkus Armbruster out: 13153b098d56SEric Blake visit_free(v); 13161f21772dSHu Tao } 13171f21772dSHu Tao 1318b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 1319b2cd7deeSPaolo Bonzini const char *name, Error **errp) 1320b2cd7deeSPaolo Bonzini { 13217a0525c7SEric Blake Visitor *v = string_input_visitor_new(string); 13227a0525c7SEric Blake object_property_set(obj, v, name, errp); 13237a0525c7SEric Blake visit_free(v); 1324b2cd7deeSPaolo Bonzini } 1325b2cd7deeSPaolo Bonzini 13260b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human, 1327b2cd7deeSPaolo Bonzini Error **errp) 1328b2cd7deeSPaolo Bonzini { 13293b098d56SEric Blake Visitor *v; 13303a53009fSGonglei char *string = NULL; 13313a53009fSGonglei Error *local_err = NULL; 1332b2cd7deeSPaolo Bonzini 13333b098d56SEric Blake v = string_output_visitor_new(human, &string); 13343b098d56SEric Blake object_property_get(obj, v, name, &local_err); 13353a53009fSGonglei if (local_err) { 13363a53009fSGonglei error_propagate(errp, local_err); 13373a53009fSGonglei goto out; 13383a53009fSGonglei } 13393a53009fSGonglei 13403b098d56SEric Blake visit_complete(v, &string); 13413a53009fSGonglei 13423a53009fSGonglei out: 13433b098d56SEric Blake visit_free(v); 1344b2cd7deeSPaolo Bonzini return string; 1345b2cd7deeSPaolo Bonzini } 1346b2cd7deeSPaolo Bonzini 134757c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 134857c9fafeSAnthony Liguori { 134989bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 135057c9fafeSAnthony Liguori if (prop == NULL) { 135157c9fafeSAnthony Liguori return NULL; 135257c9fafeSAnthony Liguori } 135357c9fafeSAnthony Liguori 135457c9fafeSAnthony Liguori return prop->type; 135557c9fafeSAnthony Liguori } 135657c9fafeSAnthony Liguori 135757c9fafeSAnthony Liguori Object *object_get_root(void) 135857c9fafeSAnthony Liguori { 13598b45d447SAnthony Liguori static Object *root; 136057c9fafeSAnthony Liguori 13618b45d447SAnthony Liguori if (!root) { 13628b45d447SAnthony Liguori root = object_new("container"); 136357c9fafeSAnthony Liguori } 136457c9fafeSAnthony Liguori 13658b45d447SAnthony Liguori return root; 136657c9fafeSAnthony Liguori } 136757c9fafeSAnthony Liguori 1368bc2256c4SDaniel P. Berrange Object *object_get_objects_root(void) 1369bc2256c4SDaniel P. Berrange { 1370bc2256c4SDaniel P. Berrange return container_get(object_get_root(), "/objects"); 1371bc2256c4SDaniel P. Berrange } 1372bc2256c4SDaniel P. Berrange 1373*7c47c4eaSPeter Xu Object *object_get_internal_root(void) 1374*7c47c4eaSPeter Xu { 1375*7c47c4eaSPeter Xu static Object *internal_root; 1376*7c47c4eaSPeter Xu 1377*7c47c4eaSPeter Xu if (!internal_root) { 1378*7c47c4eaSPeter Xu internal_root = object_new("container"); 1379*7c47c4eaSPeter Xu } 1380*7c47c4eaSPeter Xu 1381*7c47c4eaSPeter Xu return internal_root; 1382*7c47c4eaSPeter Xu } 1383*7c47c4eaSPeter Xu 1384d7bce999SEric Blake static void object_get_child_property(Object *obj, Visitor *v, 1385d7bce999SEric Blake const char *name, void *opaque, 1386d7bce999SEric Blake Error **errp) 138757c9fafeSAnthony Liguori { 138857c9fafeSAnthony Liguori Object *child = opaque; 138957c9fafeSAnthony Liguori gchar *path; 139057c9fafeSAnthony Liguori 139157c9fafeSAnthony Liguori path = object_get_canonical_path(child); 139251e72bc1SEric Blake visit_type_str(v, name, &path, errp); 139357c9fafeSAnthony Liguori g_free(path); 139457c9fafeSAnthony Liguori } 139557c9fafeSAnthony Liguori 139664607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) 139764607d08SPaolo Bonzini { 139864607d08SPaolo Bonzini return opaque; 139964607d08SPaolo Bonzini } 140064607d08SPaolo Bonzini 1401db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 1402db85b575SAnthony Liguori void *opaque) 1403db85b575SAnthony Liguori { 1404db85b575SAnthony Liguori Object *child = opaque; 1405db85b575SAnthony Liguori 1406bffc687dSPaolo Bonzini if (child->class->unparent) { 1407bffc687dSPaolo Bonzini (child->class->unparent)(child); 1408bffc687dSPaolo Bonzini } 1409bffc687dSPaolo Bonzini child->parent = NULL; 1410db85b575SAnthony Liguori object_unref(child); 1411db85b575SAnthony Liguori } 1412db85b575SAnthony Liguori 141357c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 141457c9fafeSAnthony Liguori Object *child, Error **errp) 141557c9fafeSAnthony Liguori { 1416b0ed5e9fSPaolo Bonzini Error *local_err = NULL; 141757c9fafeSAnthony Liguori gchar *type; 141864607d08SPaolo Bonzini ObjectProperty *op; 141957c9fafeSAnthony Liguori 14208faa2f85SPeter Crosthwaite if (child->parent != NULL) { 14218faa2f85SPeter Crosthwaite error_setg(errp, "child object is already parented"); 14228faa2f85SPeter Crosthwaite return; 14238faa2f85SPeter Crosthwaite } 14248faa2f85SPeter Crosthwaite 142557c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 142657c9fafeSAnthony Liguori 142764607d08SPaolo Bonzini op = object_property_add(obj, name, type, object_get_child_property, NULL, 1428b0ed5e9fSPaolo Bonzini object_finalize_child_property, child, &local_err); 1429b0ed5e9fSPaolo Bonzini if (local_err) { 1430b0ed5e9fSPaolo Bonzini error_propagate(errp, local_err); 1431b0ed5e9fSPaolo Bonzini goto out; 1432b0ed5e9fSPaolo Bonzini } 143364607d08SPaolo Bonzini 143464607d08SPaolo Bonzini op->resolve = object_resolve_child_property; 143557c9fafeSAnthony Liguori object_ref(child); 143657c9fafeSAnthony Liguori child->parent = obj; 143757c9fafeSAnthony Liguori 1438b0ed5e9fSPaolo Bonzini out: 143957c9fafeSAnthony Liguori g_free(type); 144057c9fafeSAnthony Liguori } 144157c9fafeSAnthony Liguori 14428f5d58efSIgor Mammedov void object_property_allow_set_link(const Object *obj, const char *name, 144339f72ef9SStefan Hajnoczi Object *val, Error **errp) 144439f72ef9SStefan Hajnoczi { 144539f72ef9SStefan Hajnoczi /* Allow the link to be set, always */ 144639f72ef9SStefan Hajnoczi } 144739f72ef9SStefan Hajnoczi 14489561fda8SStefan Hajnoczi typedef struct { 14499561fda8SStefan Hajnoczi Object **child; 14508f5d58efSIgor Mammedov void (*check)(const Object *, const char *, Object *, Error **); 14519561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags; 14529561fda8SStefan Hajnoczi } LinkProperty; 14539561fda8SStefan Hajnoczi 1454d7bce999SEric Blake static void object_get_link_property(Object *obj, Visitor *v, 1455d7bce999SEric Blake const char *name, void *opaque, 1456d7bce999SEric Blake Error **errp) 145757c9fafeSAnthony Liguori { 14589561fda8SStefan Hajnoczi LinkProperty *lprop = opaque; 14599561fda8SStefan Hajnoczi Object **child = lprop->child; 146057c9fafeSAnthony Liguori gchar *path; 146157c9fafeSAnthony Liguori 146257c9fafeSAnthony Liguori if (*child) { 146357c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 146451e72bc1SEric Blake visit_type_str(v, name, &path, errp); 146557c9fafeSAnthony Liguori g_free(path); 146657c9fafeSAnthony Liguori } else { 146757c9fafeSAnthony Liguori path = (gchar *)""; 146851e72bc1SEric Blake visit_type_str(v, name, &path, errp); 146957c9fafeSAnthony Liguori } 147057c9fafeSAnthony Liguori } 147157c9fafeSAnthony Liguori 1472f5ec6704SStefan Hajnoczi /* 1473f5ec6704SStefan Hajnoczi * object_resolve_link: 1474f5ec6704SStefan Hajnoczi * 1475f5ec6704SStefan Hajnoczi * Lookup an object and ensure its type matches the link property type. This 1476f5ec6704SStefan Hajnoczi * is similar to object_resolve_path() except type verification against the 1477f5ec6704SStefan Hajnoczi * link property is performed. 1478f5ec6704SStefan Hajnoczi * 1479f5ec6704SStefan Hajnoczi * Returns: The matched object or NULL on path lookup failures. 1480f5ec6704SStefan Hajnoczi */ 1481f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name, 1482f5ec6704SStefan Hajnoczi const char *path, Error **errp) 1483f5ec6704SStefan Hajnoczi { 1484f5ec6704SStefan Hajnoczi const char *type; 1485f5ec6704SStefan Hajnoczi gchar *target_type; 1486f5ec6704SStefan Hajnoczi bool ambiguous = false; 1487f5ec6704SStefan Hajnoczi Object *target; 1488f5ec6704SStefan Hajnoczi 1489f5ec6704SStefan Hajnoczi /* Go from link<FOO> to FOO. */ 1490f5ec6704SStefan Hajnoczi type = object_property_get_type(obj, name, NULL); 1491f5ec6704SStefan Hajnoczi target_type = g_strndup(&type[5], strlen(type) - 6); 1492f5ec6704SStefan Hajnoczi target = object_resolve_path_type(path, target_type, &ambiguous); 1493f5ec6704SStefan Hajnoczi 1494f5ec6704SStefan Hajnoczi if (ambiguous) { 1495455b0fdeSEric Blake error_setg(errp, "Path '%s' does not uniquely identify an object", 1496455b0fdeSEric Blake path); 1497f5ec6704SStefan Hajnoczi } else if (!target) { 1498f5ec6704SStefan Hajnoczi target = object_resolve_path(path, &ambiguous); 1499f5ec6704SStefan Hajnoczi if (target || ambiguous) { 1500c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 1501f5ec6704SStefan Hajnoczi } else { 150275158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 150375158ebbSMarkus Armbruster "Device '%s' not found", path); 1504f5ec6704SStefan Hajnoczi } 1505f5ec6704SStefan Hajnoczi target = NULL; 1506f5ec6704SStefan Hajnoczi } 1507f5ec6704SStefan Hajnoczi g_free(target_type); 1508f5ec6704SStefan Hajnoczi 1509f5ec6704SStefan Hajnoczi return target; 1510f5ec6704SStefan Hajnoczi } 1511f5ec6704SStefan Hajnoczi 1512d7bce999SEric Blake static void object_set_link_property(Object *obj, Visitor *v, 1513d7bce999SEric Blake const char *name, void *opaque, 1514d7bce999SEric Blake Error **errp) 151557c9fafeSAnthony Liguori { 1516c6aed983SStefan Hajnoczi Error *local_err = NULL; 15179561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 15189561fda8SStefan Hajnoczi Object **child = prop->child; 1519c6aed983SStefan Hajnoczi Object *old_target = *child; 1520c6aed983SStefan Hajnoczi Object *new_target = NULL; 1521c6aed983SStefan Hajnoczi char *path = NULL; 152257c9fafeSAnthony Liguori 152351e72bc1SEric Blake visit_type_str(v, name, &path, &local_err); 152457c9fafeSAnthony Liguori 1525c6aed983SStefan Hajnoczi if (!local_err && strcmp(path, "") != 0) { 1526c6aed983SStefan Hajnoczi new_target = object_resolve_link(obj, name, path, &local_err); 152711e35bfdSPaolo Bonzini } 152857c9fafeSAnthony Liguori 152957c9fafeSAnthony Liguori g_free(path); 1530c6aed983SStefan Hajnoczi if (local_err) { 1531c6aed983SStefan Hajnoczi error_propagate(errp, local_err); 1532c6aed983SStefan Hajnoczi return; 1533c6aed983SStefan Hajnoczi } 1534f0cdc966SAlexander Barabash 153539f72ef9SStefan Hajnoczi prop->check(obj, name, new_target, &local_err); 153639f72ef9SStefan Hajnoczi if (local_err) { 153739f72ef9SStefan Hajnoczi error_propagate(errp, local_err); 153839f72ef9SStefan Hajnoczi return; 153939f72ef9SStefan Hajnoczi } 154039f72ef9SStefan Hajnoczi 1541c6aed983SStefan Hajnoczi object_ref(new_target); 1542c6aed983SStefan Hajnoczi *child = new_target; 1543f0cdc966SAlexander Barabash object_unref(old_target); 1544f0cdc966SAlexander Barabash } 154557c9fafeSAnthony Liguori 154664607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) 154764607d08SPaolo Bonzini { 154864607d08SPaolo Bonzini LinkProperty *lprop = opaque; 154964607d08SPaolo Bonzini 155064607d08SPaolo Bonzini return *lprop->child; 155164607d08SPaolo Bonzini } 155264607d08SPaolo Bonzini 15539561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name, 15549561fda8SStefan Hajnoczi void *opaque) 15559561fda8SStefan Hajnoczi { 15569561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 15579561fda8SStefan Hajnoczi 15589561fda8SStefan Hajnoczi if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { 15599561fda8SStefan Hajnoczi object_unref(*prop->child); 15609561fda8SStefan Hajnoczi } 15619561fda8SStefan Hajnoczi g_free(prop); 15629561fda8SStefan Hajnoczi } 15639561fda8SStefan Hajnoczi 156457c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 156557c9fafeSAnthony Liguori const char *type, Object **child, 15668f5d58efSIgor Mammedov void (*check)(const Object *, const char *, 156739f72ef9SStefan Hajnoczi Object *, Error **), 15689561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags, 156957c9fafeSAnthony Liguori Error **errp) 157057c9fafeSAnthony Liguori { 15719561fda8SStefan Hajnoczi Error *local_err = NULL; 15729561fda8SStefan Hajnoczi LinkProperty *prop = g_malloc(sizeof(*prop)); 157357c9fafeSAnthony Liguori gchar *full_type; 157464607d08SPaolo Bonzini ObjectProperty *op; 157557c9fafeSAnthony Liguori 15769561fda8SStefan Hajnoczi prop->child = child; 157739f72ef9SStefan Hajnoczi prop->check = check; 15789561fda8SStefan Hajnoczi prop->flags = flags; 15799561fda8SStefan Hajnoczi 158057c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 158157c9fafeSAnthony Liguori 158264607d08SPaolo Bonzini op = object_property_add(obj, name, full_type, 158357c9fafeSAnthony Liguori object_get_link_property, 158439f72ef9SStefan Hajnoczi check ? object_set_link_property : NULL, 15859561fda8SStefan Hajnoczi object_release_link_property, 15869561fda8SStefan Hajnoczi prop, 15879561fda8SStefan Hajnoczi &local_err); 15889561fda8SStefan Hajnoczi if (local_err) { 15899561fda8SStefan Hajnoczi error_propagate(errp, local_err); 15909561fda8SStefan Hajnoczi g_free(prop); 159164607d08SPaolo Bonzini goto out; 15929561fda8SStefan Hajnoczi } 159357c9fafeSAnthony Liguori 159464607d08SPaolo Bonzini op->resolve = object_resolve_link_property; 159564607d08SPaolo Bonzini 159664607d08SPaolo Bonzini out: 159757c9fafeSAnthony Liguori g_free(full_type); 159857c9fafeSAnthony Liguori } 159957c9fafeSAnthony Liguori 1600fb9e7e33SPaolo Bonzini void object_property_add_const_link(Object *obj, const char *name, 1601fb9e7e33SPaolo Bonzini Object *target, Error **errp) 1602fb9e7e33SPaolo Bonzini { 1603fb9e7e33SPaolo Bonzini char *link_type; 1604fb9e7e33SPaolo Bonzini ObjectProperty *op; 1605fb9e7e33SPaolo Bonzini 1606fb9e7e33SPaolo Bonzini link_type = g_strdup_printf("link<%s>", object_get_typename(target)); 1607fb9e7e33SPaolo Bonzini op = object_property_add(obj, name, link_type, 1608fb9e7e33SPaolo Bonzini object_get_child_property, NULL, 1609fb9e7e33SPaolo Bonzini NULL, target, errp); 1610fb9e7e33SPaolo Bonzini if (op != NULL) { 1611fb9e7e33SPaolo Bonzini op->resolve = object_resolve_child_property; 1612fb9e7e33SPaolo Bonzini } 1613fb9e7e33SPaolo Bonzini g_free(link_type); 1614fb9e7e33SPaolo Bonzini } 1615fb9e7e33SPaolo Bonzini 161611f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj) 161757c9fafeSAnthony Liguori { 161857c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 1619b604a854SPavel Fedin GHashTableIter iter; 162057c9fafeSAnthony Liguori 162111f590b1SStefan Hajnoczi g_assert(obj); 162257c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 162357c9fafeSAnthony Liguori 1624b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->parent->properties); 1625b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 16265d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 162757c9fafeSAnthony Liguori continue; 162857c9fafeSAnthony Liguori } 162957c9fafeSAnthony Liguori 163057c9fafeSAnthony Liguori if (prop->opaque == obj) { 163111f590b1SStefan Hajnoczi return g_strdup(prop->name); 163257c9fafeSAnthony Liguori } 163357c9fafeSAnthony Liguori } 163457c9fafeSAnthony Liguori 163511f590b1SStefan Hajnoczi /* obj had a parent but was not a child, should never happen */ 163611f590b1SStefan Hajnoczi g_assert_not_reached(); 163711f590b1SStefan Hajnoczi return NULL; 163811f590b1SStefan Hajnoczi } 163911f590b1SStefan Hajnoczi 164011f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj) 164111f590b1SStefan Hajnoczi { 164211f590b1SStefan Hajnoczi Object *root = object_get_root(); 164311f590b1SStefan Hajnoczi char *newpath, *path = NULL; 164411f590b1SStefan Hajnoczi 164511f590b1SStefan Hajnoczi while (obj != root) { 164611f590b1SStefan Hajnoczi char *component = object_get_canonical_path_component(obj); 164711f590b1SStefan Hajnoczi 164811f590b1SStefan Hajnoczi if (path) { 164911f590b1SStefan Hajnoczi newpath = g_strdup_printf("%s/%s", component, path); 165011f590b1SStefan Hajnoczi g_free(component); 165111f590b1SStefan Hajnoczi g_free(path); 165211f590b1SStefan Hajnoczi path = newpath; 165311f590b1SStefan Hajnoczi } else { 165411f590b1SStefan Hajnoczi path = component; 165511f590b1SStefan Hajnoczi } 165657c9fafeSAnthony Liguori 165757c9fafeSAnthony Liguori obj = obj->parent; 165857c9fafeSAnthony Liguori } 165957c9fafeSAnthony Liguori 166011f590b1SStefan Hajnoczi newpath = g_strdup_printf("/%s", path ? path : ""); 166157c9fafeSAnthony Liguori g_free(path); 166257c9fafeSAnthony Liguori 166357c9fafeSAnthony Liguori return newpath; 166457c9fafeSAnthony Liguori } 166557c9fafeSAnthony Liguori 16663e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part) 1667a612b2a6SPaolo Bonzini { 166889bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part, NULL); 1669a612b2a6SPaolo Bonzini if (prop == NULL) { 1670a612b2a6SPaolo Bonzini return NULL; 1671a612b2a6SPaolo Bonzini } 1672a612b2a6SPaolo Bonzini 167364607d08SPaolo Bonzini if (prop->resolve) { 167464607d08SPaolo Bonzini return prop->resolve(parent, prop->opaque, part); 1675a612b2a6SPaolo Bonzini } else { 1676a612b2a6SPaolo Bonzini return NULL; 1677a612b2a6SPaolo Bonzini } 1678a612b2a6SPaolo Bonzini } 1679a612b2a6SPaolo Bonzini 168057c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 168157c9fafeSAnthony Liguori gchar **parts, 168202fe2db6SPaolo Bonzini const char *typename, 168357c9fafeSAnthony Liguori int index) 168457c9fafeSAnthony Liguori { 168557c9fafeSAnthony Liguori Object *child; 168657c9fafeSAnthony Liguori 168757c9fafeSAnthony Liguori if (parts[index] == NULL) { 168802fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 168957c9fafeSAnthony Liguori } 169057c9fafeSAnthony Liguori 169157c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 169202fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 169357c9fafeSAnthony Liguori } 169457c9fafeSAnthony Liguori 1695a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 169657c9fafeSAnthony Liguori if (!child) { 169757c9fafeSAnthony Liguori return NULL; 169857c9fafeSAnthony Liguori } 169957c9fafeSAnthony Liguori 170002fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 170157c9fafeSAnthony Liguori } 170257c9fafeSAnthony Liguori 170357c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 170457c9fafeSAnthony Liguori gchar **parts, 170502fe2db6SPaolo Bonzini const char *typename, 170657c9fafeSAnthony Liguori bool *ambiguous) 170757c9fafeSAnthony Liguori { 170857c9fafeSAnthony Liguori Object *obj; 1709b604a854SPavel Fedin GHashTableIter iter; 171057c9fafeSAnthony Liguori ObjectProperty *prop; 171157c9fafeSAnthony Liguori 171202fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 171357c9fafeSAnthony Liguori 1714b604a854SPavel Fedin g_hash_table_iter_init(&iter, parent->properties); 1715b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 171657c9fafeSAnthony Liguori Object *found; 171757c9fafeSAnthony Liguori 17185d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 171957c9fafeSAnthony Liguori continue; 172057c9fafeSAnthony Liguori } 172157c9fafeSAnthony Liguori 172202fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 172302fe2db6SPaolo Bonzini typename, ambiguous); 172457c9fafeSAnthony Liguori if (found) { 172557c9fafeSAnthony Liguori if (obj) { 172657c9fafeSAnthony Liguori *ambiguous = true; 172757c9fafeSAnthony Liguori return NULL; 172857c9fafeSAnthony Liguori } 172957c9fafeSAnthony Liguori obj = found; 173057c9fafeSAnthony Liguori } 173157c9fafeSAnthony Liguori 1732ebcc479eSEduardo Habkost if (*ambiguous) { 173357c9fafeSAnthony Liguori return NULL; 173457c9fafeSAnthony Liguori } 173557c9fafeSAnthony Liguori } 173657c9fafeSAnthony Liguori 173757c9fafeSAnthony Liguori return obj; 173857c9fafeSAnthony Liguori } 173957c9fafeSAnthony Liguori 174002fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 1741ebcc479eSEduardo Habkost bool *ambiguousp) 174257c9fafeSAnthony Liguori { 174357c9fafeSAnthony Liguori Object *obj; 174457c9fafeSAnthony Liguori gchar **parts; 174557c9fafeSAnthony Liguori 174657c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 17472e1103f6SPaolo Bonzini assert(parts); 174857c9fafeSAnthony Liguori 17492e1103f6SPaolo Bonzini if (parts[0] == NULL || strcmp(parts[0], "") != 0) { 1750ebcc479eSEduardo Habkost bool ambiguous = false; 175102fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 1752ebcc479eSEduardo Habkost typename, &ambiguous); 1753ebcc479eSEduardo Habkost if (ambiguousp) { 1754ebcc479eSEduardo Habkost *ambiguousp = ambiguous; 1755ebcc479eSEduardo Habkost } 175657c9fafeSAnthony Liguori } else { 175702fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 175857c9fafeSAnthony Liguori } 175957c9fafeSAnthony Liguori 176057c9fafeSAnthony Liguori g_strfreev(parts); 176157c9fafeSAnthony Liguori 176257c9fafeSAnthony Liguori return obj; 176357c9fafeSAnthony Liguori } 176457c9fafeSAnthony Liguori 176502fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 176602fe2db6SPaolo Bonzini { 176702fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 176802fe2db6SPaolo Bonzini } 176902fe2db6SPaolo Bonzini 177057c9fafeSAnthony Liguori typedef struct StringProperty 177157c9fafeSAnthony Liguori { 177257c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 177357c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 177457c9fafeSAnthony Liguori } StringProperty; 177557c9fafeSAnthony Liguori 1776d7bce999SEric Blake static void property_get_str(Object *obj, Visitor *v, const char *name, 1777d7bce999SEric Blake void *opaque, Error **errp) 177857c9fafeSAnthony Liguori { 177957c9fafeSAnthony Liguori StringProperty *prop = opaque; 178057c9fafeSAnthony Liguori char *value; 1781e1c8237dSMarkus Armbruster Error *err = NULL; 178257c9fafeSAnthony Liguori 1783e1c8237dSMarkus Armbruster value = prop->get(obj, &err); 1784e1c8237dSMarkus Armbruster if (err) { 1785e1c8237dSMarkus Armbruster error_propagate(errp, err); 1786e1c8237dSMarkus Armbruster return; 1787e1c8237dSMarkus Armbruster } 1788e1c8237dSMarkus Armbruster 178951e72bc1SEric Blake visit_type_str(v, name, &value, errp); 179057c9fafeSAnthony Liguori g_free(value); 179157c9fafeSAnthony Liguori } 179257c9fafeSAnthony Liguori 1793d7bce999SEric Blake static void property_set_str(Object *obj, Visitor *v, const char *name, 1794d7bce999SEric Blake void *opaque, Error **errp) 179557c9fafeSAnthony Liguori { 179657c9fafeSAnthony Liguori StringProperty *prop = opaque; 179757c9fafeSAnthony Liguori char *value; 179857c9fafeSAnthony Liguori Error *local_err = NULL; 179957c9fafeSAnthony Liguori 180051e72bc1SEric Blake visit_type_str(v, name, &value, &local_err); 180157c9fafeSAnthony Liguori if (local_err) { 180257c9fafeSAnthony Liguori error_propagate(errp, local_err); 180357c9fafeSAnthony Liguori return; 180457c9fafeSAnthony Liguori } 180557c9fafeSAnthony Liguori 180657c9fafeSAnthony Liguori prop->set(obj, value, errp); 180757c9fafeSAnthony Liguori g_free(value); 180857c9fafeSAnthony Liguori } 180957c9fafeSAnthony Liguori 18107b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 181157c9fafeSAnthony Liguori void *opaque) 181257c9fafeSAnthony Liguori { 181357c9fafeSAnthony Liguori StringProperty *prop = opaque; 181457c9fafeSAnthony Liguori g_free(prop); 181557c9fafeSAnthony Liguori } 181657c9fafeSAnthony Liguori 181757c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 181857c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 181957c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 182057c9fafeSAnthony Liguori Error **errp) 182157c9fafeSAnthony Liguori { 1822a01aedc8SStefan Hajnoczi Error *local_err = NULL; 182357c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 182457c9fafeSAnthony Liguori 182557c9fafeSAnthony Liguori prop->get = get; 182657c9fafeSAnthony Liguori prop->set = set; 182757c9fafeSAnthony Liguori 182857c9fafeSAnthony Liguori object_property_add(obj, name, "string", 18297b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 18307b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 18317b7b7d18SPaolo Bonzini property_release_str, 1832a01aedc8SStefan Hajnoczi prop, &local_err); 1833a01aedc8SStefan Hajnoczi if (local_err) { 1834a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1835a01aedc8SStefan Hajnoczi g_free(prop); 1836a01aedc8SStefan Hajnoczi } 183757c9fafeSAnthony Liguori } 1838745549c8SPaolo Bonzini 183916bf7f52SDaniel P. Berrange void object_class_property_add_str(ObjectClass *klass, const char *name, 184016bf7f52SDaniel P. Berrange char *(*get)(Object *, Error **), 184116bf7f52SDaniel P. Berrange void (*set)(Object *, const char *, 184216bf7f52SDaniel P. Berrange Error **), 184316bf7f52SDaniel P. Berrange Error **errp) 184416bf7f52SDaniel P. Berrange { 184516bf7f52SDaniel P. Berrange Error *local_err = NULL; 184616bf7f52SDaniel P. Berrange StringProperty *prop = g_malloc0(sizeof(*prop)); 184716bf7f52SDaniel P. Berrange 184816bf7f52SDaniel P. Berrange prop->get = get; 184916bf7f52SDaniel P. Berrange prop->set = set; 185016bf7f52SDaniel P. Berrange 185116bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "string", 185216bf7f52SDaniel P. Berrange get ? property_get_str : NULL, 185316bf7f52SDaniel P. Berrange set ? property_set_str : NULL, 185416bf7f52SDaniel P. Berrange property_release_str, 185516bf7f52SDaniel P. Berrange prop, &local_err); 185616bf7f52SDaniel P. Berrange if (local_err) { 185716bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 185816bf7f52SDaniel P. Berrange g_free(prop); 185916bf7f52SDaniel P. Berrange } 186016bf7f52SDaniel P. Berrange } 186116bf7f52SDaniel P. Berrange 18620e558843SAnthony Liguori typedef struct BoolProperty 18630e558843SAnthony Liguori { 18640e558843SAnthony Liguori bool (*get)(Object *, Error **); 18650e558843SAnthony Liguori void (*set)(Object *, bool, Error **); 18660e558843SAnthony Liguori } BoolProperty; 18670e558843SAnthony Liguori 1868d7bce999SEric Blake static void property_get_bool(Object *obj, Visitor *v, const char *name, 1869d7bce999SEric Blake void *opaque, Error **errp) 18700e558843SAnthony Liguori { 18710e558843SAnthony Liguori BoolProperty *prop = opaque; 18720e558843SAnthony Liguori bool value; 18734715d42eSMarkus Armbruster Error *err = NULL; 18740e558843SAnthony Liguori 18754715d42eSMarkus Armbruster value = prop->get(obj, &err); 18764715d42eSMarkus Armbruster if (err) { 18774715d42eSMarkus Armbruster error_propagate(errp, err); 18784715d42eSMarkus Armbruster return; 18794715d42eSMarkus Armbruster } 18804715d42eSMarkus Armbruster 188151e72bc1SEric Blake visit_type_bool(v, name, &value, errp); 18820e558843SAnthony Liguori } 18830e558843SAnthony Liguori 1884d7bce999SEric Blake static void property_set_bool(Object *obj, Visitor *v, const char *name, 1885d7bce999SEric Blake void *opaque, Error **errp) 18860e558843SAnthony Liguori { 18870e558843SAnthony Liguori BoolProperty *prop = opaque; 18880e558843SAnthony Liguori bool value; 18890e558843SAnthony Liguori Error *local_err = NULL; 18900e558843SAnthony Liguori 189151e72bc1SEric Blake visit_type_bool(v, name, &value, &local_err); 18920e558843SAnthony Liguori if (local_err) { 18930e558843SAnthony Liguori error_propagate(errp, local_err); 18940e558843SAnthony Liguori return; 18950e558843SAnthony Liguori } 18960e558843SAnthony Liguori 18970e558843SAnthony Liguori prop->set(obj, value, errp); 18980e558843SAnthony Liguori } 18990e558843SAnthony Liguori 19000e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name, 19010e558843SAnthony Liguori void *opaque) 19020e558843SAnthony Liguori { 19030e558843SAnthony Liguori BoolProperty *prop = opaque; 19040e558843SAnthony Liguori g_free(prop); 19050e558843SAnthony Liguori } 19060e558843SAnthony Liguori 19070e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name, 19080e558843SAnthony Liguori bool (*get)(Object *, Error **), 19090e558843SAnthony Liguori void (*set)(Object *, bool, Error **), 19100e558843SAnthony Liguori Error **errp) 19110e558843SAnthony Liguori { 1912a01aedc8SStefan Hajnoczi Error *local_err = NULL; 19130e558843SAnthony Liguori BoolProperty *prop = g_malloc0(sizeof(*prop)); 19140e558843SAnthony Liguori 19150e558843SAnthony Liguori prop->get = get; 19160e558843SAnthony Liguori prop->set = set; 19170e558843SAnthony Liguori 19180e558843SAnthony Liguori object_property_add(obj, name, "bool", 19190e558843SAnthony Liguori get ? property_get_bool : NULL, 19200e558843SAnthony Liguori set ? property_set_bool : NULL, 19210e558843SAnthony Liguori property_release_bool, 1922a01aedc8SStefan Hajnoczi prop, &local_err); 1923a01aedc8SStefan Hajnoczi if (local_err) { 1924a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1925a01aedc8SStefan Hajnoczi g_free(prop); 1926a01aedc8SStefan Hajnoczi } 19270e558843SAnthony Liguori } 19280e558843SAnthony Liguori 192916bf7f52SDaniel P. Berrange void object_class_property_add_bool(ObjectClass *klass, const char *name, 193016bf7f52SDaniel P. Berrange bool (*get)(Object *, Error **), 193116bf7f52SDaniel P. Berrange void (*set)(Object *, bool, Error **), 193216bf7f52SDaniel P. Berrange Error **errp) 193316bf7f52SDaniel P. Berrange { 193416bf7f52SDaniel P. Berrange Error *local_err = NULL; 193516bf7f52SDaniel P. Berrange BoolProperty *prop = g_malloc0(sizeof(*prop)); 193616bf7f52SDaniel P. Berrange 193716bf7f52SDaniel P. Berrange prop->get = get; 193816bf7f52SDaniel P. Berrange prop->set = set; 193916bf7f52SDaniel P. Berrange 194016bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "bool", 194116bf7f52SDaniel P. Berrange get ? property_get_bool : NULL, 194216bf7f52SDaniel P. Berrange set ? property_set_bool : NULL, 194316bf7f52SDaniel P. Berrange property_release_bool, 194416bf7f52SDaniel P. Berrange prop, &local_err); 194516bf7f52SDaniel P. Berrange if (local_err) { 194616bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 194716bf7f52SDaniel P. Berrange g_free(prop); 194816bf7f52SDaniel P. Berrange } 194916bf7f52SDaniel P. Berrange } 195016bf7f52SDaniel P. Berrange 1951d7bce999SEric Blake static void property_get_enum(Object *obj, Visitor *v, const char *name, 1952d7bce999SEric Blake void *opaque, Error **errp) 1953a8e3fbedSDaniel P. Berrange { 1954a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1955a8e3fbedSDaniel P. Berrange int value; 19564715d42eSMarkus Armbruster Error *err = NULL; 1957a8e3fbedSDaniel P. Berrange 19584715d42eSMarkus Armbruster value = prop->get(obj, &err); 19594715d42eSMarkus Armbruster if (err) { 19604715d42eSMarkus Armbruster error_propagate(errp, err); 19614715d42eSMarkus Armbruster return; 19624715d42eSMarkus Armbruster } 19634715d42eSMarkus Armbruster 1964f7abe0ecSMarc-André Lureau visit_type_enum(v, name, &value, prop->lookup, errp); 1965a8e3fbedSDaniel P. Berrange } 1966a8e3fbedSDaniel P. Berrange 1967d7bce999SEric Blake static void property_set_enum(Object *obj, Visitor *v, const char *name, 1968d7bce999SEric Blake void *opaque, Error **errp) 1969a8e3fbedSDaniel P. Berrange { 1970a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1971a8e3fbedSDaniel P. Berrange int value; 19724715d42eSMarkus Armbruster Error *err = NULL; 1973a8e3fbedSDaniel P. Berrange 1974f7abe0ecSMarc-André Lureau visit_type_enum(v, name, &value, prop->lookup, &err); 19754715d42eSMarkus Armbruster if (err) { 19764715d42eSMarkus Armbruster error_propagate(errp, err); 19774715d42eSMarkus Armbruster return; 19784715d42eSMarkus Armbruster } 1979a8e3fbedSDaniel P. Berrange prop->set(obj, value, errp); 1980a8e3fbedSDaniel P. Berrange } 1981a8e3fbedSDaniel P. Berrange 1982a8e3fbedSDaniel P. Berrange static void property_release_enum(Object *obj, const char *name, 1983a8e3fbedSDaniel P. Berrange void *opaque) 1984a8e3fbedSDaniel P. Berrange { 1985a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1986a8e3fbedSDaniel P. Berrange g_free(prop); 1987a8e3fbedSDaniel P. Berrange } 1988a8e3fbedSDaniel P. Berrange 1989a8e3fbedSDaniel P. Berrange void object_property_add_enum(Object *obj, const char *name, 1990a8e3fbedSDaniel P. Berrange const char *typename, 1991f7abe0ecSMarc-André Lureau const QEnumLookup *lookup, 1992a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **), 1993a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **), 1994a8e3fbedSDaniel P. Berrange Error **errp) 1995a8e3fbedSDaniel P. Berrange { 1996a8e3fbedSDaniel P. Berrange Error *local_err = NULL; 1997a8e3fbedSDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 1998a8e3fbedSDaniel P. Berrange 1999f7abe0ecSMarc-André Lureau prop->lookup = lookup; 2000a8e3fbedSDaniel P. Berrange prop->get = get; 2001a8e3fbedSDaniel P. Berrange prop->set = set; 2002a8e3fbedSDaniel P. Berrange 2003a8e3fbedSDaniel P. Berrange object_property_add(obj, name, typename, 2004a8e3fbedSDaniel P. Berrange get ? property_get_enum : NULL, 2005a8e3fbedSDaniel P. Berrange set ? property_set_enum : NULL, 2006a8e3fbedSDaniel P. Berrange property_release_enum, 2007a8e3fbedSDaniel P. Berrange prop, &local_err); 2008a8e3fbedSDaniel P. Berrange if (local_err) { 2009a8e3fbedSDaniel P. Berrange error_propagate(errp, local_err); 2010a8e3fbedSDaniel P. Berrange g_free(prop); 2011a8e3fbedSDaniel P. Berrange } 2012a8e3fbedSDaniel P. Berrange } 2013a8e3fbedSDaniel P. Berrange 201416bf7f52SDaniel P. Berrange void object_class_property_add_enum(ObjectClass *klass, const char *name, 201516bf7f52SDaniel P. Berrange const char *typename, 2016f7abe0ecSMarc-André Lureau const QEnumLookup *lookup, 201716bf7f52SDaniel P. Berrange int (*get)(Object *, Error **), 201816bf7f52SDaniel P. Berrange void (*set)(Object *, int, Error **), 201916bf7f52SDaniel P. Berrange Error **errp) 202016bf7f52SDaniel P. Berrange { 202116bf7f52SDaniel P. Berrange Error *local_err = NULL; 202216bf7f52SDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 202316bf7f52SDaniel P. Berrange 2024f7abe0ecSMarc-André Lureau prop->lookup = lookup; 202516bf7f52SDaniel P. Berrange prop->get = get; 202616bf7f52SDaniel P. Berrange prop->set = set; 202716bf7f52SDaniel P. Berrange 202816bf7f52SDaniel P. Berrange object_class_property_add(klass, name, typename, 202916bf7f52SDaniel P. Berrange get ? property_get_enum : NULL, 203016bf7f52SDaniel P. Berrange set ? property_set_enum : NULL, 203116bf7f52SDaniel P. Berrange property_release_enum, 203216bf7f52SDaniel P. Berrange prop, &local_err); 203316bf7f52SDaniel P. Berrange if (local_err) { 203416bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 203516bf7f52SDaniel P. Berrange g_free(prop); 203616bf7f52SDaniel P. Berrange } 203716bf7f52SDaniel P. Berrange } 203816bf7f52SDaniel P. Berrange 20398e099d14SDavid Gibson typedef struct TMProperty { 20408e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **); 20418e099d14SDavid Gibson } TMProperty; 20428e099d14SDavid Gibson 2043d7bce999SEric Blake static void property_get_tm(Object *obj, Visitor *v, const char *name, 2044d7bce999SEric Blake void *opaque, Error **errp) 20458e099d14SDavid Gibson { 20468e099d14SDavid Gibson TMProperty *prop = opaque; 20478e099d14SDavid Gibson Error *err = NULL; 20488e099d14SDavid Gibson struct tm value; 20498e099d14SDavid Gibson 20508e099d14SDavid Gibson prop->get(obj, &value, &err); 20518e099d14SDavid Gibson if (err) { 20528e099d14SDavid Gibson goto out; 20538e099d14SDavid Gibson } 20548e099d14SDavid Gibson 2055337283dfSEric Blake visit_start_struct(v, name, NULL, 0, &err); 20568e099d14SDavid Gibson if (err) { 20578e099d14SDavid Gibson goto out; 20588e099d14SDavid Gibson } 205951e72bc1SEric Blake visit_type_int32(v, "tm_year", &value.tm_year, &err); 20608e099d14SDavid Gibson if (err) { 20618e099d14SDavid Gibson goto out_end; 20628e099d14SDavid Gibson } 206351e72bc1SEric Blake visit_type_int32(v, "tm_mon", &value.tm_mon, &err); 20648e099d14SDavid Gibson if (err) { 20658e099d14SDavid Gibson goto out_end; 20668e099d14SDavid Gibson } 206751e72bc1SEric Blake visit_type_int32(v, "tm_mday", &value.tm_mday, &err); 20688e099d14SDavid Gibson if (err) { 20698e099d14SDavid Gibson goto out_end; 20708e099d14SDavid Gibson } 207151e72bc1SEric Blake visit_type_int32(v, "tm_hour", &value.tm_hour, &err); 20728e099d14SDavid Gibson if (err) { 20738e099d14SDavid Gibson goto out_end; 20748e099d14SDavid Gibson } 207551e72bc1SEric Blake visit_type_int32(v, "tm_min", &value.tm_min, &err); 20768e099d14SDavid Gibson if (err) { 20778e099d14SDavid Gibson goto out_end; 20788e099d14SDavid Gibson } 207951e72bc1SEric Blake visit_type_int32(v, "tm_sec", &value.tm_sec, &err); 20808e099d14SDavid Gibson if (err) { 20818e099d14SDavid Gibson goto out_end; 20828e099d14SDavid Gibson } 208315c2f669SEric Blake visit_check_struct(v, &err); 20848e099d14SDavid Gibson out_end: 20851158bb2aSEric Blake visit_end_struct(v, NULL); 20868e099d14SDavid Gibson out: 20878e099d14SDavid Gibson error_propagate(errp, err); 20888e099d14SDavid Gibson 20898e099d14SDavid Gibson } 20908e099d14SDavid Gibson 20918e099d14SDavid Gibson static void property_release_tm(Object *obj, const char *name, 20928e099d14SDavid Gibson void *opaque) 20938e099d14SDavid Gibson { 20948e099d14SDavid Gibson TMProperty *prop = opaque; 20958e099d14SDavid Gibson g_free(prop); 20968e099d14SDavid Gibson } 20978e099d14SDavid Gibson 20988e099d14SDavid Gibson void object_property_add_tm(Object *obj, const char *name, 20998e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **), 21008e099d14SDavid Gibson Error **errp) 21018e099d14SDavid Gibson { 21028e099d14SDavid Gibson Error *local_err = NULL; 21038e099d14SDavid Gibson TMProperty *prop = g_malloc0(sizeof(*prop)); 21048e099d14SDavid Gibson 21058e099d14SDavid Gibson prop->get = get; 21068e099d14SDavid Gibson 21078e099d14SDavid Gibson object_property_add(obj, name, "struct tm", 21088e099d14SDavid Gibson get ? property_get_tm : NULL, NULL, 21098e099d14SDavid Gibson property_release_tm, 21108e099d14SDavid Gibson prop, &local_err); 21118e099d14SDavid Gibson if (local_err) { 21128e099d14SDavid Gibson error_propagate(errp, local_err); 21138e099d14SDavid Gibson g_free(prop); 21148e099d14SDavid Gibson } 21158e099d14SDavid Gibson } 21168e099d14SDavid Gibson 211716bf7f52SDaniel P. Berrange void object_class_property_add_tm(ObjectClass *klass, const char *name, 211816bf7f52SDaniel P. Berrange void (*get)(Object *, struct tm *, Error **), 211916bf7f52SDaniel P. Berrange Error **errp) 212016bf7f52SDaniel P. Berrange { 212116bf7f52SDaniel P. Berrange Error *local_err = NULL; 212216bf7f52SDaniel P. Berrange TMProperty *prop = g_malloc0(sizeof(*prop)); 212316bf7f52SDaniel P. Berrange 212416bf7f52SDaniel P. Berrange prop->get = get; 212516bf7f52SDaniel P. Berrange 212616bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "struct tm", 212716bf7f52SDaniel P. Berrange get ? property_get_tm : NULL, NULL, 212816bf7f52SDaniel P. Berrange property_release_tm, 212916bf7f52SDaniel P. Berrange prop, &local_err); 213016bf7f52SDaniel P. Berrange if (local_err) { 213116bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 213216bf7f52SDaniel P. Berrange g_free(prop); 213316bf7f52SDaniel P. Berrange } 213416bf7f52SDaniel P. Berrange } 213516bf7f52SDaniel P. Berrange 21362f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp) 21372f262e06SPaolo Bonzini { 21382f262e06SPaolo Bonzini return g_strdup(object_get_typename(obj)); 21392f262e06SPaolo Bonzini } 21402f262e06SPaolo Bonzini 2141d7bce999SEric Blake static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name, 2142d7bce999SEric Blake void *opaque, Error **errp) 2143e732ea63SMichael S. Tsirkin { 2144e732ea63SMichael S. Tsirkin uint8_t value = *(uint8_t *)opaque; 214551e72bc1SEric Blake visit_type_uint8(v, name, &value, errp); 2146e732ea63SMichael S. Tsirkin } 2147e732ea63SMichael S. Tsirkin 2148d7bce999SEric Blake static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name, 2149d7bce999SEric Blake void *opaque, Error **errp) 2150e732ea63SMichael S. Tsirkin { 2151e732ea63SMichael S. Tsirkin uint16_t value = *(uint16_t *)opaque; 215251e72bc1SEric Blake visit_type_uint16(v, name, &value, errp); 2153e732ea63SMichael S. Tsirkin } 2154e732ea63SMichael S. Tsirkin 2155d7bce999SEric Blake static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name, 2156d7bce999SEric Blake void *opaque, Error **errp) 2157e732ea63SMichael S. Tsirkin { 2158e732ea63SMichael S. Tsirkin uint32_t value = *(uint32_t *)opaque; 215951e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 2160e732ea63SMichael S. Tsirkin } 2161e732ea63SMichael S. Tsirkin 2162d7bce999SEric Blake static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name, 2163d7bce999SEric Blake void *opaque, Error **errp) 2164e732ea63SMichael S. Tsirkin { 2165e732ea63SMichael S. Tsirkin uint64_t value = *(uint64_t *)opaque; 216651e72bc1SEric Blake visit_type_uint64(v, name, &value, errp); 2167e732ea63SMichael S. Tsirkin } 2168e732ea63SMichael S. Tsirkin 2169e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name, 2170e732ea63SMichael S. Tsirkin const uint8_t *v, Error **errp) 2171e732ea63SMichael S. Tsirkin { 2172e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint8", property_get_uint8_ptr, 2173e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2174e732ea63SMichael S. Tsirkin } 2175e732ea63SMichael S. Tsirkin 217616bf7f52SDaniel P. Berrange void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, 217716bf7f52SDaniel P. Berrange const uint8_t *v, Error **errp) 217816bf7f52SDaniel P. Berrange { 217916bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint8", property_get_uint8_ptr, 218016bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 218116bf7f52SDaniel P. Berrange } 218216bf7f52SDaniel P. Berrange 2183e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name, 2184e732ea63SMichael S. Tsirkin const uint16_t *v, Error **errp) 2185e732ea63SMichael S. Tsirkin { 2186e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint16", property_get_uint16_ptr, 2187e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2188e732ea63SMichael S. Tsirkin } 2189e732ea63SMichael S. Tsirkin 219016bf7f52SDaniel P. Berrange void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, 219116bf7f52SDaniel P. Berrange const uint16_t *v, Error **errp) 219216bf7f52SDaniel P. Berrange { 219316bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint16", property_get_uint16_ptr, 219416bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 219516bf7f52SDaniel P. Berrange } 219616bf7f52SDaniel P. Berrange 2197e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name, 2198e732ea63SMichael S. Tsirkin const uint32_t *v, Error **errp) 2199e732ea63SMichael S. Tsirkin { 2200e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint32", property_get_uint32_ptr, 2201e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2202e732ea63SMichael S. Tsirkin } 2203e732ea63SMichael S. Tsirkin 220416bf7f52SDaniel P. Berrange void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, 220516bf7f52SDaniel P. Berrange const uint32_t *v, Error **errp) 220616bf7f52SDaniel P. Berrange { 220716bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint32", property_get_uint32_ptr, 220816bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 220916bf7f52SDaniel P. Berrange } 221016bf7f52SDaniel P. Berrange 2211e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name, 2212e732ea63SMichael S. Tsirkin const uint64_t *v, Error **errp) 2213e732ea63SMichael S. Tsirkin { 2214e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint64", property_get_uint64_ptr, 2215e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2216e732ea63SMichael S. Tsirkin } 2217e732ea63SMichael S. Tsirkin 221816bf7f52SDaniel P. Berrange void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, 221916bf7f52SDaniel P. Berrange const uint64_t *v, Error **errp) 222016bf7f52SDaniel P. Berrange { 222116bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint64", property_get_uint64_ptr, 222216bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 222316bf7f52SDaniel P. Berrange } 222416bf7f52SDaniel P. Berrange 2225ef7c7ff6SStefan Hajnoczi typedef struct { 2226ef7c7ff6SStefan Hajnoczi Object *target_obj; 22271590d266SEduardo Habkost char *target_name; 2228ef7c7ff6SStefan Hajnoczi } AliasProperty; 2229ef7c7ff6SStefan Hajnoczi 2230d7bce999SEric Blake static void property_get_alias(Object *obj, Visitor *v, const char *name, 2231d7bce999SEric Blake void *opaque, Error **errp) 2232ef7c7ff6SStefan Hajnoczi { 2233ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2234ef7c7ff6SStefan Hajnoczi 2235ef7c7ff6SStefan Hajnoczi object_property_get(prop->target_obj, v, prop->target_name, errp); 2236ef7c7ff6SStefan Hajnoczi } 2237ef7c7ff6SStefan Hajnoczi 2238d7bce999SEric Blake static void property_set_alias(Object *obj, Visitor *v, const char *name, 2239d7bce999SEric Blake void *opaque, Error **errp) 2240ef7c7ff6SStefan Hajnoczi { 2241ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2242ef7c7ff6SStefan Hajnoczi 2243ef7c7ff6SStefan Hajnoczi object_property_set(prop->target_obj, v, prop->target_name, errp); 2244ef7c7ff6SStefan Hajnoczi } 2245ef7c7ff6SStefan Hajnoczi 224664607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque, 224764607d08SPaolo Bonzini const gchar *part) 224864607d08SPaolo Bonzini { 224964607d08SPaolo Bonzini AliasProperty *prop = opaque; 225064607d08SPaolo Bonzini 225164607d08SPaolo Bonzini return object_resolve_path_component(prop->target_obj, prop->target_name); 225264607d08SPaolo Bonzini } 225364607d08SPaolo Bonzini 2254ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque) 2255ef7c7ff6SStefan Hajnoczi { 2256ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2257ef7c7ff6SStefan Hajnoczi 22581590d266SEduardo Habkost g_free(prop->target_name); 2259ef7c7ff6SStefan Hajnoczi g_free(prop); 2260ef7c7ff6SStefan Hajnoczi } 2261ef7c7ff6SStefan Hajnoczi 2262ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name, 2263ef7c7ff6SStefan Hajnoczi Object *target_obj, const char *target_name, 2264ef7c7ff6SStefan Hajnoczi Error **errp) 2265ef7c7ff6SStefan Hajnoczi { 2266ef7c7ff6SStefan Hajnoczi AliasProperty *prop; 226764607d08SPaolo Bonzini ObjectProperty *op; 2268ef7c7ff6SStefan Hajnoczi ObjectProperty *target_prop; 2269d190698eSPaolo Bonzini gchar *prop_type; 22708ae9a9efSGonglei Error *local_err = NULL; 2271ef7c7ff6SStefan Hajnoczi 2272ef7c7ff6SStefan Hajnoczi target_prop = object_property_find(target_obj, target_name, errp); 2273ef7c7ff6SStefan Hajnoczi if (!target_prop) { 2274ef7c7ff6SStefan Hajnoczi return; 2275ef7c7ff6SStefan Hajnoczi } 2276ef7c7ff6SStefan Hajnoczi 2277d190698eSPaolo Bonzini if (object_property_is_child(target_prop)) { 2278d190698eSPaolo Bonzini prop_type = g_strdup_printf("link%s", 2279d190698eSPaolo Bonzini target_prop->type + strlen("child")); 2280d190698eSPaolo Bonzini } else { 2281d190698eSPaolo Bonzini prop_type = g_strdup(target_prop->type); 2282d190698eSPaolo Bonzini } 2283d190698eSPaolo Bonzini 2284ef7c7ff6SStefan Hajnoczi prop = g_malloc(sizeof(*prop)); 2285ef7c7ff6SStefan Hajnoczi prop->target_obj = target_obj; 22861590d266SEduardo Habkost prop->target_name = g_strdup(target_name); 2287ef7c7ff6SStefan Hajnoczi 2288d190698eSPaolo Bonzini op = object_property_add(obj, name, prop_type, 2289ef7c7ff6SStefan Hajnoczi property_get_alias, 2290ef7c7ff6SStefan Hajnoczi property_set_alias, 2291ef7c7ff6SStefan Hajnoczi property_release_alias, 22928ae9a9efSGonglei prop, &local_err); 22938ae9a9efSGonglei if (local_err) { 22948ae9a9efSGonglei error_propagate(errp, local_err); 22958ae9a9efSGonglei g_free(prop); 22968ae9a9efSGonglei goto out; 22978ae9a9efSGonglei } 229864607d08SPaolo Bonzini op->resolve = property_resolve_alias; 2299d190698eSPaolo Bonzini 2300a18bb417SAndreas Färber object_property_set_description(obj, op->name, 230180742642SGonglei target_prop->description, 230280742642SGonglei &error_abort); 230380742642SGonglei 23048ae9a9efSGonglei out: 2305d190698eSPaolo Bonzini g_free(prop_type); 2306ef7c7ff6SStefan Hajnoczi } 2307ef7c7ff6SStefan Hajnoczi 230880742642SGonglei void object_property_set_description(Object *obj, const char *name, 230980742642SGonglei const char *description, Error **errp) 231080742642SGonglei { 231180742642SGonglei ObjectProperty *op; 231280742642SGonglei 231380742642SGonglei op = object_property_find(obj, name, errp); 231480742642SGonglei if (!op) { 231580742642SGonglei return; 231680742642SGonglei } 231780742642SGonglei 231880742642SGonglei g_free(op->description); 231980742642SGonglei op->description = g_strdup(description); 232080742642SGonglei } 232180742642SGonglei 232216bf7f52SDaniel P. Berrange void object_class_property_set_description(ObjectClass *klass, 232316bf7f52SDaniel P. Berrange const char *name, 232416bf7f52SDaniel P. Berrange const char *description, 232516bf7f52SDaniel P. Berrange Error **errp) 232616bf7f52SDaniel P. Berrange { 232716bf7f52SDaniel P. Berrange ObjectProperty *op; 232816bf7f52SDaniel P. Berrange 232916bf7f52SDaniel P. Berrange op = g_hash_table_lookup(klass->properties, name); 233016bf7f52SDaniel P. Berrange if (!op) { 233116bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 233216bf7f52SDaniel P. Berrange return; 233316bf7f52SDaniel P. Berrange } 233416bf7f52SDaniel P. Berrange 233516bf7f52SDaniel P. Berrange g_free(op->description); 233616bf7f52SDaniel P. Berrange op->description = g_strdup(description); 233716bf7f52SDaniel P. Berrange } 233816bf7f52SDaniel P. Berrange 23392f262e06SPaolo Bonzini static void object_instance_init(Object *obj) 23402f262e06SPaolo Bonzini { 23412f262e06SPaolo Bonzini object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); 23422f262e06SPaolo Bonzini } 23432f262e06SPaolo Bonzini 2344745549c8SPaolo Bonzini static void register_types(void) 2345745549c8SPaolo Bonzini { 2346745549c8SPaolo Bonzini static TypeInfo interface_info = { 2347745549c8SPaolo Bonzini .name = TYPE_INTERFACE, 234833e95c63SAnthony Liguori .class_size = sizeof(InterfaceClass), 2349745549c8SPaolo Bonzini .abstract = true, 2350745549c8SPaolo Bonzini }; 2351745549c8SPaolo Bonzini 2352745549c8SPaolo Bonzini static TypeInfo object_info = { 2353745549c8SPaolo Bonzini .name = TYPE_OBJECT, 2354745549c8SPaolo Bonzini .instance_size = sizeof(Object), 23552f262e06SPaolo Bonzini .instance_init = object_instance_init, 2356745549c8SPaolo Bonzini .abstract = true, 2357745549c8SPaolo Bonzini }; 2358745549c8SPaolo Bonzini 2359049cb3cfSPaolo Bonzini type_interface = type_register_internal(&interface_info); 2360049cb3cfSPaolo Bonzini type_register_internal(&object_info); 2361745549c8SPaolo Bonzini } 2362745549c8SPaolo Bonzini 2363745549c8SPaolo Bonzini type_init(register_types) 2364