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/qint.h" 317b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h" 327b7b7d18SPaolo Bonzini 332f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 342f28d2ffSAnthony Liguori 352f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 362f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 372f28d2ffSAnthony Liguori 382f28d2ffSAnthony Liguori struct InterfaceImpl 392f28d2ffSAnthony Liguori { 4033e95c63SAnthony Liguori const char *typename; 412f28d2ffSAnthony Liguori }; 422f28d2ffSAnthony Liguori 432f28d2ffSAnthony Liguori struct TypeImpl 442f28d2ffSAnthony Liguori { 452f28d2ffSAnthony Liguori const char *name; 462f28d2ffSAnthony Liguori 472f28d2ffSAnthony Liguori size_t class_size; 482f28d2ffSAnthony Liguori 492f28d2ffSAnthony Liguori size_t instance_size; 502f28d2ffSAnthony Liguori 512f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 523b50e311SPaolo Bonzini void (*class_base_init)(ObjectClass *klass, void *data); 532f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 542f28d2ffSAnthony Liguori 552f28d2ffSAnthony Liguori void *class_data; 562f28d2ffSAnthony Liguori 572f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 588231c2ddSEduardo Habkost void (*instance_post_init)(Object *obj); 592f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 602f28d2ffSAnthony Liguori 612f28d2ffSAnthony Liguori bool abstract; 622f28d2ffSAnthony Liguori 632f28d2ffSAnthony Liguori const char *parent; 642f28d2ffSAnthony Liguori TypeImpl *parent_type; 652f28d2ffSAnthony Liguori 662f28d2ffSAnthony Liguori ObjectClass *class; 672f28d2ffSAnthony Liguori 682f28d2ffSAnthony Liguori int num_interfaces; 692f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 702f28d2ffSAnthony Liguori }; 712f28d2ffSAnthony Liguori 729970bd88SPaolo Bonzini static Type type_interface; 739970bd88SPaolo Bonzini 742f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 752f28d2ffSAnthony Liguori { 762f28d2ffSAnthony Liguori static GHashTable *type_table; 772f28d2ffSAnthony Liguori 782f28d2ffSAnthony Liguori if (type_table == NULL) { 792f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 802f28d2ffSAnthony Liguori } 812f28d2ffSAnthony Liguori 822f28d2ffSAnthony Liguori return type_table; 832f28d2ffSAnthony Liguori } 842f28d2ffSAnthony Liguori 85f54c19caSHervé Poussineau static bool enumerating_types; 86f54c19caSHervé Poussineau 872f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 882f28d2ffSAnthony Liguori { 89f54c19caSHervé Poussineau assert(!enumerating_types); 902f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 912f28d2ffSAnthony Liguori } 922f28d2ffSAnthony Liguori 932f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 942f28d2ffSAnthony Liguori { 952f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 962f28d2ffSAnthony Liguori } 972f28d2ffSAnthony Liguori 98b061dc41SPaolo Bonzini static TypeImpl *type_new(const TypeInfo *info) 992f28d2ffSAnthony Liguori { 1002f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 10133e95c63SAnthony Liguori int i; 1022f28d2ffSAnthony Liguori 1032f28d2ffSAnthony Liguori g_assert(info->name != NULL); 1042f28d2ffSAnthony Liguori 10573093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 10673093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 10773093354SAnthony Liguori abort(); 10873093354SAnthony Liguori } 10973093354SAnthony Liguori 1102f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1112f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1122f28d2ffSAnthony Liguori 1132f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1142f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1152f28d2ffSAnthony Liguori 1162f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1173b50e311SPaolo Bonzini ti->class_base_init = info->class_base_init; 1182f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1192f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1202f28d2ffSAnthony Liguori 1212f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1228231c2ddSEduardo Habkost ti->instance_post_init = info->instance_post_init; 1232f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1242f28d2ffSAnthony Liguori 1252f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1262f28d2ffSAnthony Liguori 12733e95c63SAnthony Liguori for (i = 0; info->interfaces && info->interfaces[i].type; i++) { 12833e95c63SAnthony Liguori ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); 1292f28d2ffSAnthony Liguori } 13033e95c63SAnthony Liguori ti->num_interfaces = i; 1312f28d2ffSAnthony Liguori 132b061dc41SPaolo Bonzini return ti; 133b061dc41SPaolo Bonzini } 1342f28d2ffSAnthony Liguori 135b061dc41SPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info) 136b061dc41SPaolo Bonzini { 137b061dc41SPaolo Bonzini TypeImpl *ti; 138b061dc41SPaolo Bonzini ti = type_new(info); 139b061dc41SPaolo Bonzini 140b061dc41SPaolo Bonzini type_table_add(ti); 1412f28d2ffSAnthony Liguori return ti; 1422f28d2ffSAnthony Liguori } 1432f28d2ffSAnthony Liguori 144049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info) 145049cb3cfSPaolo Bonzini { 146049cb3cfSPaolo Bonzini assert(info->parent); 147049cb3cfSPaolo Bonzini return type_register_internal(info); 148049cb3cfSPaolo Bonzini } 149049cb3cfSPaolo Bonzini 1502f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1512f28d2ffSAnthony Liguori { 1522f28d2ffSAnthony Liguori return type_register(info); 1532f28d2ffSAnthony Liguori } 1542f28d2ffSAnthony Liguori 1552f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1562f28d2ffSAnthony Liguori { 1572f28d2ffSAnthony Liguori if (name == NULL) { 1582f28d2ffSAnthony Liguori return NULL; 1592f28d2ffSAnthony Liguori } 1602f28d2ffSAnthony Liguori 1612f28d2ffSAnthony Liguori return type_table_lookup(name); 1622f28d2ffSAnthony Liguori } 1632f28d2ffSAnthony Liguori 1642f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1652f28d2ffSAnthony Liguori { 1662f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1672f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1682f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1692f28d2ffSAnthony Liguori } 1702f28d2ffSAnthony Liguori 1712f28d2ffSAnthony Liguori return type->parent_type; 1722f28d2ffSAnthony Liguori } 1732f28d2ffSAnthony Liguori 1742f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1752f28d2ffSAnthony Liguori { 1762f28d2ffSAnthony Liguori return (type->parent != NULL); 1772f28d2ffSAnthony Liguori } 1782f28d2ffSAnthony Liguori 1792f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1802f28d2ffSAnthony Liguori { 1812f28d2ffSAnthony Liguori if (ti->class_size) { 1822f28d2ffSAnthony Liguori return ti->class_size; 1832f28d2ffSAnthony Liguori } 1842f28d2ffSAnthony Liguori 1852f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1862f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1872f28d2ffSAnthony Liguori } 1882f28d2ffSAnthony Liguori 1892f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1902f28d2ffSAnthony Liguori } 1912f28d2ffSAnthony Liguori 192aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 193aca59af6SIgor Mitsyanko { 194aca59af6SIgor Mitsyanko if (ti->instance_size) { 195aca59af6SIgor Mitsyanko return ti->instance_size; 196aca59af6SIgor Mitsyanko } 197aca59af6SIgor Mitsyanko 198aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 199aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 200aca59af6SIgor Mitsyanko } 201aca59af6SIgor Mitsyanko 202aca59af6SIgor Mitsyanko return 0; 203aca59af6SIgor Mitsyanko } 204aca59af6SIgor Mitsyanko 2053f97b53aSBharata B Rao size_t object_type_get_instance_size(const char *typename) 2063f97b53aSBharata B Rao { 2073f97b53aSBharata B Rao TypeImpl *type = type_get_by_name(typename); 2083f97b53aSBharata B Rao 2093f97b53aSBharata B Rao g_assert(type != NULL); 2103f97b53aSBharata B Rao return type_object_get_size(type); 2113f97b53aSBharata B Rao } 2123f97b53aSBharata B Rao 21333e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 2142f28d2ffSAnthony Liguori { 21533e95c63SAnthony Liguori assert(target_type); 2162f28d2ffSAnthony Liguori 217b30d8054SCao jin /* Check if target_type is a direct ancestor of type */ 21833e95c63SAnthony Liguori while (type) { 21933e95c63SAnthony Liguori if (type == target_type) { 22033e95c63SAnthony Liguori return true; 22133e95c63SAnthony Liguori } 22233e95c63SAnthony Liguori 22333e95c63SAnthony Liguori type = type_get_parent(type); 22433e95c63SAnthony Liguori } 22533e95c63SAnthony Liguori 22633e95c63SAnthony Liguori return false; 22733e95c63SAnthony Liguori } 22833e95c63SAnthony Liguori 22933e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti); 23033e95c63SAnthony Liguori 231b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, 232b061dc41SPaolo Bonzini TypeImpl *parent_type) 23333e95c63SAnthony Liguori { 23433e95c63SAnthony Liguori InterfaceClass *new_iface; 23533e95c63SAnthony Liguori TypeInfo info = { }; 23633e95c63SAnthony Liguori TypeImpl *iface_impl; 23733e95c63SAnthony Liguori 238b061dc41SPaolo Bonzini info.parent = parent_type->name; 239b061dc41SPaolo Bonzini info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); 24033e95c63SAnthony Liguori info.abstract = true; 24133e95c63SAnthony Liguori 242b061dc41SPaolo Bonzini iface_impl = type_new(&info); 243b061dc41SPaolo Bonzini iface_impl->parent_type = parent_type; 24433e95c63SAnthony Liguori type_initialize(iface_impl); 24533e95c63SAnthony Liguori g_free((char *)info.name); 24633e95c63SAnthony Liguori 24733e95c63SAnthony Liguori new_iface = (InterfaceClass *)iface_impl->class; 24833e95c63SAnthony Liguori new_iface->concrete_class = ti->class; 249b061dc41SPaolo Bonzini new_iface->interface_type = interface_type; 25033e95c63SAnthony Liguori 25133e95c63SAnthony Liguori ti->class->interfaces = g_slist_append(ti->class->interfaces, 25233e95c63SAnthony Liguori iface_impl->class); 2532f28d2ffSAnthony Liguori } 2542f28d2ffSAnthony Liguori 25516bf7f52SDaniel P. Berrange static void object_property_free(gpointer data) 25616bf7f52SDaniel P. Berrange { 25716bf7f52SDaniel P. Berrange ObjectProperty *prop = data; 25816bf7f52SDaniel P. Berrange 25916bf7f52SDaniel P. Berrange g_free(prop->name); 26016bf7f52SDaniel P. Berrange g_free(prop->type); 26116bf7f52SDaniel P. Berrange g_free(prop->description); 26216bf7f52SDaniel P. Berrange g_free(prop); 26316bf7f52SDaniel P. Berrange } 26416bf7f52SDaniel P. Berrange 265ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2662f28d2ffSAnthony Liguori { 267745549c8SPaolo Bonzini TypeImpl *parent; 2682f28d2ffSAnthony Liguori 2692f28d2ffSAnthony Liguori if (ti->class) { 2702f28d2ffSAnthony Liguori return; 2712f28d2ffSAnthony Liguori } 2722f28d2ffSAnthony Liguori 2732f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 274aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2752f28d2ffSAnthony Liguori 2762f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 2772f28d2ffSAnthony Liguori 278745549c8SPaolo Bonzini parent = type_get_parent(ti); 279745549c8SPaolo Bonzini if (parent) { 280ac451033SIgor Mitsyanko type_initialize(parent); 28133e95c63SAnthony Liguori GSList *e; 28233e95c63SAnthony Liguori int i; 2832f28d2ffSAnthony Liguori 2848438a135SAndreas Färber g_assert_cmpint(parent->class_size, <=, ti->class_size); 285745549c8SPaolo Bonzini memcpy(ti->class, parent->class, parent->class_size); 2863e407de4SPeter Crosthwaite ti->class->interfaces = NULL; 28716bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 28816bf7f52SDaniel P. Berrange g_str_hash, g_str_equal, g_free, object_property_free); 28933e95c63SAnthony Liguori 29033e95c63SAnthony Liguori for (e = parent->class->interfaces; e; e = e->next) { 291b061dc41SPaolo Bonzini InterfaceClass *iface = e->data; 292b061dc41SPaolo Bonzini ObjectClass *klass = OBJECT_CLASS(iface); 293b061dc41SPaolo Bonzini 294b061dc41SPaolo Bonzini type_initialize_interface(ti, iface->interface_type, klass->type); 29533e95c63SAnthony Liguori } 29633e95c63SAnthony Liguori 29733e95c63SAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 29833e95c63SAnthony Liguori TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); 29933e95c63SAnthony Liguori for (e = ti->class->interfaces; e; e = e->next) { 30033e95c63SAnthony Liguori TypeImpl *target_type = OBJECT_CLASS(e->data)->type; 30133e95c63SAnthony Liguori 30233e95c63SAnthony Liguori if (type_is_ancestor(target_type, t)) { 30333e95c63SAnthony Liguori break; 30433e95c63SAnthony Liguori } 30533e95c63SAnthony Liguori } 30633e95c63SAnthony Liguori 30733e95c63SAnthony Liguori if (e) { 30833e95c63SAnthony Liguori continue; 30933e95c63SAnthony Liguori } 31033e95c63SAnthony Liguori 311b061dc41SPaolo Bonzini type_initialize_interface(ti, t, t); 31233e95c63SAnthony Liguori } 31316bf7f52SDaniel P. Berrange } else { 31416bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 31516bf7f52SDaniel P. Berrange g_str_hash, g_str_equal, g_free, object_property_free); 316745549c8SPaolo Bonzini } 3172f28d2ffSAnthony Liguori 318745549c8SPaolo Bonzini ti->class->type = ti; 3193b50e311SPaolo Bonzini 3203b50e311SPaolo Bonzini while (parent) { 3213b50e311SPaolo Bonzini if (parent->class_base_init) { 3223b50e311SPaolo Bonzini parent->class_base_init(ti->class, ti->class_data); 3233b50e311SPaolo Bonzini } 3243b50e311SPaolo Bonzini parent = type_get_parent(parent); 3253b50e311SPaolo Bonzini } 3262f28d2ffSAnthony Liguori 3272f28d2ffSAnthony Liguori if (ti->class_init) { 3282f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 3292f28d2ffSAnthony Liguori } 3302f28d2ffSAnthony Liguori } 3312f28d2ffSAnthony Liguori 3322f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 3332f28d2ffSAnthony Liguori { 3342f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 3352f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 3362f28d2ffSAnthony Liguori } 3372f28d2ffSAnthony Liguori 3382f28d2ffSAnthony Liguori if (ti->instance_init) { 3392f28d2ffSAnthony Liguori ti->instance_init(obj); 3402f28d2ffSAnthony Liguori } 3412f28d2ffSAnthony Liguori } 3422f28d2ffSAnthony Liguori 3438231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti) 3448231c2ddSEduardo Habkost { 3458231c2ddSEduardo Habkost if (ti->instance_post_init) { 3468231c2ddSEduardo Habkost ti->instance_post_init(obj); 3478231c2ddSEduardo Habkost } 3488231c2ddSEduardo Habkost 3498231c2ddSEduardo Habkost if (type_has_parent(ti)) { 3508231c2ddSEduardo Habkost object_post_init_with_type(obj, type_get_parent(ti)); 3518231c2ddSEduardo Habkost } 3528231c2ddSEduardo Habkost } 3538231c2ddSEduardo Habkost 3545b9237f6SAndreas Färber void object_initialize_with_type(void *data, size_t size, TypeImpl *type) 3552f28d2ffSAnthony Liguori { 3562f28d2ffSAnthony Liguori Object *obj = data; 3572f28d2ffSAnthony Liguori 3582f28d2ffSAnthony Liguori g_assert(type != NULL); 359ac451033SIgor Mitsyanko type_initialize(type); 360aca59af6SIgor Mitsyanko 3618438a135SAndreas Färber g_assert_cmpint(type->instance_size, >=, sizeof(Object)); 3622f28d2ffSAnthony Liguori g_assert(type->abstract == false); 3638438a135SAndreas Färber g_assert_cmpint(size, >=, type->instance_size); 3642f28d2ffSAnthony Liguori 3652f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 3662f28d2ffSAnthony Liguori obj->class = type->class; 367764b6312SPaolo Bonzini object_ref(obj); 368b604a854SPavel Fedin obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal, 369b604a854SPavel Fedin NULL, object_property_free); 3702f28d2ffSAnthony Liguori object_init_with_type(obj, type); 3718231c2ddSEduardo Habkost object_post_init_with_type(obj, type); 3722f28d2ffSAnthony Liguori } 3732f28d2ffSAnthony Liguori 374213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename) 3752f28d2ffSAnthony Liguori { 3762f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 3772f28d2ffSAnthony Liguori 3785b9237f6SAndreas Färber object_initialize_with_type(data, size, type); 3792f28d2ffSAnthony Liguori } 3802f28d2ffSAnthony Liguori 3815d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop) 3825d9d3f47SAndreas Färber { 3835d9d3f47SAndreas Färber return strstart(prop->type, "child<", NULL); 3845d9d3f47SAndreas Färber } 3855d9d3f47SAndreas Färber 38657c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 38757c9fafeSAnthony Liguori { 388b604a854SPavel Fedin ObjectProperty *prop; 389b604a854SPavel Fedin GHashTableIter iter; 390b604a854SPavel Fedin gpointer key, value; 391b604a854SPavel Fedin bool released; 39257c9fafeSAnthony Liguori 393b604a854SPavel Fedin do { 394b604a854SPavel Fedin released = false; 395b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 396b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 397b604a854SPavel Fedin prop = value; 39857c9fafeSAnthony Liguori if (prop->release) { 39957c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 400b604a854SPavel Fedin prop->release = NULL; 401b604a854SPavel Fedin released = true; 402b604a854SPavel Fedin break; 40357c9fafeSAnthony Liguori } 404b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 405b604a854SPavel Fedin } 406b604a854SPavel Fedin } while (released); 40757c9fafeSAnthony Liguori 408b604a854SPavel Fedin g_hash_table_unref(obj->properties); 40957c9fafeSAnthony Liguori } 41057c9fafeSAnthony Liguori 41157c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 41257c9fafeSAnthony Liguori { 41357c9fafeSAnthony Liguori ObjectProperty *prop; 414b604a854SPavel Fedin GHashTableIter iter; 415b604a854SPavel Fedin gpointer key, value; 41657c9fafeSAnthony Liguori 417b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 418b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 419b604a854SPavel Fedin prop = value; 4205d9d3f47SAndreas Färber if (object_property_is_child(prop) && prop->opaque == child) { 421b604a854SPavel Fedin if (prop->release) { 422b604a854SPavel Fedin prop->release(obj, prop->name, prop->opaque); 423b604a854SPavel Fedin prop->release = NULL; 424b604a854SPavel Fedin } 425b604a854SPavel Fedin break; 426b604a854SPavel Fedin } 427b604a854SPavel Fedin } 428b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 429b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 430b604a854SPavel Fedin prop = value; 431b604a854SPavel Fedin if (object_property_is_child(prop) && prop->opaque == child) { 432b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 4336c1fdcf9SPaolo Bonzini break; 43457c9fafeSAnthony Liguori } 43557c9fafeSAnthony Liguori } 43657c9fafeSAnthony Liguori } 43757c9fafeSAnthony Liguori 43857c9fafeSAnthony Liguori void object_unparent(Object *obj) 43957c9fafeSAnthony Liguori { 440e998fa8dSMichael S. Tsirkin if (obj->parent) { 441e998fa8dSMichael S. Tsirkin object_property_del_child(obj->parent, obj, NULL); 442e998fa8dSMichael S. Tsirkin } 44357c9fafeSAnthony Liguori } 44457c9fafeSAnthony Liguori 4452f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 4462f28d2ffSAnthony Liguori { 4472f28d2ffSAnthony Liguori if (type->instance_finalize) { 4482f28d2ffSAnthony Liguori type->instance_finalize(obj); 4492f28d2ffSAnthony Liguori } 4502f28d2ffSAnthony Liguori 4512f28d2ffSAnthony Liguori if (type_has_parent(type)) { 4522f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 4532f28d2ffSAnthony Liguori } 4542f28d2ffSAnthony Liguori } 4552f28d2ffSAnthony Liguori 456339c2708SPaolo Bonzini static void object_finalize(void *data) 4572f28d2ffSAnthony Liguori { 4582f28d2ffSAnthony Liguori Object *obj = data; 4592f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 4602f28d2ffSAnthony Liguori 46157c9fafeSAnthony Liguori object_property_del_all(obj); 46276a6e1ccSPaolo Bonzini object_deinit(obj, ti); 463db85b575SAnthony Liguori 4648438a135SAndreas Färber g_assert_cmpint(obj->ref, ==, 0); 465fde9bf44SPaolo Bonzini if (obj->free) { 466fde9bf44SPaolo Bonzini obj->free(obj); 467fde9bf44SPaolo Bonzini } 4682f28d2ffSAnthony Liguori } 4692f28d2ffSAnthony Liguori 4702f28d2ffSAnthony Liguori Object *object_new_with_type(Type type) 4712f28d2ffSAnthony Liguori { 4722f28d2ffSAnthony Liguori Object *obj; 4732f28d2ffSAnthony Liguori 4742f28d2ffSAnthony Liguori g_assert(type != NULL); 475ac451033SIgor Mitsyanko type_initialize(type); 4762f28d2ffSAnthony Liguori 4772f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 4785b9237f6SAndreas Färber object_initialize_with_type(obj, type->instance_size, type); 479fde9bf44SPaolo Bonzini obj->free = g_free; 4802f28d2ffSAnthony Liguori 4812f28d2ffSAnthony Liguori return obj; 4822f28d2ffSAnthony Liguori } 4832f28d2ffSAnthony Liguori 4842f28d2ffSAnthony Liguori Object *object_new(const char *typename) 4852f28d2ffSAnthony Liguori { 4862f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 4872f28d2ffSAnthony Liguori 4882f28d2ffSAnthony Liguori return object_new_with_type(ti); 4892f28d2ffSAnthony Liguori } 4902f28d2ffSAnthony Liguori 491a31bdae5SDaniel P. Berrange 492a31bdae5SDaniel P. Berrange Object *object_new_with_props(const char *typename, 493a31bdae5SDaniel P. Berrange Object *parent, 494a31bdae5SDaniel P. Berrange const char *id, 495a31bdae5SDaniel P. Berrange Error **errp, 496a31bdae5SDaniel P. Berrange ...) 497a31bdae5SDaniel P. Berrange { 498a31bdae5SDaniel P. Berrange va_list vargs; 499a31bdae5SDaniel P. Berrange Object *obj; 500a31bdae5SDaniel P. Berrange 501a31bdae5SDaniel P. Berrange va_start(vargs, errp); 502a31bdae5SDaniel P. Berrange obj = object_new_with_propv(typename, parent, id, errp, vargs); 503a31bdae5SDaniel P. Berrange va_end(vargs); 504a31bdae5SDaniel P. Berrange 505a31bdae5SDaniel P. Berrange return obj; 506a31bdae5SDaniel P. Berrange } 507a31bdae5SDaniel P. Berrange 508a31bdae5SDaniel P. Berrange 509a31bdae5SDaniel P. Berrange Object *object_new_with_propv(const char *typename, 510a31bdae5SDaniel P. Berrange Object *parent, 511a31bdae5SDaniel P. Berrange const char *id, 512a31bdae5SDaniel P. Berrange Error **errp, 513a31bdae5SDaniel P. Berrange va_list vargs) 514a31bdae5SDaniel P. Berrange { 515a31bdae5SDaniel P. Berrange Object *obj; 516a31bdae5SDaniel P. Berrange ObjectClass *klass; 517a31bdae5SDaniel P. Berrange Error *local_err = NULL; 518a31bdae5SDaniel P. Berrange 519a31bdae5SDaniel P. Berrange klass = object_class_by_name(typename); 520a31bdae5SDaniel P. Berrange if (!klass) { 521a31bdae5SDaniel P. Berrange error_setg(errp, "invalid object type: %s", typename); 522a31bdae5SDaniel P. Berrange return NULL; 523a31bdae5SDaniel P. Berrange } 524a31bdae5SDaniel P. Berrange 525a31bdae5SDaniel P. Berrange if (object_class_is_abstract(klass)) { 526a31bdae5SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", typename); 527a31bdae5SDaniel P. Berrange return NULL; 528a31bdae5SDaniel P. Berrange } 529a31bdae5SDaniel P. Berrange obj = object_new(typename); 530a31bdae5SDaniel P. Berrange 531a31bdae5SDaniel P. Berrange if (object_set_propv(obj, &local_err, vargs) < 0) { 532a31bdae5SDaniel P. Berrange goto error; 533a31bdae5SDaniel P. Berrange } 534a31bdae5SDaniel P. Berrange 535a31bdae5SDaniel P. Berrange object_property_add_child(parent, id, obj, &local_err); 536a31bdae5SDaniel P. Berrange if (local_err) { 537a31bdae5SDaniel P. Berrange goto error; 538a31bdae5SDaniel P. Berrange } 539a31bdae5SDaniel P. Berrange 540a31bdae5SDaniel P. Berrange if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { 541a31bdae5SDaniel P. Berrange user_creatable_complete(obj, &local_err); 542a31bdae5SDaniel P. Berrange if (local_err) { 543a31bdae5SDaniel P. Berrange object_unparent(obj); 544a31bdae5SDaniel P. Berrange goto error; 545a31bdae5SDaniel P. Berrange } 546a31bdae5SDaniel P. Berrange } 547a31bdae5SDaniel P. Berrange 548a31bdae5SDaniel P. Berrange object_unref(OBJECT(obj)); 549a31bdae5SDaniel P. Berrange return obj; 550a31bdae5SDaniel P. Berrange 551a31bdae5SDaniel P. Berrange error: 552a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 553a31bdae5SDaniel P. Berrange object_unref(obj); 554a31bdae5SDaniel P. Berrange return NULL; 555a31bdae5SDaniel P. Berrange } 556a31bdae5SDaniel P. Berrange 557a31bdae5SDaniel P. Berrange 558a31bdae5SDaniel P. Berrange int object_set_props(Object *obj, 559a31bdae5SDaniel P. Berrange Error **errp, 560a31bdae5SDaniel P. Berrange ...) 561a31bdae5SDaniel P. Berrange { 562a31bdae5SDaniel P. Berrange va_list vargs; 563a31bdae5SDaniel P. Berrange int ret; 564a31bdae5SDaniel P. Berrange 565a31bdae5SDaniel P. Berrange va_start(vargs, errp); 566a31bdae5SDaniel P. Berrange ret = object_set_propv(obj, errp, vargs); 567a31bdae5SDaniel P. Berrange va_end(vargs); 568a31bdae5SDaniel P. Berrange 569a31bdae5SDaniel P. Berrange return ret; 570a31bdae5SDaniel P. Berrange } 571a31bdae5SDaniel P. Berrange 572a31bdae5SDaniel P. Berrange 573a31bdae5SDaniel P. Berrange int object_set_propv(Object *obj, 574a31bdae5SDaniel P. Berrange Error **errp, 575a31bdae5SDaniel P. Berrange va_list vargs) 576a31bdae5SDaniel P. Berrange { 577a31bdae5SDaniel P. Berrange const char *propname; 578a31bdae5SDaniel P. Berrange Error *local_err = NULL; 579a31bdae5SDaniel P. Berrange 580a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 581a31bdae5SDaniel P. Berrange while (propname != NULL) { 582a31bdae5SDaniel P. Berrange const char *value = va_arg(vargs, char *); 583a31bdae5SDaniel P. Berrange 584a31bdae5SDaniel P. Berrange g_assert(value != NULL); 585a31bdae5SDaniel P. Berrange object_property_parse(obj, value, propname, &local_err); 586a31bdae5SDaniel P. Berrange if (local_err) { 587a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 588a31bdae5SDaniel P. Berrange return -1; 589a31bdae5SDaniel P. Berrange } 590a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 591a31bdae5SDaniel P. Berrange } 592a31bdae5SDaniel P. Berrange 593a31bdae5SDaniel P. Berrange return 0; 594a31bdae5SDaniel P. Berrange } 595a31bdae5SDaniel P. Berrange 596a31bdae5SDaniel P. Berrange 5972f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 5982f28d2ffSAnthony Liguori { 599b7f43fe4SPaolo Bonzini if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { 600acc4af3fSPaolo Bonzini return obj; 601acc4af3fSPaolo Bonzini } 602acc4af3fSPaolo Bonzini 6032f28d2ffSAnthony Liguori return NULL; 6042f28d2ffSAnthony Liguori } 6052f28d2ffSAnthony Liguori 606be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename, 607be17f18bSPaolo Bonzini const char *file, int line, const char *func) 6082f28d2ffSAnthony Liguori { 609fa131d94SPaolo Bonzini trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", 610fa131d94SPaolo Bonzini typename, file, line, func); 611fa131d94SPaolo Bonzini 6123556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG 61303587328SAnthony Liguori int i; 61403587328SAnthony Liguori Object *inst; 61503587328SAnthony Liguori 61695916abcSPeter Crosthwaite for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { 617*b6b3ccfdSAlex Bennée if (atomic_read(&obj->class->object_cast_cache[i]) == typename) { 61803587328SAnthony Liguori goto out; 61903587328SAnthony Liguori } 62003587328SAnthony Liguori } 62103587328SAnthony Liguori 62203587328SAnthony Liguori inst = object_dynamic_cast(obj, typename); 6232f28d2ffSAnthony Liguori 624b7f43fe4SPaolo Bonzini if (!inst && obj) { 625be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 626be17f18bSPaolo Bonzini file, line, func, obj, typename); 6272f28d2ffSAnthony Liguori abort(); 6282f28d2ffSAnthony Liguori } 6292f28d2ffSAnthony Liguori 6303556c233SPaolo Bonzini assert(obj == inst); 63103587328SAnthony Liguori 63295916abcSPeter Crosthwaite if (obj && obj == inst) { 63303587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 634*b6b3ccfdSAlex Bennée atomic_set(&obj->class->object_cast_cache[i - 1], 635*b6b3ccfdSAlex Bennée atomic_read(&obj->class->object_cast_cache[i])); 63603587328SAnthony Liguori } 637*b6b3ccfdSAlex Bennée atomic_set(&obj->class->object_cast_cache[i - 1], typename); 63803587328SAnthony Liguori } 63903587328SAnthony Liguori 64003587328SAnthony Liguori out: 6413556c233SPaolo Bonzini #endif 6423556c233SPaolo Bonzini return obj; 6432f28d2ffSAnthony Liguori } 6442f28d2ffSAnthony Liguori 6452f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 6462f28d2ffSAnthony Liguori const char *typename) 6472f28d2ffSAnthony Liguori { 64833e95c63SAnthony Liguori ObjectClass *ret = NULL; 649bf0fda34SPaolo Bonzini TypeImpl *target_type; 650bf0fda34SPaolo Bonzini TypeImpl *type; 6512f28d2ffSAnthony Liguori 652bf0fda34SPaolo Bonzini if (!class) { 653bf0fda34SPaolo Bonzini return NULL; 654bf0fda34SPaolo Bonzini } 655bf0fda34SPaolo Bonzini 656793c96b5SPaolo Bonzini /* A simple fast path that can trigger a lot for leaf classes. */ 657bf0fda34SPaolo Bonzini type = class->type; 658793c96b5SPaolo Bonzini if (type->name == typename) { 659793c96b5SPaolo Bonzini return class; 660793c96b5SPaolo Bonzini } 661793c96b5SPaolo Bonzini 662bf0fda34SPaolo Bonzini target_type = type_get_by_name(typename); 6639ab880b3SAlexander Graf if (!target_type) { 6649ab880b3SAlexander Graf /* target class type unknown, so fail the cast */ 6659ab880b3SAlexander Graf return NULL; 6669ab880b3SAlexander Graf } 6679ab880b3SAlexander Graf 66800e2ceaeSPeter Crosthwaite if (type->class->interfaces && 66900e2ceaeSPeter Crosthwaite type_is_ancestor(target_type, type_interface)) { 67033e95c63SAnthony Liguori int found = 0; 67133e95c63SAnthony Liguori GSList *i; 67233e95c63SAnthony Liguori 67333e95c63SAnthony Liguori for (i = class->interfaces; i; i = i->next) { 67433e95c63SAnthony Liguori ObjectClass *target_class = i->data; 67533e95c63SAnthony Liguori 67633e95c63SAnthony Liguori if (type_is_ancestor(target_class->type, target_type)) { 67733e95c63SAnthony Liguori ret = target_class; 67833e95c63SAnthony Liguori found++; 67933e95c63SAnthony Liguori } 6802f28d2ffSAnthony Liguori } 6812f28d2ffSAnthony Liguori 68233e95c63SAnthony Liguori /* The match was ambiguous, don't allow a cast */ 68333e95c63SAnthony Liguori if (found > 1) { 68433e95c63SAnthony Liguori ret = NULL; 68533e95c63SAnthony Liguori } 68633e95c63SAnthony Liguori } else if (type_is_ancestor(type, target_type)) { 68733e95c63SAnthony Liguori ret = class; 6882f28d2ffSAnthony Liguori } 6892f28d2ffSAnthony Liguori 69033e95c63SAnthony Liguori return ret; 6912f28d2ffSAnthony Liguori } 6922f28d2ffSAnthony Liguori 6932f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 694be17f18bSPaolo Bonzini const char *typename, 695be17f18bSPaolo Bonzini const char *file, int line, 696be17f18bSPaolo Bonzini const char *func) 6972f28d2ffSAnthony Liguori { 698fa131d94SPaolo Bonzini ObjectClass *ret; 6992f28d2ffSAnthony Liguori 700fa131d94SPaolo Bonzini trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", 701fa131d94SPaolo Bonzini typename, file, line, func); 702fa131d94SPaolo Bonzini 70303587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 70403587328SAnthony Liguori int i; 70503587328SAnthony Liguori 7069d6a3d58SPeter Crosthwaite for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { 707*b6b3ccfdSAlex Bennée if (atomic_read(&class->class_cast_cache[i]) == typename) { 70803587328SAnthony Liguori ret = class; 70903587328SAnthony Liguori goto out; 71003587328SAnthony Liguori } 71103587328SAnthony Liguori } 71203587328SAnthony Liguori #else 7139d6a3d58SPeter Crosthwaite if (!class || !class->interfaces) { 7143556c233SPaolo Bonzini return class; 7153556c233SPaolo Bonzini } 7163556c233SPaolo Bonzini #endif 7173556c233SPaolo Bonzini 718fa131d94SPaolo Bonzini ret = object_class_dynamic_cast(class, typename); 719bf0fda34SPaolo Bonzini if (!ret && class) { 720be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 721be17f18bSPaolo Bonzini file, line, func, class, typename); 7222f28d2ffSAnthony Liguori abort(); 7232f28d2ffSAnthony Liguori } 7242f28d2ffSAnthony Liguori 72503587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 7269d6a3d58SPeter Crosthwaite if (class && ret == class) { 72703587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 728*b6b3ccfdSAlex Bennée atomic_set(&class->class_cast_cache[i - 1], 729*b6b3ccfdSAlex Bennée atomic_read(&class->class_cast_cache[i])); 73003587328SAnthony Liguori } 731*b6b3ccfdSAlex Bennée atomic_set(&class->class_cast_cache[i - 1], typename); 73203587328SAnthony Liguori } 73303587328SAnthony Liguori out: 73403587328SAnthony Liguori #endif 7352f28d2ffSAnthony Liguori return ret; 7362f28d2ffSAnthony Liguori } 7372f28d2ffSAnthony Liguori 7382f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj) 7392f28d2ffSAnthony Liguori { 7402f28d2ffSAnthony Liguori return obj->class->type->name; 7412f28d2ffSAnthony Liguori } 7422f28d2ffSAnthony Liguori 7432f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 7442f28d2ffSAnthony Liguori { 7452f28d2ffSAnthony Liguori return obj->class; 7462f28d2ffSAnthony Liguori } 7472f28d2ffSAnthony Liguori 74817862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass) 74917862378SAndreas Färber { 75017862378SAndreas Färber return klass->type->abstract; 75117862378SAndreas Färber } 75217862378SAndreas Färber 7532f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 7542f28d2ffSAnthony Liguori { 7552f28d2ffSAnthony Liguori return klass->type->name; 7562f28d2ffSAnthony Liguori } 7572f28d2ffSAnthony Liguori 7582f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 7592f28d2ffSAnthony Liguori { 7602f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 7612f28d2ffSAnthony Liguori 7622f28d2ffSAnthony Liguori if (!type) { 7632f28d2ffSAnthony Liguori return NULL; 7642f28d2ffSAnthony Liguori } 7652f28d2ffSAnthony Liguori 766ac451033SIgor Mitsyanko type_initialize(type); 7672f28d2ffSAnthony Liguori 7682f28d2ffSAnthony Liguori return type->class; 7692f28d2ffSAnthony Liguori } 7702f28d2ffSAnthony Liguori 771e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class) 772e7cce67fSPaolo Bonzini { 773e7cce67fSPaolo Bonzini TypeImpl *type = type_get_parent(class->type); 774e7cce67fSPaolo Bonzini 775e7cce67fSPaolo Bonzini if (!type) { 776e7cce67fSPaolo Bonzini return NULL; 777e7cce67fSPaolo Bonzini } 778e7cce67fSPaolo Bonzini 779e7cce67fSPaolo Bonzini type_initialize(type); 780e7cce67fSPaolo Bonzini 781e7cce67fSPaolo Bonzini return type->class; 782e7cce67fSPaolo Bonzini } 783e7cce67fSPaolo Bonzini 7842f28d2ffSAnthony Liguori typedef struct OCFData 7852f28d2ffSAnthony Liguori { 7862f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 78793c511a1SAnthony Liguori const char *implements_type; 78893c511a1SAnthony Liguori bool include_abstract; 7892f28d2ffSAnthony Liguori void *opaque; 7902f28d2ffSAnthony Liguori } OCFData; 7912f28d2ffSAnthony Liguori 7922f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 7932f28d2ffSAnthony Liguori gpointer opaque) 7942f28d2ffSAnthony Liguori { 7952f28d2ffSAnthony Liguori OCFData *data = opaque; 7962f28d2ffSAnthony Liguori TypeImpl *type = value; 79793c511a1SAnthony Liguori ObjectClass *k; 7982f28d2ffSAnthony Liguori 799ac451033SIgor Mitsyanko type_initialize(type); 80093c511a1SAnthony Liguori k = type->class; 8012f28d2ffSAnthony Liguori 80293c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 80393c511a1SAnthony Liguori return; 80493c511a1SAnthony Liguori } 80593c511a1SAnthony Liguori 80693c511a1SAnthony Liguori if (data->implements_type && 80793c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 80893c511a1SAnthony Liguori return; 80993c511a1SAnthony Liguori } 81093c511a1SAnthony Liguori 81193c511a1SAnthony Liguori data->fn(k, data->opaque); 8122f28d2ffSAnthony Liguori } 8132f28d2ffSAnthony Liguori 8142f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 81593c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 8162f28d2ffSAnthony Liguori void *opaque) 8172f28d2ffSAnthony Liguori { 81893c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 8192f28d2ffSAnthony Liguori 820f54c19caSHervé Poussineau enumerating_types = true; 8212f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 822f54c19caSHervé Poussineau enumerating_types = false; 8232f28d2ffSAnthony Liguori } 82457c9fafeSAnthony Liguori 825d714b8deSPeter Crosthwaite static int do_object_child_foreach(Object *obj, 826d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 827d714b8deSPeter Crosthwaite void *opaque, bool recurse) 82832efc535SPaolo Bonzini { 829b604a854SPavel Fedin GHashTableIter iter; 830b604a854SPavel Fedin ObjectProperty *prop; 83132efc535SPaolo Bonzini int ret = 0; 83232efc535SPaolo Bonzini 833b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 834b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 83532efc535SPaolo Bonzini if (object_property_is_child(prop)) { 836d714b8deSPeter Crosthwaite Object *child = prop->opaque; 837d714b8deSPeter Crosthwaite 838d714b8deSPeter Crosthwaite ret = fn(child, opaque); 83932efc535SPaolo Bonzini if (ret != 0) { 84032efc535SPaolo Bonzini break; 84132efc535SPaolo Bonzini } 842d714b8deSPeter Crosthwaite if (recurse) { 843d714b8deSPeter Crosthwaite do_object_child_foreach(child, fn, opaque, true); 844d714b8deSPeter Crosthwaite } 84532efc535SPaolo Bonzini } 84632efc535SPaolo Bonzini } 84732efc535SPaolo Bonzini return ret; 84832efc535SPaolo Bonzini } 84932efc535SPaolo Bonzini 850d714b8deSPeter Crosthwaite int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), 851d714b8deSPeter Crosthwaite void *opaque) 852d714b8deSPeter Crosthwaite { 853d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, false); 854d714b8deSPeter Crosthwaite } 855d714b8deSPeter Crosthwaite 856d714b8deSPeter Crosthwaite int object_child_foreach_recursive(Object *obj, 857d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 858d714b8deSPeter Crosthwaite void *opaque) 859d714b8deSPeter Crosthwaite { 860d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, true); 861d714b8deSPeter Crosthwaite } 862d714b8deSPeter Crosthwaite 863418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 864418ba9e5SAndreas Färber { 865418ba9e5SAndreas Färber GSList **list = opaque; 866418ba9e5SAndreas Färber 867418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 868418ba9e5SAndreas Färber } 869418ba9e5SAndreas Färber 870418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 871418ba9e5SAndreas Färber bool include_abstract) 872418ba9e5SAndreas Färber { 873418ba9e5SAndreas Färber GSList *list = NULL; 874418ba9e5SAndreas Färber 875418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 876418ba9e5SAndreas Färber implements_type, include_abstract, &list); 877418ba9e5SAndreas Färber return list; 878418ba9e5SAndreas Färber } 879418ba9e5SAndreas Färber 88057c9fafeSAnthony Liguori void object_ref(Object *obj) 88157c9fafeSAnthony Liguori { 8828ffad850SPeter Crosthwaite if (!obj) { 8838ffad850SPeter Crosthwaite return; 8848ffad850SPeter Crosthwaite } 885f08c03f3SJan Kiszka atomic_inc(&obj->ref); 88657c9fafeSAnthony Liguori } 88757c9fafeSAnthony Liguori 88857c9fafeSAnthony Liguori void object_unref(Object *obj) 88957c9fafeSAnthony Liguori { 8908ffad850SPeter Crosthwaite if (!obj) { 8918ffad850SPeter Crosthwaite return; 8928ffad850SPeter Crosthwaite } 8938438a135SAndreas Färber g_assert_cmpint(obj->ref, >, 0); 89457c9fafeSAnthony Liguori 89557c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 896f08c03f3SJan Kiszka if (atomic_fetch_dec(&obj->ref) == 1) { 89757c9fafeSAnthony Liguori object_finalize(obj); 89857c9fafeSAnthony Liguori } 89957c9fafeSAnthony Liguori } 90057c9fafeSAnthony Liguori 90164607d08SPaolo Bonzini ObjectProperty * 90264607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type, 90357c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 90457c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 90557c9fafeSAnthony Liguori ObjectPropertyRelease *release, 90657c9fafeSAnthony Liguori void *opaque, Error **errp) 90757c9fafeSAnthony Liguori { 90854852b03SPeter Maydell ObjectProperty *prop; 90933965904SPeter Crosthwaite size_t name_len = strlen(name); 91033965904SPeter Crosthwaite 91133965904SPeter Crosthwaite if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { 91233965904SPeter Crosthwaite int i; 91333965904SPeter Crosthwaite ObjectProperty *ret; 91433965904SPeter Crosthwaite char *name_no_array = g_strdup(name); 91533965904SPeter Crosthwaite 91633965904SPeter Crosthwaite name_no_array[name_len - 3] = '\0'; 91733965904SPeter Crosthwaite for (i = 0; ; ++i) { 91833965904SPeter Crosthwaite char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); 91933965904SPeter Crosthwaite 92033965904SPeter Crosthwaite ret = object_property_add(obj, full_name, type, get, set, 92133965904SPeter Crosthwaite release, opaque, NULL); 92233965904SPeter Crosthwaite g_free(full_name); 92333965904SPeter Crosthwaite if (ret) { 92433965904SPeter Crosthwaite break; 92533965904SPeter Crosthwaite } 92633965904SPeter Crosthwaite } 92733965904SPeter Crosthwaite g_free(name_no_array); 92833965904SPeter Crosthwaite return ret; 92933965904SPeter Crosthwaite } 93054852b03SPeter Maydell 93116bf7f52SDaniel P. Berrange if (object_property_find(obj, name, NULL) != NULL) { 93254852b03SPeter Maydell error_setg(errp, "attempt to add duplicate property '%s'" 93354852b03SPeter Maydell " to object (type '%s')", name, 93454852b03SPeter Maydell object_get_typename(obj)); 93564607d08SPaolo Bonzini return NULL; 93654852b03SPeter Maydell } 93754852b03SPeter Maydell 93854852b03SPeter Maydell prop = g_malloc0(sizeof(*prop)); 93957c9fafeSAnthony Liguori 94057c9fafeSAnthony Liguori prop->name = g_strdup(name); 94157c9fafeSAnthony Liguori prop->type = g_strdup(type); 94257c9fafeSAnthony Liguori 94357c9fafeSAnthony Liguori prop->get = get; 94457c9fafeSAnthony Liguori prop->set = set; 94557c9fafeSAnthony Liguori prop->release = release; 94657c9fafeSAnthony Liguori prop->opaque = opaque; 94757c9fafeSAnthony Liguori 948b604a854SPavel Fedin g_hash_table_insert(obj->properties, prop->name, prop); 94964607d08SPaolo Bonzini return prop; 95057c9fafeSAnthony Liguori } 95157c9fafeSAnthony Liguori 95216bf7f52SDaniel P. Berrange ObjectProperty * 95316bf7f52SDaniel P. Berrange object_class_property_add(ObjectClass *klass, 95416bf7f52SDaniel P. Berrange const char *name, 95516bf7f52SDaniel P. Berrange const char *type, 95616bf7f52SDaniel P. Berrange ObjectPropertyAccessor *get, 95716bf7f52SDaniel P. Berrange ObjectPropertyAccessor *set, 95816bf7f52SDaniel P. Berrange ObjectPropertyRelease *release, 95916bf7f52SDaniel P. Berrange void *opaque, 96016bf7f52SDaniel P. Berrange Error **errp) 96116bf7f52SDaniel P. Berrange { 96216bf7f52SDaniel P. Berrange ObjectProperty *prop; 96316bf7f52SDaniel P. Berrange 96416bf7f52SDaniel P. Berrange if (object_class_property_find(klass, name, NULL) != NULL) { 96516bf7f52SDaniel P. Berrange error_setg(errp, "attempt to add duplicate property '%s'" 96616bf7f52SDaniel P. Berrange " to object (type '%s')", name, 96716bf7f52SDaniel P. Berrange object_class_get_name(klass)); 96816bf7f52SDaniel P. Berrange return NULL; 96916bf7f52SDaniel P. Berrange } 97016bf7f52SDaniel P. Berrange 97116bf7f52SDaniel P. Berrange prop = g_malloc0(sizeof(*prop)); 97216bf7f52SDaniel P. Berrange 97316bf7f52SDaniel P. Berrange prop->name = g_strdup(name); 97416bf7f52SDaniel P. Berrange prop->type = g_strdup(type); 97516bf7f52SDaniel P. Berrange 97616bf7f52SDaniel P. Berrange prop->get = get; 97716bf7f52SDaniel P. Berrange prop->set = set; 97816bf7f52SDaniel P. Berrange prop->release = release; 97916bf7f52SDaniel P. Berrange prop->opaque = opaque; 98016bf7f52SDaniel P. Berrange 98116bf7f52SDaniel P. Berrange g_hash_table_insert(klass->properties, g_strdup(name), prop); 98216bf7f52SDaniel P. Berrange 98316bf7f52SDaniel P. Berrange return prop; 98416bf7f52SDaniel P. Berrange } 98516bf7f52SDaniel P. Berrange 98689bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name, 98789bfe000SPaolo Bonzini Error **errp) 98857c9fafeSAnthony Liguori { 98957c9fafeSAnthony Liguori ObjectProperty *prop; 99016bf7f52SDaniel P. Berrange ObjectClass *klass = object_get_class(obj); 99116bf7f52SDaniel P. Berrange 99216bf7f52SDaniel P. Berrange prop = object_class_property_find(klass, name, NULL); 99316bf7f52SDaniel P. Berrange if (prop) { 99416bf7f52SDaniel P. Berrange return prop; 99516bf7f52SDaniel P. Berrange } 99657c9fafeSAnthony Liguori 997b604a854SPavel Fedin prop = g_hash_table_lookup(obj->properties, name); 998b604a854SPavel Fedin if (prop) { 99957c9fafeSAnthony Liguori return prop; 100057c9fafeSAnthony Liguori } 100157c9fafeSAnthony Liguori 1002f231b88dSCole Robinson error_setg(errp, "Property '.%s' not found", name); 100357c9fafeSAnthony Liguori return NULL; 100457c9fafeSAnthony Liguori } 100557c9fafeSAnthony Liguori 10067746abd8SDaniel P. Berrange void object_property_iter_init(ObjectPropertyIterator *iter, 10077746abd8SDaniel P. Berrange Object *obj) 1008a00c9482SDaniel P. Berrange { 10097746abd8SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, obj->properties); 10107746abd8SDaniel P. Berrange iter->nextclass = object_get_class(obj); 1011a00c9482SDaniel P. Berrange } 1012a00c9482SDaniel P. Berrange 1013a00c9482SDaniel P. Berrange ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) 1014a00c9482SDaniel P. Berrange { 1015b604a854SPavel Fedin gpointer key, val; 101616bf7f52SDaniel P. Berrange while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { 101716bf7f52SDaniel P. Berrange if (!iter->nextclass) { 1018b604a854SPavel Fedin return NULL; 1019a00c9482SDaniel P. Berrange } 102016bf7f52SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, iter->nextclass->properties); 102116bf7f52SDaniel P. Berrange iter->nextclass = object_class_get_parent(iter->nextclass); 102216bf7f52SDaniel P. Berrange } 1023b604a854SPavel Fedin return val; 1024a00c9482SDaniel P. Berrange } 1025a00c9482SDaniel P. Berrange 102616bf7f52SDaniel P. Berrange ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, 102716bf7f52SDaniel P. Berrange Error **errp) 102816bf7f52SDaniel P. Berrange { 102916bf7f52SDaniel P. Berrange ObjectProperty *prop; 103016bf7f52SDaniel P. Berrange ObjectClass *parent_klass; 103116bf7f52SDaniel P. Berrange 103216bf7f52SDaniel P. Berrange parent_klass = object_class_get_parent(klass); 103316bf7f52SDaniel P. Berrange if (parent_klass) { 103416bf7f52SDaniel P. Berrange prop = object_class_property_find(parent_klass, name, NULL); 103516bf7f52SDaniel P. Berrange if (prop) { 103616bf7f52SDaniel P. Berrange return prop; 103716bf7f52SDaniel P. Berrange } 103816bf7f52SDaniel P. Berrange } 103916bf7f52SDaniel P. Berrange 104016bf7f52SDaniel P. Berrange prop = g_hash_table_lookup(klass->properties, name); 104116bf7f52SDaniel P. Berrange if (!prop) { 104216bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 104316bf7f52SDaniel P. Berrange } 104416bf7f52SDaniel P. Berrange return prop; 104516bf7f52SDaniel P. Berrange } 104616bf7f52SDaniel P. Berrange 104757c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 104857c9fafeSAnthony Liguori { 1049b604a854SPavel Fedin ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); 1050b604a854SPavel Fedin 1051b604a854SPavel Fedin if (!prop) { 1052b604a854SPavel Fedin error_setg(errp, "Property '.%s' not found", name); 10530866aca1SAnthony Liguori return; 10540866aca1SAnthony Liguori } 105557c9fafeSAnthony Liguori 10560866aca1SAnthony Liguori if (prop->release) { 10570866aca1SAnthony Liguori prop->release(obj, name, prop->opaque); 10580866aca1SAnthony Liguori } 1059b604a854SPavel Fedin g_hash_table_remove(obj->properties, name); 106057c9fafeSAnthony Liguori } 106157c9fafeSAnthony Liguori 106257c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 106357c9fafeSAnthony Liguori Error **errp) 106457c9fafeSAnthony Liguori { 106589bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 106657c9fafeSAnthony Liguori if (prop == NULL) { 106757c9fafeSAnthony Liguori return; 106857c9fafeSAnthony Liguori } 106957c9fafeSAnthony Liguori 107057c9fafeSAnthony Liguori if (!prop->get) { 1071c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 107257c9fafeSAnthony Liguori } else { 1073d7bce999SEric Blake prop->get(obj, v, name, prop->opaque, errp); 107457c9fafeSAnthony Liguori } 107557c9fafeSAnthony Liguori } 107657c9fafeSAnthony Liguori 107757c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 107857c9fafeSAnthony Liguori Error **errp) 107957c9fafeSAnthony Liguori { 108089bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 108157c9fafeSAnthony Liguori if (prop == NULL) { 108257c9fafeSAnthony Liguori return; 108357c9fafeSAnthony Liguori } 108457c9fafeSAnthony Liguori 108557c9fafeSAnthony Liguori if (!prop->set) { 1086c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 108757c9fafeSAnthony Liguori } else { 1088d7bce999SEric Blake prop->set(obj, v, name, prop->opaque, errp); 108957c9fafeSAnthony Liguori } 109057c9fafeSAnthony Liguori } 109157c9fafeSAnthony Liguori 10927b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 10937b7b7d18SPaolo Bonzini const char *name, Error **errp) 10947b7b7d18SPaolo Bonzini { 10957b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 10967b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 10977b7b7d18SPaolo Bonzini 10987b7b7d18SPaolo Bonzini QDECREF(qstr); 10997b7b7d18SPaolo Bonzini } 11007b7b7d18SPaolo Bonzini 11017b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 11027b7b7d18SPaolo Bonzini Error **errp) 11037b7b7d18SPaolo Bonzini { 11047b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11057b7b7d18SPaolo Bonzini QString *qstring; 11067b7b7d18SPaolo Bonzini char *retval; 11077b7b7d18SPaolo Bonzini 11087b7b7d18SPaolo Bonzini if (!ret) { 11097b7b7d18SPaolo Bonzini return NULL; 11107b7b7d18SPaolo Bonzini } 11117b7b7d18SPaolo Bonzini qstring = qobject_to_qstring(ret); 11127b7b7d18SPaolo Bonzini if (!qstring) { 1113c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 11147b7b7d18SPaolo Bonzini retval = NULL; 11157b7b7d18SPaolo Bonzini } else { 11167b7b7d18SPaolo Bonzini retval = g_strdup(qstring_get_str(qstring)); 11177b7b7d18SPaolo Bonzini } 11187b7b7d18SPaolo Bonzini 11197b7b7d18SPaolo Bonzini QDECREF(qstring); 11207b7b7d18SPaolo Bonzini return retval; 11217b7b7d18SPaolo Bonzini } 11227b7b7d18SPaolo Bonzini 11231d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 11241d9c5a12SPaolo Bonzini const char *name, Error **errp) 11251d9c5a12SPaolo Bonzini { 1126d3c49316SPeter Crosthwaite if (value) { 11272d3aa28cSVlad Yasevich gchar *path = object_get_canonical_path(value); 11282d3aa28cSVlad Yasevich object_property_set_str(obj, path, name, errp); 11292d3aa28cSVlad Yasevich g_free(path); 1130d3c49316SPeter Crosthwaite } else { 1131d3c49316SPeter Crosthwaite object_property_set_str(obj, "", name, errp); 1132d3c49316SPeter Crosthwaite } 11331d9c5a12SPaolo Bonzini } 11341d9c5a12SPaolo Bonzini 11351d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 11361d9c5a12SPaolo Bonzini Error **errp) 11371d9c5a12SPaolo Bonzini { 11381d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 11391d9c5a12SPaolo Bonzini Object *target = NULL; 11401d9c5a12SPaolo Bonzini 11411d9c5a12SPaolo Bonzini if (str && *str) { 11421d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 11431d9c5a12SPaolo Bonzini if (!target) { 114475158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 114575158ebbSMarkus Armbruster "Device '%s' not found", str); 11461d9c5a12SPaolo Bonzini } 11471d9c5a12SPaolo Bonzini } 11481d9c5a12SPaolo Bonzini 11491d9c5a12SPaolo Bonzini g_free(str); 11501d9c5a12SPaolo Bonzini return target; 11511d9c5a12SPaolo Bonzini } 11521d9c5a12SPaolo Bonzini 11537b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 11547b7b7d18SPaolo Bonzini const char *name, Error **errp) 11557b7b7d18SPaolo Bonzini { 1156fc48ffc3SEric Blake QBool *qbool = qbool_from_bool(value); 11577b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 11587b7b7d18SPaolo Bonzini 11597b7b7d18SPaolo Bonzini QDECREF(qbool); 11607b7b7d18SPaolo Bonzini } 11617b7b7d18SPaolo Bonzini 11627b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 11637b7b7d18SPaolo Bonzini Error **errp) 11647b7b7d18SPaolo Bonzini { 11657b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11667b7b7d18SPaolo Bonzini QBool *qbool; 11677b7b7d18SPaolo Bonzini bool retval; 11687b7b7d18SPaolo Bonzini 11697b7b7d18SPaolo Bonzini if (!ret) { 11707b7b7d18SPaolo Bonzini return false; 11717b7b7d18SPaolo Bonzini } 11727b7b7d18SPaolo Bonzini qbool = qobject_to_qbool(ret); 11737b7b7d18SPaolo Bonzini if (!qbool) { 1174c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 11757b7b7d18SPaolo Bonzini retval = false; 11767b7b7d18SPaolo Bonzini } else { 1177fc48ffc3SEric Blake retval = qbool_get_bool(qbool); 11787b7b7d18SPaolo Bonzini } 11797b7b7d18SPaolo Bonzini 11807b7b7d18SPaolo Bonzini QDECREF(qbool); 11817b7b7d18SPaolo Bonzini return retval; 11827b7b7d18SPaolo Bonzini } 11837b7b7d18SPaolo Bonzini 11847b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 11857b7b7d18SPaolo Bonzini const char *name, Error **errp) 11867b7b7d18SPaolo Bonzini { 11877b7b7d18SPaolo Bonzini QInt *qint = qint_from_int(value); 11887b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qint), name, errp); 11897b7b7d18SPaolo Bonzini 11907b7b7d18SPaolo Bonzini QDECREF(qint); 11917b7b7d18SPaolo Bonzini } 11927b7b7d18SPaolo Bonzini 11937b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 11947b7b7d18SPaolo Bonzini Error **errp) 11957b7b7d18SPaolo Bonzini { 11967b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11977b7b7d18SPaolo Bonzini QInt *qint; 11987b7b7d18SPaolo Bonzini int64_t retval; 11997b7b7d18SPaolo Bonzini 12007b7b7d18SPaolo Bonzini if (!ret) { 12017b7b7d18SPaolo Bonzini return -1; 12027b7b7d18SPaolo Bonzini } 12037b7b7d18SPaolo Bonzini qint = qobject_to_qint(ret); 12047b7b7d18SPaolo Bonzini if (!qint) { 1205c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 12067b7b7d18SPaolo Bonzini retval = -1; 12077b7b7d18SPaolo Bonzini } else { 12087b7b7d18SPaolo Bonzini retval = qint_get_int(qint); 12097b7b7d18SPaolo Bonzini } 12107b7b7d18SPaolo Bonzini 12117b7b7d18SPaolo Bonzini QDECREF(qint); 12127b7b7d18SPaolo Bonzini return retval; 12137b7b7d18SPaolo Bonzini } 12147b7b7d18SPaolo Bonzini 1215a8e3fbedSDaniel P. Berrange typedef struct EnumProperty { 1216a8e3fbedSDaniel P. Berrange const char * const *strings; 1217a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **); 1218a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **); 1219a8e3fbedSDaniel P. Berrange } EnumProperty; 1220a8e3fbedSDaniel P. Berrange 12211f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name, 1222a3590dacSDaniel P. Berrange const char *typename, Error **errp) 12231f21772dSHu Tao { 12244715d42eSMarkus Armbruster Error *err = NULL; 12257a0525c7SEric Blake Visitor *v; 1226976620acSChen Fan char *str; 12271f21772dSHu Tao int ret; 1228a3590dacSDaniel P. Berrange ObjectProperty *prop = object_property_find(obj, name, errp); 1229a3590dacSDaniel P. Berrange EnumProperty *enumprop; 1230a3590dacSDaniel P. Berrange 1231a3590dacSDaniel P. Berrange if (prop == NULL) { 1232a3590dacSDaniel P. Berrange return 0; 1233a3590dacSDaniel P. Berrange } 1234a3590dacSDaniel P. Berrange 1235a3590dacSDaniel P. Berrange if (!g_str_equal(prop->type, typename)) { 1236a3590dacSDaniel P. Berrange error_setg(errp, "Property %s on %s is not '%s' enum type", 1237a3590dacSDaniel P. Berrange name, object_class_get_name( 1238a3590dacSDaniel P. Berrange object_get_class(obj)), typename); 1239a3590dacSDaniel P. Berrange return 0; 1240a3590dacSDaniel P. Berrange } 1241a3590dacSDaniel P. Berrange 1242a3590dacSDaniel P. Berrange enumprop = prop->opaque; 12431f21772dSHu Tao 12443b098d56SEric Blake v = string_output_visitor_new(false, &str); 1245e7ca5656SEric Blake object_property_get(obj, v, name, &err); 12464715d42eSMarkus Armbruster if (err) { 12474715d42eSMarkus Armbruster error_propagate(errp, err); 1248e7ca5656SEric Blake visit_free(v); 12494715d42eSMarkus Armbruster return 0; 12504715d42eSMarkus Armbruster } 12513b098d56SEric Blake visit_complete(v, &str); 1252e7ca5656SEric Blake visit_free(v); 12537a0525c7SEric Blake v = string_input_visitor_new(str); 12547a0525c7SEric Blake visit_type_enum(v, name, &ret, enumprop->strings, errp); 1255976620acSChen Fan 1256976620acSChen Fan g_free(str); 12577a0525c7SEric Blake visit_free(v); 12581f21772dSHu Tao 12591f21772dSHu Tao return ret; 12601f21772dSHu Tao } 12611f21772dSHu Tao 12621f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name, 12631f21772dSHu Tao uint16List **list, Error **errp) 12641f21772dSHu Tao { 12654715d42eSMarkus Armbruster Error *err = NULL; 12667a0525c7SEric Blake Visitor *v; 1267976620acSChen Fan char *str; 12681f21772dSHu Tao 12693b098d56SEric Blake v = string_output_visitor_new(false, &str); 12703b098d56SEric Blake object_property_get(obj, v, name, &err); 12714715d42eSMarkus Armbruster if (err) { 12724715d42eSMarkus Armbruster error_propagate(errp, err); 12734715d42eSMarkus Armbruster goto out; 12744715d42eSMarkus Armbruster } 12753b098d56SEric Blake visit_complete(v, &str); 12763b098d56SEric Blake visit_free(v); 12777a0525c7SEric Blake v = string_input_visitor_new(str); 12787a0525c7SEric Blake visit_type_uint16List(v, NULL, list, errp); 1279976620acSChen Fan 1280976620acSChen Fan g_free(str); 12814715d42eSMarkus Armbruster out: 12823b098d56SEric Blake visit_free(v); 12831f21772dSHu Tao } 12841f21772dSHu Tao 1285b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 1286b2cd7deeSPaolo Bonzini const char *name, Error **errp) 1287b2cd7deeSPaolo Bonzini { 12887a0525c7SEric Blake Visitor *v = string_input_visitor_new(string); 12897a0525c7SEric Blake object_property_set(obj, v, name, errp); 12907a0525c7SEric Blake visit_free(v); 1291b2cd7deeSPaolo Bonzini } 1292b2cd7deeSPaolo Bonzini 12930b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human, 1294b2cd7deeSPaolo Bonzini Error **errp) 1295b2cd7deeSPaolo Bonzini { 12963b098d56SEric Blake Visitor *v; 12973a53009fSGonglei char *string = NULL; 12983a53009fSGonglei Error *local_err = NULL; 1299b2cd7deeSPaolo Bonzini 13003b098d56SEric Blake v = string_output_visitor_new(human, &string); 13013b098d56SEric Blake object_property_get(obj, v, name, &local_err); 13023a53009fSGonglei if (local_err) { 13033a53009fSGonglei error_propagate(errp, local_err); 13043a53009fSGonglei goto out; 13053a53009fSGonglei } 13063a53009fSGonglei 13073b098d56SEric Blake visit_complete(v, &string); 13083a53009fSGonglei 13093a53009fSGonglei out: 13103b098d56SEric Blake visit_free(v); 1311b2cd7deeSPaolo Bonzini return string; 1312b2cd7deeSPaolo Bonzini } 1313b2cd7deeSPaolo Bonzini 131457c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 131557c9fafeSAnthony Liguori { 131689bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 131757c9fafeSAnthony Liguori if (prop == NULL) { 131857c9fafeSAnthony Liguori return NULL; 131957c9fafeSAnthony Liguori } 132057c9fafeSAnthony Liguori 132157c9fafeSAnthony Liguori return prop->type; 132257c9fafeSAnthony Liguori } 132357c9fafeSAnthony Liguori 132457c9fafeSAnthony Liguori Object *object_get_root(void) 132557c9fafeSAnthony Liguori { 13268b45d447SAnthony Liguori static Object *root; 132757c9fafeSAnthony Liguori 13288b45d447SAnthony Liguori if (!root) { 13298b45d447SAnthony Liguori root = object_new("container"); 133057c9fafeSAnthony Liguori } 133157c9fafeSAnthony Liguori 13328b45d447SAnthony Liguori return root; 133357c9fafeSAnthony Liguori } 133457c9fafeSAnthony Liguori 1335bc2256c4SDaniel P. Berrange Object *object_get_objects_root(void) 1336bc2256c4SDaniel P. Berrange { 1337bc2256c4SDaniel P. Berrange return container_get(object_get_root(), "/objects"); 1338bc2256c4SDaniel P. Berrange } 1339bc2256c4SDaniel P. Berrange 1340d7bce999SEric Blake static void object_get_child_property(Object *obj, Visitor *v, 1341d7bce999SEric Blake const char *name, void *opaque, 1342d7bce999SEric Blake Error **errp) 134357c9fafeSAnthony Liguori { 134457c9fafeSAnthony Liguori Object *child = opaque; 134557c9fafeSAnthony Liguori gchar *path; 134657c9fafeSAnthony Liguori 134757c9fafeSAnthony Liguori path = object_get_canonical_path(child); 134851e72bc1SEric Blake visit_type_str(v, name, &path, errp); 134957c9fafeSAnthony Liguori g_free(path); 135057c9fafeSAnthony Liguori } 135157c9fafeSAnthony Liguori 135264607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) 135364607d08SPaolo Bonzini { 135464607d08SPaolo Bonzini return opaque; 135564607d08SPaolo Bonzini } 135664607d08SPaolo Bonzini 1357db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 1358db85b575SAnthony Liguori void *opaque) 1359db85b575SAnthony Liguori { 1360db85b575SAnthony Liguori Object *child = opaque; 1361db85b575SAnthony Liguori 1362bffc687dSPaolo Bonzini if (child->class->unparent) { 1363bffc687dSPaolo Bonzini (child->class->unparent)(child); 1364bffc687dSPaolo Bonzini } 1365bffc687dSPaolo Bonzini child->parent = NULL; 1366db85b575SAnthony Liguori object_unref(child); 1367db85b575SAnthony Liguori } 1368db85b575SAnthony Liguori 136957c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 137057c9fafeSAnthony Liguori Object *child, Error **errp) 137157c9fafeSAnthony Liguori { 1372b0ed5e9fSPaolo Bonzini Error *local_err = NULL; 137357c9fafeSAnthony Liguori gchar *type; 137464607d08SPaolo Bonzini ObjectProperty *op; 137557c9fafeSAnthony Liguori 13768faa2f85SPeter Crosthwaite if (child->parent != NULL) { 13778faa2f85SPeter Crosthwaite error_setg(errp, "child object is already parented"); 13788faa2f85SPeter Crosthwaite return; 13798faa2f85SPeter Crosthwaite } 13808faa2f85SPeter Crosthwaite 138157c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 138257c9fafeSAnthony Liguori 138364607d08SPaolo Bonzini op = object_property_add(obj, name, type, object_get_child_property, NULL, 1384b0ed5e9fSPaolo Bonzini object_finalize_child_property, child, &local_err); 1385b0ed5e9fSPaolo Bonzini if (local_err) { 1386b0ed5e9fSPaolo Bonzini error_propagate(errp, local_err); 1387b0ed5e9fSPaolo Bonzini goto out; 1388b0ed5e9fSPaolo Bonzini } 138964607d08SPaolo Bonzini 139064607d08SPaolo Bonzini op->resolve = object_resolve_child_property; 139157c9fafeSAnthony Liguori object_ref(child); 139257c9fafeSAnthony Liguori child->parent = obj; 139357c9fafeSAnthony Liguori 1394b0ed5e9fSPaolo Bonzini out: 139557c9fafeSAnthony Liguori g_free(type); 139657c9fafeSAnthony Liguori } 139757c9fafeSAnthony Liguori 139839f72ef9SStefan Hajnoczi void object_property_allow_set_link(Object *obj, const char *name, 139939f72ef9SStefan Hajnoczi Object *val, Error **errp) 140039f72ef9SStefan Hajnoczi { 140139f72ef9SStefan Hajnoczi /* Allow the link to be set, always */ 140239f72ef9SStefan Hajnoczi } 140339f72ef9SStefan Hajnoczi 14049561fda8SStefan Hajnoczi typedef struct { 14059561fda8SStefan Hajnoczi Object **child; 140639f72ef9SStefan Hajnoczi void (*check)(Object *, const char *, Object *, Error **); 14079561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags; 14089561fda8SStefan Hajnoczi } LinkProperty; 14099561fda8SStefan Hajnoczi 1410d7bce999SEric Blake static void object_get_link_property(Object *obj, Visitor *v, 1411d7bce999SEric Blake const char *name, void *opaque, 1412d7bce999SEric Blake Error **errp) 141357c9fafeSAnthony Liguori { 14149561fda8SStefan Hajnoczi LinkProperty *lprop = opaque; 14159561fda8SStefan Hajnoczi Object **child = lprop->child; 141657c9fafeSAnthony Liguori gchar *path; 141757c9fafeSAnthony Liguori 141857c9fafeSAnthony Liguori if (*child) { 141957c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 142051e72bc1SEric Blake visit_type_str(v, name, &path, errp); 142157c9fafeSAnthony Liguori g_free(path); 142257c9fafeSAnthony Liguori } else { 142357c9fafeSAnthony Liguori path = (gchar *)""; 142451e72bc1SEric Blake visit_type_str(v, name, &path, errp); 142557c9fafeSAnthony Liguori } 142657c9fafeSAnthony Liguori } 142757c9fafeSAnthony Liguori 1428f5ec6704SStefan Hajnoczi /* 1429f5ec6704SStefan Hajnoczi * object_resolve_link: 1430f5ec6704SStefan Hajnoczi * 1431f5ec6704SStefan Hajnoczi * Lookup an object and ensure its type matches the link property type. This 1432f5ec6704SStefan Hajnoczi * is similar to object_resolve_path() except type verification against the 1433f5ec6704SStefan Hajnoczi * link property is performed. 1434f5ec6704SStefan Hajnoczi * 1435f5ec6704SStefan Hajnoczi * Returns: The matched object or NULL on path lookup failures. 1436f5ec6704SStefan Hajnoczi */ 1437f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name, 1438f5ec6704SStefan Hajnoczi const char *path, Error **errp) 1439f5ec6704SStefan Hajnoczi { 1440f5ec6704SStefan Hajnoczi const char *type; 1441f5ec6704SStefan Hajnoczi gchar *target_type; 1442f5ec6704SStefan Hajnoczi bool ambiguous = false; 1443f5ec6704SStefan Hajnoczi Object *target; 1444f5ec6704SStefan Hajnoczi 1445f5ec6704SStefan Hajnoczi /* Go from link<FOO> to FOO. */ 1446f5ec6704SStefan Hajnoczi type = object_property_get_type(obj, name, NULL); 1447f5ec6704SStefan Hajnoczi target_type = g_strndup(&type[5], strlen(type) - 6); 1448f5ec6704SStefan Hajnoczi target = object_resolve_path_type(path, target_type, &ambiguous); 1449f5ec6704SStefan Hajnoczi 1450f5ec6704SStefan Hajnoczi if (ambiguous) { 1451455b0fdeSEric Blake error_setg(errp, "Path '%s' does not uniquely identify an object", 1452455b0fdeSEric Blake path); 1453f5ec6704SStefan Hajnoczi } else if (!target) { 1454f5ec6704SStefan Hajnoczi target = object_resolve_path(path, &ambiguous); 1455f5ec6704SStefan Hajnoczi if (target || ambiguous) { 1456c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 1457f5ec6704SStefan Hajnoczi } else { 145875158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 145975158ebbSMarkus Armbruster "Device '%s' not found", path); 1460f5ec6704SStefan Hajnoczi } 1461f5ec6704SStefan Hajnoczi target = NULL; 1462f5ec6704SStefan Hajnoczi } 1463f5ec6704SStefan Hajnoczi g_free(target_type); 1464f5ec6704SStefan Hajnoczi 1465f5ec6704SStefan Hajnoczi return target; 1466f5ec6704SStefan Hajnoczi } 1467f5ec6704SStefan Hajnoczi 1468d7bce999SEric Blake static void object_set_link_property(Object *obj, Visitor *v, 1469d7bce999SEric Blake const char *name, void *opaque, 1470d7bce999SEric Blake Error **errp) 147157c9fafeSAnthony Liguori { 1472c6aed983SStefan Hajnoczi Error *local_err = NULL; 14739561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 14749561fda8SStefan Hajnoczi Object **child = prop->child; 1475c6aed983SStefan Hajnoczi Object *old_target = *child; 1476c6aed983SStefan Hajnoczi Object *new_target = NULL; 1477c6aed983SStefan Hajnoczi char *path = NULL; 147857c9fafeSAnthony Liguori 147951e72bc1SEric Blake visit_type_str(v, name, &path, &local_err); 148057c9fafeSAnthony Liguori 1481c6aed983SStefan Hajnoczi if (!local_err && strcmp(path, "") != 0) { 1482c6aed983SStefan Hajnoczi new_target = object_resolve_link(obj, name, path, &local_err); 148311e35bfdSPaolo Bonzini } 148457c9fafeSAnthony Liguori 148557c9fafeSAnthony Liguori g_free(path); 1486c6aed983SStefan Hajnoczi if (local_err) { 1487c6aed983SStefan Hajnoczi error_propagate(errp, local_err); 1488c6aed983SStefan Hajnoczi return; 1489c6aed983SStefan Hajnoczi } 1490f0cdc966SAlexander Barabash 149139f72ef9SStefan Hajnoczi prop->check(obj, name, new_target, &local_err); 149239f72ef9SStefan Hajnoczi if (local_err) { 149339f72ef9SStefan Hajnoczi error_propagate(errp, local_err); 149439f72ef9SStefan Hajnoczi return; 149539f72ef9SStefan Hajnoczi } 149639f72ef9SStefan Hajnoczi 1497c6aed983SStefan Hajnoczi object_ref(new_target); 1498c6aed983SStefan Hajnoczi *child = new_target; 1499f0cdc966SAlexander Barabash object_unref(old_target); 1500f0cdc966SAlexander Barabash } 150157c9fafeSAnthony Liguori 150264607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) 150364607d08SPaolo Bonzini { 150464607d08SPaolo Bonzini LinkProperty *lprop = opaque; 150564607d08SPaolo Bonzini 150664607d08SPaolo Bonzini return *lprop->child; 150764607d08SPaolo Bonzini } 150864607d08SPaolo Bonzini 15099561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name, 15109561fda8SStefan Hajnoczi void *opaque) 15119561fda8SStefan Hajnoczi { 15129561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 15139561fda8SStefan Hajnoczi 15149561fda8SStefan Hajnoczi if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { 15159561fda8SStefan Hajnoczi object_unref(*prop->child); 15169561fda8SStefan Hajnoczi } 15179561fda8SStefan Hajnoczi g_free(prop); 15189561fda8SStefan Hajnoczi } 15199561fda8SStefan Hajnoczi 152057c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 152157c9fafeSAnthony Liguori const char *type, Object **child, 152239f72ef9SStefan Hajnoczi void (*check)(Object *, const char *, 152339f72ef9SStefan Hajnoczi Object *, Error **), 15249561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags, 152557c9fafeSAnthony Liguori Error **errp) 152657c9fafeSAnthony Liguori { 15279561fda8SStefan Hajnoczi Error *local_err = NULL; 15289561fda8SStefan Hajnoczi LinkProperty *prop = g_malloc(sizeof(*prop)); 152957c9fafeSAnthony Liguori gchar *full_type; 153064607d08SPaolo Bonzini ObjectProperty *op; 153157c9fafeSAnthony Liguori 15329561fda8SStefan Hajnoczi prop->child = child; 153339f72ef9SStefan Hajnoczi prop->check = check; 15349561fda8SStefan Hajnoczi prop->flags = flags; 15359561fda8SStefan Hajnoczi 153657c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 153757c9fafeSAnthony Liguori 153864607d08SPaolo Bonzini op = object_property_add(obj, name, full_type, 153957c9fafeSAnthony Liguori object_get_link_property, 154039f72ef9SStefan Hajnoczi check ? object_set_link_property : NULL, 15419561fda8SStefan Hajnoczi object_release_link_property, 15429561fda8SStefan Hajnoczi prop, 15439561fda8SStefan Hajnoczi &local_err); 15449561fda8SStefan Hajnoczi if (local_err) { 15459561fda8SStefan Hajnoczi error_propagate(errp, local_err); 15469561fda8SStefan Hajnoczi g_free(prop); 154764607d08SPaolo Bonzini goto out; 15489561fda8SStefan Hajnoczi } 154957c9fafeSAnthony Liguori 155064607d08SPaolo Bonzini op->resolve = object_resolve_link_property; 155164607d08SPaolo Bonzini 155264607d08SPaolo Bonzini out: 155357c9fafeSAnthony Liguori g_free(full_type); 155457c9fafeSAnthony Liguori } 155557c9fafeSAnthony Liguori 1556fb9e7e33SPaolo Bonzini void object_property_add_const_link(Object *obj, const char *name, 1557fb9e7e33SPaolo Bonzini Object *target, Error **errp) 1558fb9e7e33SPaolo Bonzini { 1559fb9e7e33SPaolo Bonzini char *link_type; 1560fb9e7e33SPaolo Bonzini ObjectProperty *op; 1561fb9e7e33SPaolo Bonzini 1562fb9e7e33SPaolo Bonzini link_type = g_strdup_printf("link<%s>", object_get_typename(target)); 1563fb9e7e33SPaolo Bonzini op = object_property_add(obj, name, link_type, 1564fb9e7e33SPaolo Bonzini object_get_child_property, NULL, 1565fb9e7e33SPaolo Bonzini NULL, target, errp); 1566fb9e7e33SPaolo Bonzini if (op != NULL) { 1567fb9e7e33SPaolo Bonzini op->resolve = object_resolve_child_property; 1568fb9e7e33SPaolo Bonzini } 1569fb9e7e33SPaolo Bonzini g_free(link_type); 1570fb9e7e33SPaolo Bonzini } 1571fb9e7e33SPaolo Bonzini 157211f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj) 157357c9fafeSAnthony Liguori { 157457c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 1575b604a854SPavel Fedin GHashTableIter iter; 157657c9fafeSAnthony Liguori 157711f590b1SStefan Hajnoczi g_assert(obj); 157857c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 157957c9fafeSAnthony Liguori 1580b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->parent->properties); 1581b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 15825d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 158357c9fafeSAnthony Liguori continue; 158457c9fafeSAnthony Liguori } 158557c9fafeSAnthony Liguori 158657c9fafeSAnthony Liguori if (prop->opaque == obj) { 158711f590b1SStefan Hajnoczi return g_strdup(prop->name); 158857c9fafeSAnthony Liguori } 158957c9fafeSAnthony Liguori } 159057c9fafeSAnthony Liguori 159111f590b1SStefan Hajnoczi /* obj had a parent but was not a child, should never happen */ 159211f590b1SStefan Hajnoczi g_assert_not_reached(); 159311f590b1SStefan Hajnoczi return NULL; 159411f590b1SStefan Hajnoczi } 159511f590b1SStefan Hajnoczi 159611f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj) 159711f590b1SStefan Hajnoczi { 159811f590b1SStefan Hajnoczi Object *root = object_get_root(); 159911f590b1SStefan Hajnoczi char *newpath, *path = NULL; 160011f590b1SStefan Hajnoczi 160111f590b1SStefan Hajnoczi while (obj != root) { 160211f590b1SStefan Hajnoczi char *component = object_get_canonical_path_component(obj); 160311f590b1SStefan Hajnoczi 160411f590b1SStefan Hajnoczi if (path) { 160511f590b1SStefan Hajnoczi newpath = g_strdup_printf("%s/%s", component, path); 160611f590b1SStefan Hajnoczi g_free(component); 160711f590b1SStefan Hajnoczi g_free(path); 160811f590b1SStefan Hajnoczi path = newpath; 160911f590b1SStefan Hajnoczi } else { 161011f590b1SStefan Hajnoczi path = component; 161111f590b1SStefan Hajnoczi } 161257c9fafeSAnthony Liguori 161357c9fafeSAnthony Liguori obj = obj->parent; 161457c9fafeSAnthony Liguori } 161557c9fafeSAnthony Liguori 161611f590b1SStefan Hajnoczi newpath = g_strdup_printf("/%s", path ? path : ""); 161757c9fafeSAnthony Liguori g_free(path); 161857c9fafeSAnthony Liguori 161957c9fafeSAnthony Liguori return newpath; 162057c9fafeSAnthony Liguori } 162157c9fafeSAnthony Liguori 16223e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part) 1623a612b2a6SPaolo Bonzini { 162489bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part, NULL); 1625a612b2a6SPaolo Bonzini if (prop == NULL) { 1626a612b2a6SPaolo Bonzini return NULL; 1627a612b2a6SPaolo Bonzini } 1628a612b2a6SPaolo Bonzini 162964607d08SPaolo Bonzini if (prop->resolve) { 163064607d08SPaolo Bonzini return prop->resolve(parent, prop->opaque, part); 1631a612b2a6SPaolo Bonzini } else { 1632a612b2a6SPaolo Bonzini return NULL; 1633a612b2a6SPaolo Bonzini } 1634a612b2a6SPaolo Bonzini } 1635a612b2a6SPaolo Bonzini 163657c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 163757c9fafeSAnthony Liguori gchar **parts, 163802fe2db6SPaolo Bonzini const char *typename, 163957c9fafeSAnthony Liguori int index) 164057c9fafeSAnthony Liguori { 164157c9fafeSAnthony Liguori Object *child; 164257c9fafeSAnthony Liguori 164357c9fafeSAnthony Liguori if (parts[index] == NULL) { 164402fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 164557c9fafeSAnthony Liguori } 164657c9fafeSAnthony Liguori 164757c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 164802fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 164957c9fafeSAnthony Liguori } 165057c9fafeSAnthony Liguori 1651a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 165257c9fafeSAnthony Liguori if (!child) { 165357c9fafeSAnthony Liguori return NULL; 165457c9fafeSAnthony Liguori } 165557c9fafeSAnthony Liguori 165602fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 165757c9fafeSAnthony Liguori } 165857c9fafeSAnthony Liguori 165957c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 166057c9fafeSAnthony Liguori gchar **parts, 166102fe2db6SPaolo Bonzini const char *typename, 166257c9fafeSAnthony Liguori bool *ambiguous) 166357c9fafeSAnthony Liguori { 166457c9fafeSAnthony Liguori Object *obj; 1665b604a854SPavel Fedin GHashTableIter iter; 166657c9fafeSAnthony Liguori ObjectProperty *prop; 166757c9fafeSAnthony Liguori 166802fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 166957c9fafeSAnthony Liguori 1670b604a854SPavel Fedin g_hash_table_iter_init(&iter, parent->properties); 1671b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 167257c9fafeSAnthony Liguori Object *found; 167357c9fafeSAnthony Liguori 16745d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 167557c9fafeSAnthony Liguori continue; 167657c9fafeSAnthony Liguori } 167757c9fafeSAnthony Liguori 167802fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 167902fe2db6SPaolo Bonzini typename, ambiguous); 168057c9fafeSAnthony Liguori if (found) { 168157c9fafeSAnthony Liguori if (obj) { 168257c9fafeSAnthony Liguori if (ambiguous) { 168357c9fafeSAnthony Liguori *ambiguous = true; 168457c9fafeSAnthony Liguori } 168557c9fafeSAnthony Liguori return NULL; 168657c9fafeSAnthony Liguori } 168757c9fafeSAnthony Liguori obj = found; 168857c9fafeSAnthony Liguori } 168957c9fafeSAnthony Liguori 169057c9fafeSAnthony Liguori if (ambiguous && *ambiguous) { 169157c9fafeSAnthony Liguori return NULL; 169257c9fafeSAnthony Liguori } 169357c9fafeSAnthony Liguori } 169457c9fafeSAnthony Liguori 169557c9fafeSAnthony Liguori return obj; 169657c9fafeSAnthony Liguori } 169757c9fafeSAnthony Liguori 169802fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 169902fe2db6SPaolo Bonzini bool *ambiguous) 170057c9fafeSAnthony Liguori { 170157c9fafeSAnthony Liguori Object *obj; 170257c9fafeSAnthony Liguori gchar **parts; 170357c9fafeSAnthony Liguori 170457c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 17052e1103f6SPaolo Bonzini assert(parts); 170657c9fafeSAnthony Liguori 17072e1103f6SPaolo Bonzini if (parts[0] == NULL || strcmp(parts[0], "") != 0) { 170857c9fafeSAnthony Liguori if (ambiguous) { 170957c9fafeSAnthony Liguori *ambiguous = false; 171057c9fafeSAnthony Liguori } 171102fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 171202fe2db6SPaolo Bonzini typename, ambiguous); 171357c9fafeSAnthony Liguori } else { 171402fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 171557c9fafeSAnthony Liguori } 171657c9fafeSAnthony Liguori 171757c9fafeSAnthony Liguori g_strfreev(parts); 171857c9fafeSAnthony Liguori 171957c9fafeSAnthony Liguori return obj; 172057c9fafeSAnthony Liguori } 172157c9fafeSAnthony Liguori 172202fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 172302fe2db6SPaolo Bonzini { 172402fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 172502fe2db6SPaolo Bonzini } 172602fe2db6SPaolo Bonzini 172757c9fafeSAnthony Liguori typedef struct StringProperty 172857c9fafeSAnthony Liguori { 172957c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 173057c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 173157c9fafeSAnthony Liguori } StringProperty; 173257c9fafeSAnthony Liguori 1733d7bce999SEric Blake static void property_get_str(Object *obj, Visitor *v, const char *name, 1734d7bce999SEric Blake void *opaque, Error **errp) 173557c9fafeSAnthony Liguori { 173657c9fafeSAnthony Liguori StringProperty *prop = opaque; 173757c9fafeSAnthony Liguori char *value; 1738e1c8237dSMarkus Armbruster Error *err = NULL; 173957c9fafeSAnthony Liguori 1740e1c8237dSMarkus Armbruster value = prop->get(obj, &err); 1741e1c8237dSMarkus Armbruster if (err) { 1742e1c8237dSMarkus Armbruster error_propagate(errp, err); 1743e1c8237dSMarkus Armbruster return; 1744e1c8237dSMarkus Armbruster } 1745e1c8237dSMarkus Armbruster 174651e72bc1SEric Blake visit_type_str(v, name, &value, errp); 174757c9fafeSAnthony Liguori g_free(value); 174857c9fafeSAnthony Liguori } 174957c9fafeSAnthony Liguori 1750d7bce999SEric Blake static void property_set_str(Object *obj, Visitor *v, const char *name, 1751d7bce999SEric Blake void *opaque, Error **errp) 175257c9fafeSAnthony Liguori { 175357c9fafeSAnthony Liguori StringProperty *prop = opaque; 175457c9fafeSAnthony Liguori char *value; 175557c9fafeSAnthony Liguori Error *local_err = NULL; 175657c9fafeSAnthony Liguori 175751e72bc1SEric Blake visit_type_str(v, name, &value, &local_err); 175857c9fafeSAnthony Liguori if (local_err) { 175957c9fafeSAnthony Liguori error_propagate(errp, local_err); 176057c9fafeSAnthony Liguori return; 176157c9fafeSAnthony Liguori } 176257c9fafeSAnthony Liguori 176357c9fafeSAnthony Liguori prop->set(obj, value, errp); 176457c9fafeSAnthony Liguori g_free(value); 176557c9fafeSAnthony Liguori } 176657c9fafeSAnthony Liguori 17677b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 176857c9fafeSAnthony Liguori void *opaque) 176957c9fafeSAnthony Liguori { 177057c9fafeSAnthony Liguori StringProperty *prop = opaque; 177157c9fafeSAnthony Liguori g_free(prop); 177257c9fafeSAnthony Liguori } 177357c9fafeSAnthony Liguori 177457c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 177557c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 177657c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 177757c9fafeSAnthony Liguori Error **errp) 177857c9fafeSAnthony Liguori { 1779a01aedc8SStefan Hajnoczi Error *local_err = NULL; 178057c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 178157c9fafeSAnthony Liguori 178257c9fafeSAnthony Liguori prop->get = get; 178357c9fafeSAnthony Liguori prop->set = set; 178457c9fafeSAnthony Liguori 178557c9fafeSAnthony Liguori object_property_add(obj, name, "string", 17867b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 17877b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 17887b7b7d18SPaolo Bonzini property_release_str, 1789a01aedc8SStefan Hajnoczi prop, &local_err); 1790a01aedc8SStefan Hajnoczi if (local_err) { 1791a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1792a01aedc8SStefan Hajnoczi g_free(prop); 1793a01aedc8SStefan Hajnoczi } 179457c9fafeSAnthony Liguori } 1795745549c8SPaolo Bonzini 179616bf7f52SDaniel P. Berrange void object_class_property_add_str(ObjectClass *klass, const char *name, 179716bf7f52SDaniel P. Berrange char *(*get)(Object *, Error **), 179816bf7f52SDaniel P. Berrange void (*set)(Object *, const char *, 179916bf7f52SDaniel P. Berrange Error **), 180016bf7f52SDaniel P. Berrange Error **errp) 180116bf7f52SDaniel P. Berrange { 180216bf7f52SDaniel P. Berrange Error *local_err = NULL; 180316bf7f52SDaniel P. Berrange StringProperty *prop = g_malloc0(sizeof(*prop)); 180416bf7f52SDaniel P. Berrange 180516bf7f52SDaniel P. Berrange prop->get = get; 180616bf7f52SDaniel P. Berrange prop->set = set; 180716bf7f52SDaniel P. Berrange 180816bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "string", 180916bf7f52SDaniel P. Berrange get ? property_get_str : NULL, 181016bf7f52SDaniel P. Berrange set ? property_set_str : NULL, 181116bf7f52SDaniel P. Berrange property_release_str, 181216bf7f52SDaniel P. Berrange prop, &local_err); 181316bf7f52SDaniel P. Berrange if (local_err) { 181416bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 181516bf7f52SDaniel P. Berrange g_free(prop); 181616bf7f52SDaniel P. Berrange } 181716bf7f52SDaniel P. Berrange } 181816bf7f52SDaniel P. Berrange 18190e558843SAnthony Liguori typedef struct BoolProperty 18200e558843SAnthony Liguori { 18210e558843SAnthony Liguori bool (*get)(Object *, Error **); 18220e558843SAnthony Liguori void (*set)(Object *, bool, Error **); 18230e558843SAnthony Liguori } BoolProperty; 18240e558843SAnthony Liguori 1825d7bce999SEric Blake static void property_get_bool(Object *obj, Visitor *v, const char *name, 1826d7bce999SEric Blake void *opaque, Error **errp) 18270e558843SAnthony Liguori { 18280e558843SAnthony Liguori BoolProperty *prop = opaque; 18290e558843SAnthony Liguori bool value; 18304715d42eSMarkus Armbruster Error *err = NULL; 18310e558843SAnthony Liguori 18324715d42eSMarkus Armbruster value = prop->get(obj, &err); 18334715d42eSMarkus Armbruster if (err) { 18344715d42eSMarkus Armbruster error_propagate(errp, err); 18354715d42eSMarkus Armbruster return; 18364715d42eSMarkus Armbruster } 18374715d42eSMarkus Armbruster 183851e72bc1SEric Blake visit_type_bool(v, name, &value, errp); 18390e558843SAnthony Liguori } 18400e558843SAnthony Liguori 1841d7bce999SEric Blake static void property_set_bool(Object *obj, Visitor *v, const char *name, 1842d7bce999SEric Blake void *opaque, Error **errp) 18430e558843SAnthony Liguori { 18440e558843SAnthony Liguori BoolProperty *prop = opaque; 18450e558843SAnthony Liguori bool value; 18460e558843SAnthony Liguori Error *local_err = NULL; 18470e558843SAnthony Liguori 184851e72bc1SEric Blake visit_type_bool(v, name, &value, &local_err); 18490e558843SAnthony Liguori if (local_err) { 18500e558843SAnthony Liguori error_propagate(errp, local_err); 18510e558843SAnthony Liguori return; 18520e558843SAnthony Liguori } 18530e558843SAnthony Liguori 18540e558843SAnthony Liguori prop->set(obj, value, errp); 18550e558843SAnthony Liguori } 18560e558843SAnthony Liguori 18570e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name, 18580e558843SAnthony Liguori void *opaque) 18590e558843SAnthony Liguori { 18600e558843SAnthony Liguori BoolProperty *prop = opaque; 18610e558843SAnthony Liguori g_free(prop); 18620e558843SAnthony Liguori } 18630e558843SAnthony Liguori 18640e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name, 18650e558843SAnthony Liguori bool (*get)(Object *, Error **), 18660e558843SAnthony Liguori void (*set)(Object *, bool, Error **), 18670e558843SAnthony Liguori Error **errp) 18680e558843SAnthony Liguori { 1869a01aedc8SStefan Hajnoczi Error *local_err = NULL; 18700e558843SAnthony Liguori BoolProperty *prop = g_malloc0(sizeof(*prop)); 18710e558843SAnthony Liguori 18720e558843SAnthony Liguori prop->get = get; 18730e558843SAnthony Liguori prop->set = set; 18740e558843SAnthony Liguori 18750e558843SAnthony Liguori object_property_add(obj, name, "bool", 18760e558843SAnthony Liguori get ? property_get_bool : NULL, 18770e558843SAnthony Liguori set ? property_set_bool : NULL, 18780e558843SAnthony Liguori property_release_bool, 1879a01aedc8SStefan Hajnoczi prop, &local_err); 1880a01aedc8SStefan Hajnoczi if (local_err) { 1881a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1882a01aedc8SStefan Hajnoczi g_free(prop); 1883a01aedc8SStefan Hajnoczi } 18840e558843SAnthony Liguori } 18850e558843SAnthony Liguori 188616bf7f52SDaniel P. Berrange void object_class_property_add_bool(ObjectClass *klass, const char *name, 188716bf7f52SDaniel P. Berrange bool (*get)(Object *, Error **), 188816bf7f52SDaniel P. Berrange void (*set)(Object *, bool, Error **), 188916bf7f52SDaniel P. Berrange Error **errp) 189016bf7f52SDaniel P. Berrange { 189116bf7f52SDaniel P. Berrange Error *local_err = NULL; 189216bf7f52SDaniel P. Berrange BoolProperty *prop = g_malloc0(sizeof(*prop)); 189316bf7f52SDaniel P. Berrange 189416bf7f52SDaniel P. Berrange prop->get = get; 189516bf7f52SDaniel P. Berrange prop->set = set; 189616bf7f52SDaniel P. Berrange 189716bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "bool", 189816bf7f52SDaniel P. Berrange get ? property_get_bool : NULL, 189916bf7f52SDaniel P. Berrange set ? property_set_bool : NULL, 190016bf7f52SDaniel P. Berrange property_release_bool, 190116bf7f52SDaniel P. Berrange prop, &local_err); 190216bf7f52SDaniel P. Berrange if (local_err) { 190316bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 190416bf7f52SDaniel P. Berrange g_free(prop); 190516bf7f52SDaniel P. Berrange } 190616bf7f52SDaniel P. Berrange } 190716bf7f52SDaniel P. Berrange 1908d7bce999SEric Blake static void property_get_enum(Object *obj, Visitor *v, const char *name, 1909d7bce999SEric Blake void *opaque, Error **errp) 1910a8e3fbedSDaniel P. Berrange { 1911a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1912a8e3fbedSDaniel P. Berrange int value; 19134715d42eSMarkus Armbruster Error *err = NULL; 1914a8e3fbedSDaniel P. Berrange 19154715d42eSMarkus Armbruster value = prop->get(obj, &err); 19164715d42eSMarkus Armbruster if (err) { 19174715d42eSMarkus Armbruster error_propagate(errp, err); 19184715d42eSMarkus Armbruster return; 19194715d42eSMarkus Armbruster } 19204715d42eSMarkus Armbruster 1921337283dfSEric Blake visit_type_enum(v, name, &value, prop->strings, errp); 1922a8e3fbedSDaniel P. Berrange } 1923a8e3fbedSDaniel P. Berrange 1924d7bce999SEric Blake static void property_set_enum(Object *obj, Visitor *v, const char *name, 1925d7bce999SEric Blake void *opaque, Error **errp) 1926a8e3fbedSDaniel P. Berrange { 1927a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1928a8e3fbedSDaniel P. Berrange int value; 19294715d42eSMarkus Armbruster Error *err = NULL; 1930a8e3fbedSDaniel P. Berrange 1931337283dfSEric Blake visit_type_enum(v, name, &value, prop->strings, &err); 19324715d42eSMarkus Armbruster if (err) { 19334715d42eSMarkus Armbruster error_propagate(errp, err); 19344715d42eSMarkus Armbruster return; 19354715d42eSMarkus Armbruster } 1936a8e3fbedSDaniel P. Berrange prop->set(obj, value, errp); 1937a8e3fbedSDaniel P. Berrange } 1938a8e3fbedSDaniel P. Berrange 1939a8e3fbedSDaniel P. Berrange static void property_release_enum(Object *obj, const char *name, 1940a8e3fbedSDaniel P. Berrange void *opaque) 1941a8e3fbedSDaniel P. Berrange { 1942a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1943a8e3fbedSDaniel P. Berrange g_free(prop); 1944a8e3fbedSDaniel P. Berrange } 1945a8e3fbedSDaniel P. Berrange 1946a8e3fbedSDaniel P. Berrange void object_property_add_enum(Object *obj, const char *name, 1947a8e3fbedSDaniel P. Berrange const char *typename, 1948a8e3fbedSDaniel P. Berrange const char * const *strings, 1949a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **), 1950a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **), 1951a8e3fbedSDaniel P. Berrange Error **errp) 1952a8e3fbedSDaniel P. Berrange { 1953a8e3fbedSDaniel P. Berrange Error *local_err = NULL; 1954a8e3fbedSDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 1955a8e3fbedSDaniel P. Berrange 1956a8e3fbedSDaniel P. Berrange prop->strings = strings; 1957a8e3fbedSDaniel P. Berrange prop->get = get; 1958a8e3fbedSDaniel P. Berrange prop->set = set; 1959a8e3fbedSDaniel P. Berrange 1960a8e3fbedSDaniel P. Berrange object_property_add(obj, name, typename, 1961a8e3fbedSDaniel P. Berrange get ? property_get_enum : NULL, 1962a8e3fbedSDaniel P. Berrange set ? property_set_enum : NULL, 1963a8e3fbedSDaniel P. Berrange property_release_enum, 1964a8e3fbedSDaniel P. Berrange prop, &local_err); 1965a8e3fbedSDaniel P. Berrange if (local_err) { 1966a8e3fbedSDaniel P. Berrange error_propagate(errp, local_err); 1967a8e3fbedSDaniel P. Berrange g_free(prop); 1968a8e3fbedSDaniel P. Berrange } 1969a8e3fbedSDaniel P. Berrange } 1970a8e3fbedSDaniel P. Berrange 197116bf7f52SDaniel P. Berrange void object_class_property_add_enum(ObjectClass *klass, const char *name, 197216bf7f52SDaniel P. Berrange const char *typename, 197316bf7f52SDaniel P. Berrange const char * const *strings, 197416bf7f52SDaniel P. Berrange int (*get)(Object *, Error **), 197516bf7f52SDaniel P. Berrange void (*set)(Object *, int, Error **), 197616bf7f52SDaniel P. Berrange Error **errp) 197716bf7f52SDaniel P. Berrange { 197816bf7f52SDaniel P. Berrange Error *local_err = NULL; 197916bf7f52SDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 198016bf7f52SDaniel P. Berrange 198116bf7f52SDaniel P. Berrange prop->strings = strings; 198216bf7f52SDaniel P. Berrange prop->get = get; 198316bf7f52SDaniel P. Berrange prop->set = set; 198416bf7f52SDaniel P. Berrange 198516bf7f52SDaniel P. Berrange object_class_property_add(klass, name, typename, 198616bf7f52SDaniel P. Berrange get ? property_get_enum : NULL, 198716bf7f52SDaniel P. Berrange set ? property_set_enum : NULL, 198816bf7f52SDaniel P. Berrange property_release_enum, 198916bf7f52SDaniel P. Berrange prop, &local_err); 199016bf7f52SDaniel P. Berrange if (local_err) { 199116bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 199216bf7f52SDaniel P. Berrange g_free(prop); 199316bf7f52SDaniel P. Berrange } 199416bf7f52SDaniel P. Berrange } 199516bf7f52SDaniel P. Berrange 19968e099d14SDavid Gibson typedef struct TMProperty { 19978e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **); 19988e099d14SDavid Gibson } TMProperty; 19998e099d14SDavid Gibson 2000d7bce999SEric Blake static void property_get_tm(Object *obj, Visitor *v, const char *name, 2001d7bce999SEric Blake void *opaque, Error **errp) 20028e099d14SDavid Gibson { 20038e099d14SDavid Gibson TMProperty *prop = opaque; 20048e099d14SDavid Gibson Error *err = NULL; 20058e099d14SDavid Gibson struct tm value; 20068e099d14SDavid Gibson 20078e099d14SDavid Gibson prop->get(obj, &value, &err); 20088e099d14SDavid Gibson if (err) { 20098e099d14SDavid Gibson goto out; 20108e099d14SDavid Gibson } 20118e099d14SDavid Gibson 2012337283dfSEric Blake visit_start_struct(v, name, NULL, 0, &err); 20138e099d14SDavid Gibson if (err) { 20148e099d14SDavid Gibson goto out; 20158e099d14SDavid Gibson } 201651e72bc1SEric Blake visit_type_int32(v, "tm_year", &value.tm_year, &err); 20178e099d14SDavid Gibson if (err) { 20188e099d14SDavid Gibson goto out_end; 20198e099d14SDavid Gibson } 202051e72bc1SEric Blake visit_type_int32(v, "tm_mon", &value.tm_mon, &err); 20218e099d14SDavid Gibson if (err) { 20228e099d14SDavid Gibson goto out_end; 20238e099d14SDavid Gibson } 202451e72bc1SEric Blake visit_type_int32(v, "tm_mday", &value.tm_mday, &err); 20258e099d14SDavid Gibson if (err) { 20268e099d14SDavid Gibson goto out_end; 20278e099d14SDavid Gibson } 202851e72bc1SEric Blake visit_type_int32(v, "tm_hour", &value.tm_hour, &err); 20298e099d14SDavid Gibson if (err) { 20308e099d14SDavid Gibson goto out_end; 20318e099d14SDavid Gibson } 203251e72bc1SEric Blake visit_type_int32(v, "tm_min", &value.tm_min, &err); 20338e099d14SDavid Gibson if (err) { 20348e099d14SDavid Gibson goto out_end; 20358e099d14SDavid Gibson } 203651e72bc1SEric Blake visit_type_int32(v, "tm_sec", &value.tm_sec, &err); 20378e099d14SDavid Gibson if (err) { 20388e099d14SDavid Gibson goto out_end; 20398e099d14SDavid Gibson } 204015c2f669SEric Blake visit_check_struct(v, &err); 20418e099d14SDavid Gibson out_end: 20421158bb2aSEric Blake visit_end_struct(v, NULL); 20438e099d14SDavid Gibson out: 20448e099d14SDavid Gibson error_propagate(errp, err); 20458e099d14SDavid Gibson 20468e099d14SDavid Gibson } 20478e099d14SDavid Gibson 20488e099d14SDavid Gibson static void property_release_tm(Object *obj, const char *name, 20498e099d14SDavid Gibson void *opaque) 20508e099d14SDavid Gibson { 20518e099d14SDavid Gibson TMProperty *prop = opaque; 20528e099d14SDavid Gibson g_free(prop); 20538e099d14SDavid Gibson } 20548e099d14SDavid Gibson 20558e099d14SDavid Gibson void object_property_add_tm(Object *obj, const char *name, 20568e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **), 20578e099d14SDavid Gibson Error **errp) 20588e099d14SDavid Gibson { 20598e099d14SDavid Gibson Error *local_err = NULL; 20608e099d14SDavid Gibson TMProperty *prop = g_malloc0(sizeof(*prop)); 20618e099d14SDavid Gibson 20628e099d14SDavid Gibson prop->get = get; 20638e099d14SDavid Gibson 20648e099d14SDavid Gibson object_property_add(obj, name, "struct tm", 20658e099d14SDavid Gibson get ? property_get_tm : NULL, NULL, 20668e099d14SDavid Gibson property_release_tm, 20678e099d14SDavid Gibson prop, &local_err); 20688e099d14SDavid Gibson if (local_err) { 20698e099d14SDavid Gibson error_propagate(errp, local_err); 20708e099d14SDavid Gibson g_free(prop); 20718e099d14SDavid Gibson } 20728e099d14SDavid Gibson } 20738e099d14SDavid Gibson 207416bf7f52SDaniel P. Berrange void object_class_property_add_tm(ObjectClass *klass, const char *name, 207516bf7f52SDaniel P. Berrange void (*get)(Object *, struct tm *, Error **), 207616bf7f52SDaniel P. Berrange Error **errp) 207716bf7f52SDaniel P. Berrange { 207816bf7f52SDaniel P. Berrange Error *local_err = NULL; 207916bf7f52SDaniel P. Berrange TMProperty *prop = g_malloc0(sizeof(*prop)); 208016bf7f52SDaniel P. Berrange 208116bf7f52SDaniel P. Berrange prop->get = get; 208216bf7f52SDaniel P. Berrange 208316bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "struct tm", 208416bf7f52SDaniel P. Berrange get ? property_get_tm : NULL, NULL, 208516bf7f52SDaniel P. Berrange property_release_tm, 208616bf7f52SDaniel P. Berrange prop, &local_err); 208716bf7f52SDaniel P. Berrange if (local_err) { 208816bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 208916bf7f52SDaniel P. Berrange g_free(prop); 209016bf7f52SDaniel P. Berrange } 209116bf7f52SDaniel P. Berrange } 209216bf7f52SDaniel P. Berrange 20932f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp) 20942f262e06SPaolo Bonzini { 20952f262e06SPaolo Bonzini return g_strdup(object_get_typename(obj)); 20962f262e06SPaolo Bonzini } 20972f262e06SPaolo Bonzini 2098d7bce999SEric Blake static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name, 2099d7bce999SEric Blake void *opaque, Error **errp) 2100e732ea63SMichael S. Tsirkin { 2101e732ea63SMichael S. Tsirkin uint8_t value = *(uint8_t *)opaque; 210251e72bc1SEric Blake visit_type_uint8(v, name, &value, errp); 2103e732ea63SMichael S. Tsirkin } 2104e732ea63SMichael S. Tsirkin 2105d7bce999SEric Blake static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name, 2106d7bce999SEric Blake void *opaque, Error **errp) 2107e732ea63SMichael S. Tsirkin { 2108e732ea63SMichael S. Tsirkin uint16_t value = *(uint16_t *)opaque; 210951e72bc1SEric Blake visit_type_uint16(v, name, &value, errp); 2110e732ea63SMichael S. Tsirkin } 2111e732ea63SMichael S. Tsirkin 2112d7bce999SEric Blake static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name, 2113d7bce999SEric Blake void *opaque, Error **errp) 2114e732ea63SMichael S. Tsirkin { 2115e732ea63SMichael S. Tsirkin uint32_t value = *(uint32_t *)opaque; 211651e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 2117e732ea63SMichael S. Tsirkin } 2118e732ea63SMichael S. Tsirkin 2119d7bce999SEric Blake static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name, 2120d7bce999SEric Blake void *opaque, Error **errp) 2121e732ea63SMichael S. Tsirkin { 2122e732ea63SMichael S. Tsirkin uint64_t value = *(uint64_t *)opaque; 212351e72bc1SEric Blake visit_type_uint64(v, name, &value, errp); 2124e732ea63SMichael S. Tsirkin } 2125e732ea63SMichael S. Tsirkin 2126e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name, 2127e732ea63SMichael S. Tsirkin const uint8_t *v, Error **errp) 2128e732ea63SMichael S. Tsirkin { 2129e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint8", property_get_uint8_ptr, 2130e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2131e732ea63SMichael S. Tsirkin } 2132e732ea63SMichael S. Tsirkin 213316bf7f52SDaniel P. Berrange void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, 213416bf7f52SDaniel P. Berrange const uint8_t *v, Error **errp) 213516bf7f52SDaniel P. Berrange { 213616bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint8", property_get_uint8_ptr, 213716bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 213816bf7f52SDaniel P. Berrange } 213916bf7f52SDaniel P. Berrange 2140e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name, 2141e732ea63SMichael S. Tsirkin const uint16_t *v, Error **errp) 2142e732ea63SMichael S. Tsirkin { 2143e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint16", property_get_uint16_ptr, 2144e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2145e732ea63SMichael S. Tsirkin } 2146e732ea63SMichael S. Tsirkin 214716bf7f52SDaniel P. Berrange void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, 214816bf7f52SDaniel P. Berrange const uint16_t *v, Error **errp) 214916bf7f52SDaniel P. Berrange { 215016bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint16", property_get_uint16_ptr, 215116bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 215216bf7f52SDaniel P. Berrange } 215316bf7f52SDaniel P. Berrange 2154e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name, 2155e732ea63SMichael S. Tsirkin const uint32_t *v, Error **errp) 2156e732ea63SMichael S. Tsirkin { 2157e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint32", property_get_uint32_ptr, 2158e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2159e732ea63SMichael S. Tsirkin } 2160e732ea63SMichael S. Tsirkin 216116bf7f52SDaniel P. Berrange void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, 216216bf7f52SDaniel P. Berrange const uint32_t *v, Error **errp) 216316bf7f52SDaniel P. Berrange { 216416bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint32", property_get_uint32_ptr, 216516bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 216616bf7f52SDaniel P. Berrange } 216716bf7f52SDaniel P. Berrange 2168e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name, 2169e732ea63SMichael S. Tsirkin const uint64_t *v, Error **errp) 2170e732ea63SMichael S. Tsirkin { 2171e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint64", property_get_uint64_ptr, 2172e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2173e732ea63SMichael S. Tsirkin } 2174e732ea63SMichael S. Tsirkin 217516bf7f52SDaniel P. Berrange void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, 217616bf7f52SDaniel P. Berrange const uint64_t *v, Error **errp) 217716bf7f52SDaniel P. Berrange { 217816bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint64", property_get_uint64_ptr, 217916bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 218016bf7f52SDaniel P. Berrange } 218116bf7f52SDaniel P. Berrange 2182ef7c7ff6SStefan Hajnoczi typedef struct { 2183ef7c7ff6SStefan Hajnoczi Object *target_obj; 21841590d266SEduardo Habkost char *target_name; 2185ef7c7ff6SStefan Hajnoczi } AliasProperty; 2186ef7c7ff6SStefan Hajnoczi 2187d7bce999SEric Blake static void property_get_alias(Object *obj, Visitor *v, const char *name, 2188d7bce999SEric Blake void *opaque, Error **errp) 2189ef7c7ff6SStefan Hajnoczi { 2190ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2191ef7c7ff6SStefan Hajnoczi 2192ef7c7ff6SStefan Hajnoczi object_property_get(prop->target_obj, v, prop->target_name, errp); 2193ef7c7ff6SStefan Hajnoczi } 2194ef7c7ff6SStefan Hajnoczi 2195d7bce999SEric Blake static void property_set_alias(Object *obj, Visitor *v, const char *name, 2196d7bce999SEric Blake void *opaque, Error **errp) 2197ef7c7ff6SStefan Hajnoczi { 2198ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2199ef7c7ff6SStefan Hajnoczi 2200ef7c7ff6SStefan Hajnoczi object_property_set(prop->target_obj, v, prop->target_name, errp); 2201ef7c7ff6SStefan Hajnoczi } 2202ef7c7ff6SStefan Hajnoczi 220364607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque, 220464607d08SPaolo Bonzini const gchar *part) 220564607d08SPaolo Bonzini { 220664607d08SPaolo Bonzini AliasProperty *prop = opaque; 220764607d08SPaolo Bonzini 220864607d08SPaolo Bonzini return object_resolve_path_component(prop->target_obj, prop->target_name); 220964607d08SPaolo Bonzini } 221064607d08SPaolo Bonzini 2211ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque) 2212ef7c7ff6SStefan Hajnoczi { 2213ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2214ef7c7ff6SStefan Hajnoczi 22151590d266SEduardo Habkost g_free(prop->target_name); 2216ef7c7ff6SStefan Hajnoczi g_free(prop); 2217ef7c7ff6SStefan Hajnoczi } 2218ef7c7ff6SStefan Hajnoczi 2219ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name, 2220ef7c7ff6SStefan Hajnoczi Object *target_obj, const char *target_name, 2221ef7c7ff6SStefan Hajnoczi Error **errp) 2222ef7c7ff6SStefan Hajnoczi { 2223ef7c7ff6SStefan Hajnoczi AliasProperty *prop; 222464607d08SPaolo Bonzini ObjectProperty *op; 2225ef7c7ff6SStefan Hajnoczi ObjectProperty *target_prop; 2226d190698eSPaolo Bonzini gchar *prop_type; 22278ae9a9efSGonglei Error *local_err = NULL; 2228ef7c7ff6SStefan Hajnoczi 2229ef7c7ff6SStefan Hajnoczi target_prop = object_property_find(target_obj, target_name, errp); 2230ef7c7ff6SStefan Hajnoczi if (!target_prop) { 2231ef7c7ff6SStefan Hajnoczi return; 2232ef7c7ff6SStefan Hajnoczi } 2233ef7c7ff6SStefan Hajnoczi 2234d190698eSPaolo Bonzini if (object_property_is_child(target_prop)) { 2235d190698eSPaolo Bonzini prop_type = g_strdup_printf("link%s", 2236d190698eSPaolo Bonzini target_prop->type + strlen("child")); 2237d190698eSPaolo Bonzini } else { 2238d190698eSPaolo Bonzini prop_type = g_strdup(target_prop->type); 2239d190698eSPaolo Bonzini } 2240d190698eSPaolo Bonzini 2241ef7c7ff6SStefan Hajnoczi prop = g_malloc(sizeof(*prop)); 2242ef7c7ff6SStefan Hajnoczi prop->target_obj = target_obj; 22431590d266SEduardo Habkost prop->target_name = g_strdup(target_name); 2244ef7c7ff6SStefan Hajnoczi 2245d190698eSPaolo Bonzini op = object_property_add(obj, name, prop_type, 2246ef7c7ff6SStefan Hajnoczi property_get_alias, 2247ef7c7ff6SStefan Hajnoczi property_set_alias, 2248ef7c7ff6SStefan Hajnoczi property_release_alias, 22498ae9a9efSGonglei prop, &local_err); 22508ae9a9efSGonglei if (local_err) { 22518ae9a9efSGonglei error_propagate(errp, local_err); 22528ae9a9efSGonglei g_free(prop); 22538ae9a9efSGonglei goto out; 22548ae9a9efSGonglei } 225564607d08SPaolo Bonzini op->resolve = property_resolve_alias; 2256d190698eSPaolo Bonzini 2257a18bb417SAndreas Färber object_property_set_description(obj, op->name, 225880742642SGonglei target_prop->description, 225980742642SGonglei &error_abort); 226080742642SGonglei 22618ae9a9efSGonglei out: 2262d190698eSPaolo Bonzini g_free(prop_type); 2263ef7c7ff6SStefan Hajnoczi } 2264ef7c7ff6SStefan Hajnoczi 226580742642SGonglei void object_property_set_description(Object *obj, const char *name, 226680742642SGonglei const char *description, Error **errp) 226780742642SGonglei { 226880742642SGonglei ObjectProperty *op; 226980742642SGonglei 227080742642SGonglei op = object_property_find(obj, name, errp); 227180742642SGonglei if (!op) { 227280742642SGonglei return; 227380742642SGonglei } 227480742642SGonglei 227580742642SGonglei g_free(op->description); 227680742642SGonglei op->description = g_strdup(description); 227780742642SGonglei } 227880742642SGonglei 227916bf7f52SDaniel P. Berrange void object_class_property_set_description(ObjectClass *klass, 228016bf7f52SDaniel P. Berrange const char *name, 228116bf7f52SDaniel P. Berrange const char *description, 228216bf7f52SDaniel P. Berrange Error **errp) 228316bf7f52SDaniel P. Berrange { 228416bf7f52SDaniel P. Berrange ObjectProperty *op; 228516bf7f52SDaniel P. Berrange 228616bf7f52SDaniel P. Berrange op = g_hash_table_lookup(klass->properties, name); 228716bf7f52SDaniel P. Berrange if (!op) { 228816bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 228916bf7f52SDaniel P. Berrange return; 229016bf7f52SDaniel P. Berrange } 229116bf7f52SDaniel P. Berrange 229216bf7f52SDaniel P. Berrange g_free(op->description); 229316bf7f52SDaniel P. Berrange op->description = g_strdup(description); 229416bf7f52SDaniel P. Berrange } 229516bf7f52SDaniel P. Berrange 22962f262e06SPaolo Bonzini static void object_instance_init(Object *obj) 22972f262e06SPaolo Bonzini { 22982f262e06SPaolo Bonzini object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); 22992f262e06SPaolo Bonzini } 23002f262e06SPaolo Bonzini 2301745549c8SPaolo Bonzini static void register_types(void) 2302745549c8SPaolo Bonzini { 2303745549c8SPaolo Bonzini static TypeInfo interface_info = { 2304745549c8SPaolo Bonzini .name = TYPE_INTERFACE, 230533e95c63SAnthony Liguori .class_size = sizeof(InterfaceClass), 2306745549c8SPaolo Bonzini .abstract = true, 2307745549c8SPaolo Bonzini }; 2308745549c8SPaolo Bonzini 2309745549c8SPaolo Bonzini static TypeInfo object_info = { 2310745549c8SPaolo Bonzini .name = TYPE_OBJECT, 2311745549c8SPaolo Bonzini .instance_size = sizeof(Object), 23122f262e06SPaolo Bonzini .instance_init = object_instance_init, 2313745549c8SPaolo Bonzini .abstract = true, 2314745549c8SPaolo Bonzini }; 2315745549c8SPaolo Bonzini 2316049cb3cfSPaolo Bonzini type_interface = type_register_internal(&interface_info); 2317049cb3cfSPaolo Bonzini type_register_internal(&object_info); 2318745549c8SPaolo Bonzini } 2319745549c8SPaolo Bonzini 2320745549c8SPaolo Bonzini type_init(register_types) 2321