12f28d2ffSAnthony Liguori /* 22f28d2ffSAnthony Liguori * QEMU Object Model 32f28d2ffSAnthony Liguori * 42f28d2ffSAnthony Liguori * Copyright IBM, Corp. 2011 52f28d2ffSAnthony Liguori * 62f28d2ffSAnthony Liguori * Authors: 72f28d2ffSAnthony Liguori * Anthony Liguori <aliguori@us.ibm.com> 82f28d2ffSAnthony Liguori * 92f28d2ffSAnthony Liguori * This work is licensed under the terms of the GNU GPL, version 2 or later. 102f28d2ffSAnthony Liguori * See the COPYING file in the top-level directory. 112f28d2ffSAnthony Liguori */ 122f28d2ffSAnthony Liguori 132f28d2ffSAnthony Liguori #include "qemu/object.h" 142f28d2ffSAnthony Liguori #include "qemu-common.h" 1557c9fafeSAnthony Liguori #include "qapi/qapi-visit-core.h" 16b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h" 17b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h" 182f28d2ffSAnthony Liguori 197b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency 207b7b7d18SPaolo Bonzini * of the QOM core on QObject? */ 217b7b7d18SPaolo Bonzini #include "qemu/qom-qobject.h" 227b7b7d18SPaolo Bonzini #include "qobject.h" 237b7b7d18SPaolo Bonzini #include "qbool.h" 247b7b7d18SPaolo Bonzini #include "qint.h" 257b7b7d18SPaolo Bonzini #include "qstring.h" 267b7b7d18SPaolo Bonzini 272f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 282f28d2ffSAnthony Liguori 292f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 302f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 312f28d2ffSAnthony Liguori 322f28d2ffSAnthony Liguori struct InterfaceImpl 332f28d2ffSAnthony Liguori { 342f28d2ffSAnthony Liguori const char *parent; 352f28d2ffSAnthony Liguori void (*interface_initfn)(ObjectClass *class, void *data); 362f28d2ffSAnthony Liguori TypeImpl *type; 372f28d2ffSAnthony Liguori }; 382f28d2ffSAnthony Liguori 392f28d2ffSAnthony Liguori struct TypeImpl 402f28d2ffSAnthony Liguori { 412f28d2ffSAnthony Liguori const char *name; 422f28d2ffSAnthony Liguori 432f28d2ffSAnthony Liguori size_t class_size; 442f28d2ffSAnthony Liguori 452f28d2ffSAnthony Liguori size_t instance_size; 462f28d2ffSAnthony Liguori 472f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 482f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 492f28d2ffSAnthony Liguori 502f28d2ffSAnthony Liguori void *class_data; 512f28d2ffSAnthony Liguori 522f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 532f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 542f28d2ffSAnthony Liguori 552f28d2ffSAnthony Liguori bool abstract; 562f28d2ffSAnthony Liguori 572f28d2ffSAnthony Liguori const char *parent; 582f28d2ffSAnthony Liguori TypeImpl *parent_type; 592f28d2ffSAnthony Liguori 602f28d2ffSAnthony Liguori ObjectClass *class; 612f28d2ffSAnthony Liguori 622f28d2ffSAnthony Liguori int num_interfaces; 632f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 642f28d2ffSAnthony Liguori }; 652f28d2ffSAnthony Liguori 662f28d2ffSAnthony Liguori typedef struct Interface 672f28d2ffSAnthony Liguori { 682f28d2ffSAnthony Liguori Object parent; 692f28d2ffSAnthony Liguori Object *obj; 702f28d2ffSAnthony Liguori } Interface; 712f28d2ffSAnthony Liguori 722f28d2ffSAnthony Liguori #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE) 732f28d2ffSAnthony Liguori 749970bd88SPaolo Bonzini static Type type_interface; 759970bd88SPaolo Bonzini 762f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 772f28d2ffSAnthony Liguori { 782f28d2ffSAnthony Liguori static GHashTable *type_table; 792f28d2ffSAnthony Liguori 802f28d2ffSAnthony Liguori if (type_table == NULL) { 812f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 822f28d2ffSAnthony Liguori } 832f28d2ffSAnthony Liguori 842f28d2ffSAnthony Liguori return type_table; 852f28d2ffSAnthony Liguori } 862f28d2ffSAnthony Liguori 872f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 882f28d2ffSAnthony Liguori { 892f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 902f28d2ffSAnthony Liguori } 912f28d2ffSAnthony Liguori 922f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 932f28d2ffSAnthony Liguori { 942f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 952f28d2ffSAnthony Liguori } 962f28d2ffSAnthony Liguori 972f28d2ffSAnthony Liguori TypeImpl *type_register(const TypeInfo *info) 982f28d2ffSAnthony Liguori { 992f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 1002f28d2ffSAnthony Liguori 1012f28d2ffSAnthony Liguori g_assert(info->name != NULL); 1022f28d2ffSAnthony Liguori 10373093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 10473093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 10573093354SAnthony Liguori abort(); 10673093354SAnthony Liguori } 10773093354SAnthony Liguori 1082f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1092f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1102f28d2ffSAnthony Liguori 1112f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1122f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1132f28d2ffSAnthony Liguori 1142f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1152f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1162f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1172f28d2ffSAnthony Liguori 1182f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1192f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1202f28d2ffSAnthony Liguori 1212f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1222f28d2ffSAnthony Liguori 1232f28d2ffSAnthony Liguori if (info->interfaces) { 1242f28d2ffSAnthony Liguori int i; 1252f28d2ffSAnthony Liguori 1262f28d2ffSAnthony Liguori for (i = 0; info->interfaces[i].type; i++) { 1272f28d2ffSAnthony Liguori ti->interfaces[i].parent = info->interfaces[i].type; 1282f28d2ffSAnthony Liguori ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn; 1292f28d2ffSAnthony Liguori ti->num_interfaces++; 1302f28d2ffSAnthony Liguori } 1312f28d2ffSAnthony Liguori } 1322f28d2ffSAnthony Liguori 1332f28d2ffSAnthony Liguori type_table_add(ti); 1342f28d2ffSAnthony Liguori 1352f28d2ffSAnthony Liguori return ti; 1362f28d2ffSAnthony Liguori } 1372f28d2ffSAnthony Liguori 1382f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1392f28d2ffSAnthony Liguori { 1402f28d2ffSAnthony Liguori return type_register(info); 1412f28d2ffSAnthony Liguori } 1422f28d2ffSAnthony Liguori 1432f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1442f28d2ffSAnthony Liguori { 1452f28d2ffSAnthony Liguori if (name == NULL) { 1462f28d2ffSAnthony Liguori return NULL; 1472f28d2ffSAnthony Liguori } 1482f28d2ffSAnthony Liguori 1492f28d2ffSAnthony Liguori return type_table_lookup(name); 1502f28d2ffSAnthony Liguori } 1512f28d2ffSAnthony Liguori 1522f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1532f28d2ffSAnthony Liguori { 1542f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1552f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1562f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1572f28d2ffSAnthony Liguori } 1582f28d2ffSAnthony Liguori 1592f28d2ffSAnthony Liguori return type->parent_type; 1602f28d2ffSAnthony Liguori } 1612f28d2ffSAnthony Liguori 1622f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1632f28d2ffSAnthony Liguori { 1642f28d2ffSAnthony Liguori return (type->parent != NULL); 1652f28d2ffSAnthony Liguori } 1662f28d2ffSAnthony Liguori 1672f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1682f28d2ffSAnthony Liguori { 1692f28d2ffSAnthony Liguori if (ti->class_size) { 1702f28d2ffSAnthony Liguori return ti->class_size; 1712f28d2ffSAnthony Liguori } 1722f28d2ffSAnthony Liguori 1732f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1742f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1752f28d2ffSAnthony Liguori } 1762f28d2ffSAnthony Liguori 1772f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1782f28d2ffSAnthony Liguori } 1792f28d2ffSAnthony Liguori 180aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 181aca59af6SIgor Mitsyanko { 182aca59af6SIgor Mitsyanko if (ti->instance_size) { 183aca59af6SIgor Mitsyanko return ti->instance_size; 184aca59af6SIgor Mitsyanko } 185aca59af6SIgor Mitsyanko 186aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 187aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 188aca59af6SIgor Mitsyanko } 189aca59af6SIgor Mitsyanko 190aca59af6SIgor Mitsyanko return 0; 191aca59af6SIgor Mitsyanko } 192aca59af6SIgor Mitsyanko 1932f28d2ffSAnthony Liguori static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface) 1942f28d2ffSAnthony Liguori { 1952f28d2ffSAnthony Liguori TypeInfo info = { 1962f28d2ffSAnthony Liguori .instance_size = sizeof(Interface), 1972f28d2ffSAnthony Liguori .parent = iface->parent, 1982f28d2ffSAnthony Liguori .class_size = sizeof(InterfaceClass), 1992f28d2ffSAnthony Liguori .class_init = iface->interface_initfn, 2002f28d2ffSAnthony Liguori .abstract = true, 2012f28d2ffSAnthony Liguori }; 2022f28d2ffSAnthony Liguori char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent); 2032f28d2ffSAnthony Liguori 2042f28d2ffSAnthony Liguori info.name = name; 2052f28d2ffSAnthony Liguori iface->type = type_register(&info); 2062f28d2ffSAnthony Liguori g_free(name); 2072f28d2ffSAnthony Liguori } 2082f28d2ffSAnthony Liguori 209ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2102f28d2ffSAnthony Liguori { 2112f28d2ffSAnthony Liguori size_t class_size = sizeof(ObjectClass); 2122f28d2ffSAnthony Liguori int i; 2132f28d2ffSAnthony Liguori 2142f28d2ffSAnthony Liguori if (ti->class) { 2152f28d2ffSAnthony Liguori return; 2162f28d2ffSAnthony Liguori } 2172f28d2ffSAnthony Liguori 2182f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 219aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2202f28d2ffSAnthony Liguori 2212f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 2222f28d2ffSAnthony Liguori ti->class->type = ti; 2232f28d2ffSAnthony Liguori 2242f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 2252f28d2ffSAnthony Liguori TypeImpl *parent = type_get_parent(ti); 2262f28d2ffSAnthony Liguori 227ac451033SIgor Mitsyanko type_initialize(parent); 2282f28d2ffSAnthony Liguori 2292f28d2ffSAnthony Liguori class_size = parent->class_size; 2302f28d2ffSAnthony Liguori g_assert(parent->class_size <= ti->class_size); 2312f28d2ffSAnthony Liguori 2322f28d2ffSAnthony Liguori memcpy((void *)ti->class + sizeof(ObjectClass), 2332f28d2ffSAnthony Liguori (void *)parent->class + sizeof(ObjectClass), 2342f28d2ffSAnthony Liguori parent->class_size - sizeof(ObjectClass)); 2352f28d2ffSAnthony Liguori } 2362f28d2ffSAnthony Liguori 2372f28d2ffSAnthony Liguori memset((void *)ti->class + class_size, 0, ti->class_size - class_size); 2382f28d2ffSAnthony Liguori 2392f28d2ffSAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 2402f28d2ffSAnthony Liguori type_class_interface_init(ti, &ti->interfaces[i]); 2412f28d2ffSAnthony Liguori } 2422f28d2ffSAnthony Liguori 2432f28d2ffSAnthony Liguori if (ti->class_init) { 2442f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 2452f28d2ffSAnthony Liguori } 2462f28d2ffSAnthony Liguori } 2472f28d2ffSAnthony Liguori 2482f28d2ffSAnthony Liguori static void object_interface_init(Object *obj, InterfaceImpl *iface) 2492f28d2ffSAnthony Liguori { 2502f28d2ffSAnthony Liguori TypeImpl *ti = iface->type; 2512f28d2ffSAnthony Liguori Interface *iface_obj; 2522f28d2ffSAnthony Liguori 2532f28d2ffSAnthony Liguori iface_obj = INTERFACE(object_new(ti->name)); 2542f28d2ffSAnthony Liguori iface_obj->obj = obj; 2552f28d2ffSAnthony Liguori 2562f28d2ffSAnthony Liguori obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj); 2572f28d2ffSAnthony Liguori } 2582f28d2ffSAnthony Liguori 2592f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 2602f28d2ffSAnthony Liguori { 2612f28d2ffSAnthony Liguori int i; 2622f28d2ffSAnthony Liguori 2632f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 2642f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 2652f28d2ffSAnthony Liguori } 2662f28d2ffSAnthony Liguori 2672f28d2ffSAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 2682f28d2ffSAnthony Liguori object_interface_init(obj, &ti->interfaces[i]); 2692f28d2ffSAnthony Liguori } 2702f28d2ffSAnthony Liguori 2712f28d2ffSAnthony Liguori if (ti->instance_init) { 2722f28d2ffSAnthony Liguori ti->instance_init(obj); 2732f28d2ffSAnthony Liguori } 2742f28d2ffSAnthony Liguori } 2752f28d2ffSAnthony Liguori 2762f28d2ffSAnthony Liguori void object_initialize_with_type(void *data, TypeImpl *type) 2772f28d2ffSAnthony Liguori { 2782f28d2ffSAnthony Liguori Object *obj = data; 2792f28d2ffSAnthony Liguori 2802f28d2ffSAnthony Liguori g_assert(type != NULL); 281ac451033SIgor Mitsyanko type_initialize(type); 282aca59af6SIgor Mitsyanko 283aca59af6SIgor Mitsyanko g_assert(type->instance_size >= sizeof(Object)); 2842f28d2ffSAnthony Liguori g_assert(type->abstract == false); 2852f28d2ffSAnthony Liguori 2862f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 2872f28d2ffSAnthony Liguori obj->class = type->class; 28857c9fafeSAnthony Liguori QTAILQ_INIT(&obj->properties); 2892f28d2ffSAnthony Liguori object_init_with_type(obj, type); 2902f28d2ffSAnthony Liguori } 2912f28d2ffSAnthony Liguori 2922f28d2ffSAnthony Liguori void object_initialize(void *data, const char *typename) 2932f28d2ffSAnthony Liguori { 2942f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 2952f28d2ffSAnthony Liguori 2962f28d2ffSAnthony Liguori object_initialize_with_type(data, type); 2972f28d2ffSAnthony Liguori } 2982f28d2ffSAnthony Liguori 29957c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 30057c9fafeSAnthony Liguori { 30157c9fafeSAnthony Liguori while (!QTAILQ_EMPTY(&obj->properties)) { 30257c9fafeSAnthony Liguori ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); 30357c9fafeSAnthony Liguori 30457c9fafeSAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 30557c9fafeSAnthony Liguori 30657c9fafeSAnthony Liguori if (prop->release) { 30757c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 30857c9fafeSAnthony Liguori } 30957c9fafeSAnthony Liguori 31057c9fafeSAnthony Liguori g_free(prop->name); 31157c9fafeSAnthony Liguori g_free(prop->type); 31257c9fafeSAnthony Liguori g_free(prop); 31357c9fafeSAnthony Liguori } 31457c9fafeSAnthony Liguori } 31557c9fafeSAnthony Liguori 31657c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 31757c9fafeSAnthony Liguori { 31857c9fafeSAnthony Liguori ObjectProperty *prop; 31957c9fafeSAnthony Liguori 32057c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 3216c1fdcf9SPaolo Bonzini if (strstart(prop->type, "child<", NULL) && prop->opaque == child) { 32257c9fafeSAnthony Liguori object_property_del(obj, prop->name, errp); 3236c1fdcf9SPaolo Bonzini break; 32457c9fafeSAnthony Liguori } 32557c9fafeSAnthony Liguori } 32657c9fafeSAnthony Liguori } 32757c9fafeSAnthony Liguori 32857c9fafeSAnthony Liguori void object_unparent(Object *obj) 32957c9fafeSAnthony Liguori { 33057c9fafeSAnthony Liguori if (obj->parent) { 33157c9fafeSAnthony Liguori object_property_del_child(obj->parent, obj, NULL); 33257c9fafeSAnthony Liguori } 33357c9fafeSAnthony Liguori } 33457c9fafeSAnthony Liguori 3352f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 3362f28d2ffSAnthony Liguori { 3372f28d2ffSAnthony Liguori if (type->instance_finalize) { 3382f28d2ffSAnthony Liguori type->instance_finalize(obj); 3392f28d2ffSAnthony Liguori } 3402f28d2ffSAnthony Liguori 3412f28d2ffSAnthony Liguori while (obj->interfaces) { 3422f28d2ffSAnthony Liguori Interface *iface_obj = obj->interfaces->data; 3432f28d2ffSAnthony Liguori obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces); 3442f28d2ffSAnthony Liguori object_delete(OBJECT(iface_obj)); 3452f28d2ffSAnthony Liguori } 3462f28d2ffSAnthony Liguori 3472f28d2ffSAnthony Liguori if (type_has_parent(type)) { 3482f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 3492f28d2ffSAnthony Liguori } 35057c9fafeSAnthony Liguori 35157c9fafeSAnthony Liguori object_unparent(obj); 3522f28d2ffSAnthony Liguori } 3532f28d2ffSAnthony Liguori 3542f28d2ffSAnthony Liguori void object_finalize(void *data) 3552f28d2ffSAnthony Liguori { 3562f28d2ffSAnthony Liguori Object *obj = data; 3572f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 3582f28d2ffSAnthony Liguori 3592f28d2ffSAnthony Liguori object_deinit(obj, ti); 36057c9fafeSAnthony Liguori object_property_del_all(obj); 361db85b575SAnthony Liguori 362db85b575SAnthony Liguori g_assert(obj->ref == 0); 3632f28d2ffSAnthony Liguori } 3642f28d2ffSAnthony Liguori 3652f28d2ffSAnthony Liguori Object *object_new_with_type(Type type) 3662f28d2ffSAnthony Liguori { 3672f28d2ffSAnthony Liguori Object *obj; 3682f28d2ffSAnthony Liguori 3692f28d2ffSAnthony Liguori g_assert(type != NULL); 370ac451033SIgor Mitsyanko type_initialize(type); 3712f28d2ffSAnthony Liguori 3722f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 3732f28d2ffSAnthony Liguori object_initialize_with_type(obj, type); 374db85b575SAnthony Liguori object_ref(obj); 3752f28d2ffSAnthony Liguori 3762f28d2ffSAnthony Liguori return obj; 3772f28d2ffSAnthony Liguori } 3782f28d2ffSAnthony Liguori 3792f28d2ffSAnthony Liguori Object *object_new(const char *typename) 3802f28d2ffSAnthony Liguori { 3812f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 3822f28d2ffSAnthony Liguori 3832f28d2ffSAnthony Liguori return object_new_with_type(ti); 3842f28d2ffSAnthony Liguori } 3852f28d2ffSAnthony Liguori 3862f28d2ffSAnthony Liguori void object_delete(Object *obj) 3872f28d2ffSAnthony Liguori { 388db85b575SAnthony Liguori object_unref(obj); 389db85b575SAnthony Liguori g_assert(obj->ref == 0); 3902f28d2ffSAnthony Liguori g_free(obj); 3912f28d2ffSAnthony Liguori } 3922f28d2ffSAnthony Liguori 393acc4af3fSPaolo Bonzini static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 3942f28d2ffSAnthony Liguori { 395acc4af3fSPaolo Bonzini assert(target_type); 3962f28d2ffSAnthony Liguori 3972f28d2ffSAnthony Liguori /* Check if typename is a direct ancestor of type */ 3982f28d2ffSAnthony Liguori while (type) { 3992f28d2ffSAnthony Liguori if (type == target_type) { 4002f28d2ffSAnthony Liguori return true; 4012f28d2ffSAnthony Liguori } 4022f28d2ffSAnthony Liguori 4032f28d2ffSAnthony Liguori type = type_get_parent(type); 4042f28d2ffSAnthony Liguori } 4052f28d2ffSAnthony Liguori 406acc4af3fSPaolo Bonzini return false; 407acc4af3fSPaolo Bonzini } 4082f28d2ffSAnthony Liguori 4099970bd88SPaolo Bonzini static bool object_is_type(Object *obj, TypeImpl *target_type) 410acc4af3fSPaolo Bonzini { 4119970bd88SPaolo Bonzini return !target_type || type_is_ancestor(obj->class->type, target_type); 4122f28d2ffSAnthony Liguori } 4132f28d2ffSAnthony Liguori 4142f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 4152f28d2ffSAnthony Liguori { 4169970bd88SPaolo Bonzini TypeImpl *target_type = type_get_by_name(typename); 4172f28d2ffSAnthony Liguori GSList *i; 4182f28d2ffSAnthony Liguori 419acc4af3fSPaolo Bonzini /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT, 420acc4af3fSPaolo Bonzini * we want to go back from interfaces to the parent. 421acc4af3fSPaolo Bonzini */ 4229970bd88SPaolo Bonzini if (target_type && object_is_type(obj, target_type)) { 423acc4af3fSPaolo Bonzini return obj; 424acc4af3fSPaolo Bonzini } 425acc4af3fSPaolo Bonzini 426acc4af3fSPaolo Bonzini /* Check if obj is an interface and its containing object is a direct 427acc4af3fSPaolo Bonzini * ancestor of typename. In principle we could do this test at the very 428acc4af3fSPaolo Bonzini * beginning of object_dynamic_cast, avoiding a second call to 429acc4af3fSPaolo Bonzini * object_is_type. However, casting between interfaces is relatively 4309970bd88SPaolo Bonzini * rare, and object_is_type(obj, type_interface) would fail almost always. 431acc4af3fSPaolo Bonzini * 432acc4af3fSPaolo Bonzini * Perhaps we could add a magic value to the object header for increased 433acc4af3fSPaolo Bonzini * (run-time) type safety and to speed up tests like this one. If we ever 434acc4af3fSPaolo Bonzini * do that we can revisit the order here. 435acc4af3fSPaolo Bonzini */ 4369970bd88SPaolo Bonzini if (object_is_type(obj, type_interface)) { 437acc4af3fSPaolo Bonzini assert(!obj->interfaces); 438acc4af3fSPaolo Bonzini obj = INTERFACE(obj)->obj; 4399970bd88SPaolo Bonzini if (object_is_type(obj, target_type)) { 4402f28d2ffSAnthony Liguori return obj; 4412f28d2ffSAnthony Liguori } 442acc4af3fSPaolo Bonzini } 443acc4af3fSPaolo Bonzini 4449970bd88SPaolo Bonzini if (!target_type) { 445acc4af3fSPaolo Bonzini return obj; 446acc4af3fSPaolo Bonzini } 4472f28d2ffSAnthony Liguori 4482f28d2ffSAnthony Liguori /* Check if obj has an interface of typename */ 4492f28d2ffSAnthony Liguori for (i = obj->interfaces; i; i = i->next) { 4502f28d2ffSAnthony Liguori Interface *iface = i->data; 4512f28d2ffSAnthony Liguori 4529970bd88SPaolo Bonzini if (object_is_type(OBJECT(iface), target_type)) { 4532f28d2ffSAnthony Liguori return OBJECT(iface); 4542f28d2ffSAnthony Liguori } 4552f28d2ffSAnthony Liguori } 4562f28d2ffSAnthony Liguori 4572f28d2ffSAnthony Liguori return NULL; 4582f28d2ffSAnthony Liguori } 4592f28d2ffSAnthony Liguori 4602f28d2ffSAnthony Liguori 46183f7d43aSAndreas Färber static void register_types(void) 4622f28d2ffSAnthony Liguori { 4632f28d2ffSAnthony Liguori static TypeInfo interface_info = { 4642f28d2ffSAnthony Liguori .name = TYPE_INTERFACE, 4652f28d2ffSAnthony Liguori .instance_size = sizeof(Interface), 4662f28d2ffSAnthony Liguori .abstract = true, 4672f28d2ffSAnthony Liguori }; 4682f28d2ffSAnthony Liguori 4699970bd88SPaolo Bonzini type_interface = type_register_static(&interface_info); 4702f28d2ffSAnthony Liguori } 4712f28d2ffSAnthony Liguori 47283f7d43aSAndreas Färber type_init(register_types) 4732f28d2ffSAnthony Liguori 4742f28d2ffSAnthony Liguori Object *object_dynamic_cast_assert(Object *obj, const char *typename) 4752f28d2ffSAnthony Liguori { 4762f28d2ffSAnthony Liguori Object *inst; 4772f28d2ffSAnthony Liguori 4782f28d2ffSAnthony Liguori inst = object_dynamic_cast(obj, typename); 4792f28d2ffSAnthony Liguori 4802f28d2ffSAnthony Liguori if (!inst) { 4812f28d2ffSAnthony Liguori fprintf(stderr, "Object %p is not an instance of type %s\n", 4822f28d2ffSAnthony Liguori obj, typename); 4832f28d2ffSAnthony Liguori abort(); 4842f28d2ffSAnthony Liguori } 4852f28d2ffSAnthony Liguori 4862f28d2ffSAnthony Liguori return inst; 4872f28d2ffSAnthony Liguori } 4882f28d2ffSAnthony Liguori 4892f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 4902f28d2ffSAnthony Liguori const char *typename) 4912f28d2ffSAnthony Liguori { 4922f28d2ffSAnthony Liguori TypeImpl *target_type = type_get_by_name(typename); 4932f28d2ffSAnthony Liguori TypeImpl *type = class->type; 4942f28d2ffSAnthony Liguori 4952f28d2ffSAnthony Liguori while (type) { 4962f28d2ffSAnthony Liguori if (type == target_type) { 4972f28d2ffSAnthony Liguori return class; 4982f28d2ffSAnthony Liguori } 4992f28d2ffSAnthony Liguori 5002f28d2ffSAnthony Liguori type = type_get_parent(type); 5012f28d2ffSAnthony Liguori } 5022f28d2ffSAnthony Liguori 5032f28d2ffSAnthony Liguori return NULL; 5042f28d2ffSAnthony Liguori } 5052f28d2ffSAnthony Liguori 5062f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 5072f28d2ffSAnthony Liguori const char *typename) 5082f28d2ffSAnthony Liguori { 5092f28d2ffSAnthony Liguori ObjectClass *ret = object_class_dynamic_cast(class, typename); 5102f28d2ffSAnthony Liguori 5112f28d2ffSAnthony Liguori if (!ret) { 5122f28d2ffSAnthony Liguori fprintf(stderr, "Object %p is not an instance of type %s\n", 5132f28d2ffSAnthony Liguori class, typename); 5142f28d2ffSAnthony Liguori abort(); 5152f28d2ffSAnthony Liguori } 5162f28d2ffSAnthony Liguori 5172f28d2ffSAnthony Liguori return ret; 5182f28d2ffSAnthony Liguori } 5192f28d2ffSAnthony Liguori 5202f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj) 5212f28d2ffSAnthony Liguori { 5222f28d2ffSAnthony Liguori return obj->class->type->name; 5232f28d2ffSAnthony Liguori } 5242f28d2ffSAnthony Liguori 5252f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 5262f28d2ffSAnthony Liguori { 5272f28d2ffSAnthony Liguori return obj->class; 5282f28d2ffSAnthony Liguori } 5292f28d2ffSAnthony Liguori 5302f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 5312f28d2ffSAnthony Liguori { 5322f28d2ffSAnthony Liguori return klass->type->name; 5332f28d2ffSAnthony Liguori } 5342f28d2ffSAnthony Liguori 5352f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 5362f28d2ffSAnthony Liguori { 5372f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 5382f28d2ffSAnthony Liguori 5392f28d2ffSAnthony Liguori if (!type) { 5402f28d2ffSAnthony Liguori return NULL; 5412f28d2ffSAnthony Liguori } 5422f28d2ffSAnthony Liguori 543ac451033SIgor Mitsyanko type_initialize(type); 5442f28d2ffSAnthony Liguori 5452f28d2ffSAnthony Liguori return type->class; 5462f28d2ffSAnthony Liguori } 5472f28d2ffSAnthony Liguori 5482f28d2ffSAnthony Liguori typedef struct OCFData 5492f28d2ffSAnthony Liguori { 5502f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 55193c511a1SAnthony Liguori const char *implements_type; 55293c511a1SAnthony Liguori bool include_abstract; 5532f28d2ffSAnthony Liguori void *opaque; 5542f28d2ffSAnthony Liguori } OCFData; 5552f28d2ffSAnthony Liguori 5562f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 5572f28d2ffSAnthony Liguori gpointer opaque) 5582f28d2ffSAnthony Liguori { 5592f28d2ffSAnthony Liguori OCFData *data = opaque; 5602f28d2ffSAnthony Liguori TypeImpl *type = value; 56193c511a1SAnthony Liguori ObjectClass *k; 5622f28d2ffSAnthony Liguori 563ac451033SIgor Mitsyanko type_initialize(type); 56493c511a1SAnthony Liguori k = type->class; 5652f28d2ffSAnthony Liguori 56693c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 56793c511a1SAnthony Liguori return; 56893c511a1SAnthony Liguori } 56993c511a1SAnthony Liguori 57093c511a1SAnthony Liguori if (data->implements_type && 57193c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 57293c511a1SAnthony Liguori return; 57393c511a1SAnthony Liguori } 57493c511a1SAnthony Liguori 57593c511a1SAnthony Liguori data->fn(k, data->opaque); 5762f28d2ffSAnthony Liguori } 5772f28d2ffSAnthony Liguori 5782f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 57993c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 5802f28d2ffSAnthony Liguori void *opaque) 5812f28d2ffSAnthony Liguori { 58293c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 5832f28d2ffSAnthony Liguori 5842f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 5852f28d2ffSAnthony Liguori } 58657c9fafeSAnthony Liguori 587418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 588418ba9e5SAndreas Färber { 589418ba9e5SAndreas Färber GSList **list = opaque; 590418ba9e5SAndreas Färber 591418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 592418ba9e5SAndreas Färber } 593418ba9e5SAndreas Färber 594418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 595418ba9e5SAndreas Färber bool include_abstract) 596418ba9e5SAndreas Färber { 597418ba9e5SAndreas Färber GSList *list = NULL; 598418ba9e5SAndreas Färber 599418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 600418ba9e5SAndreas Färber implements_type, include_abstract, &list); 601418ba9e5SAndreas Färber return list; 602418ba9e5SAndreas Färber } 603418ba9e5SAndreas Färber 60457c9fafeSAnthony Liguori void object_ref(Object *obj) 60557c9fafeSAnthony Liguori { 60657c9fafeSAnthony Liguori obj->ref++; 60757c9fafeSAnthony Liguori } 60857c9fafeSAnthony Liguori 60957c9fafeSAnthony Liguori void object_unref(Object *obj) 61057c9fafeSAnthony Liguori { 61157c9fafeSAnthony Liguori g_assert(obj->ref > 0); 61257c9fafeSAnthony Liguori obj->ref--; 61357c9fafeSAnthony Liguori 61457c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 61557c9fafeSAnthony Liguori if (obj->ref == 0) { 61657c9fafeSAnthony Liguori object_finalize(obj); 61757c9fafeSAnthony Liguori } 61857c9fafeSAnthony Liguori } 61957c9fafeSAnthony Liguori 62057c9fafeSAnthony Liguori void object_property_add(Object *obj, const char *name, const char *type, 62157c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 62257c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 62357c9fafeSAnthony Liguori ObjectPropertyRelease *release, 62457c9fafeSAnthony Liguori void *opaque, Error **errp) 62557c9fafeSAnthony Liguori { 62657c9fafeSAnthony Liguori ObjectProperty *prop = g_malloc0(sizeof(*prop)); 62757c9fafeSAnthony Liguori 62857c9fafeSAnthony Liguori prop->name = g_strdup(name); 62957c9fafeSAnthony Liguori prop->type = g_strdup(type); 63057c9fafeSAnthony Liguori 63157c9fafeSAnthony Liguori prop->get = get; 63257c9fafeSAnthony Liguori prop->set = set; 63357c9fafeSAnthony Liguori prop->release = release; 63457c9fafeSAnthony Liguori prop->opaque = opaque; 63557c9fafeSAnthony Liguori 63657c9fafeSAnthony Liguori QTAILQ_INSERT_TAIL(&obj->properties, prop, node); 63757c9fafeSAnthony Liguori } 63857c9fafeSAnthony Liguori 63957c9fafeSAnthony Liguori static ObjectProperty *object_property_find(Object *obj, const char *name) 64057c9fafeSAnthony Liguori { 64157c9fafeSAnthony Liguori ObjectProperty *prop; 64257c9fafeSAnthony Liguori 64357c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 64457c9fafeSAnthony Liguori if (strcmp(prop->name, name) == 0) { 64557c9fafeSAnthony Liguori return prop; 64657c9fafeSAnthony Liguori } 64757c9fafeSAnthony Liguori } 64857c9fafeSAnthony Liguori 64957c9fafeSAnthony Liguori return NULL; 65057c9fafeSAnthony Liguori } 65157c9fafeSAnthony Liguori 65257c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 65357c9fafeSAnthony Liguori { 65457c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 65557c9fafeSAnthony Liguori 65657c9fafeSAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 65757c9fafeSAnthony Liguori 65857c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 65957c9fafeSAnthony Liguori 66057c9fafeSAnthony Liguori g_free(prop->name); 66157c9fafeSAnthony Liguori g_free(prop->type); 66257c9fafeSAnthony Liguori g_free(prop); 66357c9fafeSAnthony Liguori } 66457c9fafeSAnthony Liguori 66557c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 66657c9fafeSAnthony Liguori Error **errp) 66757c9fafeSAnthony Liguori { 66857c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 66957c9fafeSAnthony Liguori 67057c9fafeSAnthony Liguori if (prop == NULL) { 67157c9fafeSAnthony Liguori error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 67257c9fafeSAnthony Liguori return; 67357c9fafeSAnthony Liguori } 67457c9fafeSAnthony Liguori 67557c9fafeSAnthony Liguori if (!prop->get) { 67657c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 67757c9fafeSAnthony Liguori } else { 67857c9fafeSAnthony Liguori prop->get(obj, v, prop->opaque, name, errp); 67957c9fafeSAnthony Liguori } 68057c9fafeSAnthony Liguori } 68157c9fafeSAnthony Liguori 68257c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 68357c9fafeSAnthony Liguori Error **errp) 68457c9fafeSAnthony Liguori { 68557c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 68657c9fafeSAnthony Liguori 68757c9fafeSAnthony Liguori if (prop == NULL) { 68857c9fafeSAnthony Liguori error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 68957c9fafeSAnthony Liguori return; 69057c9fafeSAnthony Liguori } 69157c9fafeSAnthony Liguori 69257c9fafeSAnthony Liguori if (!prop->set) { 69357c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 69457c9fafeSAnthony Liguori } else { 69557c9fafeSAnthony Liguori prop->set(obj, v, prop->opaque, name, errp); 69657c9fafeSAnthony Liguori } 69757c9fafeSAnthony Liguori } 69857c9fafeSAnthony Liguori 6997b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 7007b7b7d18SPaolo Bonzini const char *name, Error **errp) 7017b7b7d18SPaolo Bonzini { 7027b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 7037b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 7047b7b7d18SPaolo Bonzini 7057b7b7d18SPaolo Bonzini QDECREF(qstr); 7067b7b7d18SPaolo Bonzini } 7077b7b7d18SPaolo Bonzini 7087b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 7097b7b7d18SPaolo Bonzini Error **errp) 7107b7b7d18SPaolo Bonzini { 7117b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 7127b7b7d18SPaolo Bonzini QString *qstring; 7137b7b7d18SPaolo Bonzini char *retval; 7147b7b7d18SPaolo Bonzini 7157b7b7d18SPaolo Bonzini if (!ret) { 7167b7b7d18SPaolo Bonzini return NULL; 7177b7b7d18SPaolo Bonzini } 7187b7b7d18SPaolo Bonzini qstring = qobject_to_qstring(ret); 7197b7b7d18SPaolo Bonzini if (!qstring) { 7207b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 7217b7b7d18SPaolo Bonzini retval = NULL; 7227b7b7d18SPaolo Bonzini } else { 7237b7b7d18SPaolo Bonzini retval = g_strdup(qstring_get_str(qstring)); 7247b7b7d18SPaolo Bonzini } 7257b7b7d18SPaolo Bonzini 7267b7b7d18SPaolo Bonzini QDECREF(qstring); 7277b7b7d18SPaolo Bonzini return retval; 7287b7b7d18SPaolo Bonzini } 7297b7b7d18SPaolo Bonzini 7301d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 7311d9c5a12SPaolo Bonzini const char *name, Error **errp) 7321d9c5a12SPaolo Bonzini { 7331d9c5a12SPaolo Bonzini object_property_set_str(obj, object_get_canonical_path(value), 7341d9c5a12SPaolo Bonzini name, errp); 7351d9c5a12SPaolo Bonzini } 7361d9c5a12SPaolo Bonzini 7371d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 7381d9c5a12SPaolo Bonzini Error **errp) 7391d9c5a12SPaolo Bonzini { 7401d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 7411d9c5a12SPaolo Bonzini Object *target = NULL; 7421d9c5a12SPaolo Bonzini 7431d9c5a12SPaolo Bonzini if (str && *str) { 7441d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 7451d9c5a12SPaolo Bonzini if (!target) { 7461d9c5a12SPaolo Bonzini error_set(errp, QERR_DEVICE_NOT_FOUND, str); 7471d9c5a12SPaolo Bonzini } 7481d9c5a12SPaolo Bonzini } 7491d9c5a12SPaolo Bonzini 7501d9c5a12SPaolo Bonzini g_free(str); 7511d9c5a12SPaolo Bonzini return target; 7521d9c5a12SPaolo Bonzini } 7531d9c5a12SPaolo Bonzini 7547b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 7557b7b7d18SPaolo Bonzini const char *name, Error **errp) 7567b7b7d18SPaolo Bonzini { 7577b7b7d18SPaolo Bonzini QBool *qbool = qbool_from_int(value); 7587b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 7597b7b7d18SPaolo Bonzini 7607b7b7d18SPaolo Bonzini QDECREF(qbool); 7617b7b7d18SPaolo Bonzini } 7627b7b7d18SPaolo Bonzini 7637b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 7647b7b7d18SPaolo Bonzini Error **errp) 7657b7b7d18SPaolo Bonzini { 7667b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 7677b7b7d18SPaolo Bonzini QBool *qbool; 7687b7b7d18SPaolo Bonzini bool retval; 7697b7b7d18SPaolo Bonzini 7707b7b7d18SPaolo Bonzini if (!ret) { 7717b7b7d18SPaolo Bonzini return false; 7727b7b7d18SPaolo Bonzini } 7737b7b7d18SPaolo Bonzini qbool = qobject_to_qbool(ret); 7747b7b7d18SPaolo Bonzini if (!qbool) { 7757b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 7767b7b7d18SPaolo Bonzini retval = false; 7777b7b7d18SPaolo Bonzini } else { 7787b7b7d18SPaolo Bonzini retval = qbool_get_int(qbool); 7797b7b7d18SPaolo Bonzini } 7807b7b7d18SPaolo Bonzini 7817b7b7d18SPaolo Bonzini QDECREF(qbool); 7827b7b7d18SPaolo Bonzini return retval; 7837b7b7d18SPaolo Bonzini } 7847b7b7d18SPaolo Bonzini 7857b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 7867b7b7d18SPaolo Bonzini const char *name, Error **errp) 7877b7b7d18SPaolo Bonzini { 7887b7b7d18SPaolo Bonzini QInt *qint = qint_from_int(value); 7897b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qint), name, errp); 7907b7b7d18SPaolo Bonzini 7917b7b7d18SPaolo Bonzini QDECREF(qint); 7927b7b7d18SPaolo Bonzini } 7937b7b7d18SPaolo Bonzini 7947b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 7957b7b7d18SPaolo Bonzini Error **errp) 7967b7b7d18SPaolo Bonzini { 7977b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 7987b7b7d18SPaolo Bonzini QInt *qint; 7997b7b7d18SPaolo Bonzini int64_t retval; 8007b7b7d18SPaolo Bonzini 8017b7b7d18SPaolo Bonzini if (!ret) { 8027b7b7d18SPaolo Bonzini return -1; 8037b7b7d18SPaolo Bonzini } 8047b7b7d18SPaolo Bonzini qint = qobject_to_qint(ret); 8057b7b7d18SPaolo Bonzini if (!qint) { 8067b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 8077b7b7d18SPaolo Bonzini retval = -1; 8087b7b7d18SPaolo Bonzini } else { 8097b7b7d18SPaolo Bonzini retval = qint_get_int(qint); 8107b7b7d18SPaolo Bonzini } 8117b7b7d18SPaolo Bonzini 8127b7b7d18SPaolo Bonzini QDECREF(qint); 8137b7b7d18SPaolo Bonzini return retval; 8147b7b7d18SPaolo Bonzini } 8157b7b7d18SPaolo Bonzini 816b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 817b2cd7deeSPaolo Bonzini const char *name, Error **errp) 818b2cd7deeSPaolo Bonzini { 819b2cd7deeSPaolo Bonzini StringInputVisitor *mi; 820b2cd7deeSPaolo Bonzini mi = string_input_visitor_new(string); 821b2cd7deeSPaolo Bonzini object_property_set(obj, string_input_get_visitor(mi), name, errp); 822b2cd7deeSPaolo Bonzini 823b2cd7deeSPaolo Bonzini string_input_visitor_cleanup(mi); 824b2cd7deeSPaolo Bonzini } 825b2cd7deeSPaolo Bonzini 826b2cd7deeSPaolo Bonzini char *object_property_print(Object *obj, const char *name, 827b2cd7deeSPaolo Bonzini Error **errp) 828b2cd7deeSPaolo Bonzini { 829b2cd7deeSPaolo Bonzini StringOutputVisitor *mo; 830b2cd7deeSPaolo Bonzini char *string; 831b2cd7deeSPaolo Bonzini 832b2cd7deeSPaolo Bonzini mo = string_output_visitor_new(); 833*8185bfc1SPaolo Bonzini object_property_get(obj, string_output_get_visitor(mo), name, errp); 834b2cd7deeSPaolo Bonzini string = string_output_get_string(mo); 835b2cd7deeSPaolo Bonzini string_output_visitor_cleanup(mo); 836b2cd7deeSPaolo Bonzini return string; 837b2cd7deeSPaolo Bonzini } 838b2cd7deeSPaolo Bonzini 83957c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 84057c9fafeSAnthony Liguori { 84157c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 84257c9fafeSAnthony Liguori 84357c9fafeSAnthony Liguori if (prop == NULL) { 84457c9fafeSAnthony Liguori error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 84557c9fafeSAnthony Liguori return NULL; 84657c9fafeSAnthony Liguori } 84757c9fafeSAnthony Liguori 84857c9fafeSAnthony Liguori return prop->type; 84957c9fafeSAnthony Liguori } 85057c9fafeSAnthony Liguori 85157c9fafeSAnthony Liguori Object *object_get_root(void) 85257c9fafeSAnthony Liguori { 8538b45d447SAnthony Liguori static Object *root; 85457c9fafeSAnthony Liguori 8558b45d447SAnthony Liguori if (!root) { 8568b45d447SAnthony Liguori root = object_new("container"); 85757c9fafeSAnthony Liguori } 85857c9fafeSAnthony Liguori 8598b45d447SAnthony Liguori return root; 86057c9fafeSAnthony Liguori } 86157c9fafeSAnthony Liguori 86257c9fafeSAnthony Liguori static void object_get_child_property(Object *obj, Visitor *v, void *opaque, 86357c9fafeSAnthony Liguori const char *name, Error **errp) 86457c9fafeSAnthony Liguori { 86557c9fafeSAnthony Liguori Object *child = opaque; 86657c9fafeSAnthony Liguori gchar *path; 86757c9fafeSAnthony Liguori 86857c9fafeSAnthony Liguori path = object_get_canonical_path(child); 86957c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 87057c9fafeSAnthony Liguori g_free(path); 87157c9fafeSAnthony Liguori } 87257c9fafeSAnthony Liguori 873db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 874db85b575SAnthony Liguori void *opaque) 875db85b575SAnthony Liguori { 876db85b575SAnthony Liguori Object *child = opaque; 877db85b575SAnthony Liguori 878db85b575SAnthony Liguori object_unref(child); 879db85b575SAnthony Liguori } 880db85b575SAnthony Liguori 88157c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 88257c9fafeSAnthony Liguori Object *child, Error **errp) 88357c9fafeSAnthony Liguori { 88457c9fafeSAnthony Liguori gchar *type; 88557c9fafeSAnthony Liguori 886a1e7efdcSPaolo Bonzini /* Registering an interface object in the composition tree will mightily 887a1e7efdcSPaolo Bonzini * confuse object_get_canonical_path (which, on the other hand, knows how 888a1e7efdcSPaolo Bonzini * to get the canonical path of an interface object). 889a1e7efdcSPaolo Bonzini */ 890a1e7efdcSPaolo Bonzini assert(!object_is_type(obj, type_interface)); 891a1e7efdcSPaolo Bonzini 89257c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 89357c9fafeSAnthony Liguori 89457c9fafeSAnthony Liguori object_property_add(obj, name, type, object_get_child_property, 895db85b575SAnthony Liguori NULL, object_finalize_child_property, child, errp); 89657c9fafeSAnthony Liguori 89757c9fafeSAnthony Liguori object_ref(child); 89857c9fafeSAnthony Liguori g_assert(child->parent == NULL); 89957c9fafeSAnthony Liguori child->parent = obj; 90057c9fafeSAnthony Liguori 90157c9fafeSAnthony Liguori g_free(type); 90257c9fafeSAnthony Liguori } 90357c9fafeSAnthony Liguori 90457c9fafeSAnthony Liguori static void object_get_link_property(Object *obj, Visitor *v, void *opaque, 90557c9fafeSAnthony Liguori const char *name, Error **errp) 90657c9fafeSAnthony Liguori { 90757c9fafeSAnthony Liguori Object **child = opaque; 90857c9fafeSAnthony Liguori gchar *path; 90957c9fafeSAnthony Liguori 91057c9fafeSAnthony Liguori if (*child) { 91157c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 91257c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 91357c9fafeSAnthony Liguori g_free(path); 91457c9fafeSAnthony Liguori } else { 91557c9fafeSAnthony Liguori path = (gchar *)""; 91657c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 91757c9fafeSAnthony Liguori } 91857c9fafeSAnthony Liguori } 91957c9fafeSAnthony Liguori 92057c9fafeSAnthony Liguori static void object_set_link_property(Object *obj, Visitor *v, void *opaque, 92157c9fafeSAnthony Liguori const char *name, Error **errp) 92257c9fafeSAnthony Liguori { 92357c9fafeSAnthony Liguori Object **child = opaque; 924f0cdc966SAlexander Barabash Object *old_target; 92557c9fafeSAnthony Liguori bool ambiguous = false; 92657c9fafeSAnthony Liguori const char *type; 92757c9fafeSAnthony Liguori char *path; 92811e35bfdSPaolo Bonzini gchar *target_type; 92957c9fafeSAnthony Liguori 93057c9fafeSAnthony Liguori type = object_property_get_type(obj, name, NULL); 93157c9fafeSAnthony Liguori 93257c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 93357c9fafeSAnthony Liguori 934f0cdc966SAlexander Barabash old_target = *child; 93511e35bfdSPaolo Bonzini *child = NULL; 93657c9fafeSAnthony Liguori 93757c9fafeSAnthony Liguori if (strcmp(path, "") != 0) { 93857c9fafeSAnthony Liguori Object *target; 93957c9fafeSAnthony Liguori 9408f770d39SPaolo Bonzini /* Go from link<FOO> to FOO. */ 94111e35bfdSPaolo Bonzini target_type = g_strndup(&type[5], strlen(type) - 6); 94211e35bfdSPaolo Bonzini target = object_resolve_path_type(path, target_type, &ambiguous); 94311e35bfdSPaolo Bonzini 94411e35bfdSPaolo Bonzini if (ambiguous) { 94511e35bfdSPaolo Bonzini error_set(errp, QERR_AMBIGUOUS_PATH, path); 94611e35bfdSPaolo Bonzini } else if (target) { 94757c9fafeSAnthony Liguori object_ref(target); 948fe40e627SAnthony Liguori *child = target; 94957c9fafeSAnthony Liguori } else { 95011e35bfdSPaolo Bonzini target = object_resolve_path(path, &ambiguous); 95111e35bfdSPaolo Bonzini if (target || ambiguous) { 95211e35bfdSPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 95357c9fafeSAnthony Liguori } else { 95457c9fafeSAnthony Liguori error_set(errp, QERR_DEVICE_NOT_FOUND, path); 95557c9fafeSAnthony Liguori } 95611e35bfdSPaolo Bonzini } 95711e35bfdSPaolo Bonzini g_free(target_type); 95857c9fafeSAnthony Liguori } 95957c9fafeSAnthony Liguori 96057c9fafeSAnthony Liguori g_free(path); 961f0cdc966SAlexander Barabash 962f0cdc966SAlexander Barabash if (old_target != NULL) { 963f0cdc966SAlexander Barabash object_unref(old_target); 964f0cdc966SAlexander Barabash } 96557c9fafeSAnthony Liguori } 96657c9fafeSAnthony Liguori 96757c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 96857c9fafeSAnthony Liguori const char *type, Object **child, 96957c9fafeSAnthony Liguori Error **errp) 97057c9fafeSAnthony Liguori { 97157c9fafeSAnthony Liguori gchar *full_type; 97257c9fafeSAnthony Liguori 97357c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 97457c9fafeSAnthony Liguori 97557c9fafeSAnthony Liguori object_property_add(obj, name, full_type, 97657c9fafeSAnthony Liguori object_get_link_property, 97757c9fafeSAnthony Liguori object_set_link_property, 97857c9fafeSAnthony Liguori NULL, child, errp); 97957c9fafeSAnthony Liguori 98057c9fafeSAnthony Liguori g_free(full_type); 98157c9fafeSAnthony Liguori } 98257c9fafeSAnthony Liguori 98357c9fafeSAnthony Liguori gchar *object_get_canonical_path(Object *obj) 98457c9fafeSAnthony Liguori { 98557c9fafeSAnthony Liguori Object *root = object_get_root(); 98657c9fafeSAnthony Liguori char *newpath = NULL, *path = NULL; 98757c9fafeSAnthony Liguori 988a1e7efdcSPaolo Bonzini if (object_is_type(obj, type_interface)) { 989a1e7efdcSPaolo Bonzini obj = INTERFACE(obj)->obj; 990a1e7efdcSPaolo Bonzini } 991a1e7efdcSPaolo Bonzini 99257c9fafeSAnthony Liguori while (obj != root) { 99357c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 99457c9fafeSAnthony Liguori 99557c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 99657c9fafeSAnthony Liguori 99757c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->parent->properties, node) { 99857c9fafeSAnthony Liguori if (!strstart(prop->type, "child<", NULL)) { 99957c9fafeSAnthony Liguori continue; 100057c9fafeSAnthony Liguori } 100157c9fafeSAnthony Liguori 100257c9fafeSAnthony Liguori if (prop->opaque == obj) { 100357c9fafeSAnthony Liguori if (path) { 100457c9fafeSAnthony Liguori newpath = g_strdup_printf("%s/%s", prop->name, path); 100557c9fafeSAnthony Liguori g_free(path); 100657c9fafeSAnthony Liguori path = newpath; 100757c9fafeSAnthony Liguori } else { 100857c9fafeSAnthony Liguori path = g_strdup(prop->name); 100957c9fafeSAnthony Liguori } 101057c9fafeSAnthony Liguori break; 101157c9fafeSAnthony Liguori } 101257c9fafeSAnthony Liguori } 101357c9fafeSAnthony Liguori 101457c9fafeSAnthony Liguori g_assert(prop != NULL); 101557c9fafeSAnthony Liguori 101657c9fafeSAnthony Liguori obj = obj->parent; 101757c9fafeSAnthony Liguori } 101857c9fafeSAnthony Liguori 101957c9fafeSAnthony Liguori newpath = g_strdup_printf("/%s", path); 102057c9fafeSAnthony Liguori g_free(path); 102157c9fafeSAnthony Liguori 102257c9fafeSAnthony Liguori return newpath; 102357c9fafeSAnthony Liguori } 102457c9fafeSAnthony Liguori 1025a612b2a6SPaolo Bonzini Object *object_resolve_path_component(Object *parent, gchar *part) 1026a612b2a6SPaolo Bonzini { 1027a612b2a6SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part); 1028a612b2a6SPaolo Bonzini if (prop == NULL) { 1029a612b2a6SPaolo Bonzini return NULL; 1030a612b2a6SPaolo Bonzini } 1031a612b2a6SPaolo Bonzini 1032a612b2a6SPaolo Bonzini if (strstart(prop->type, "link<", NULL)) { 1033a612b2a6SPaolo Bonzini return *(Object **)prop->opaque; 1034a612b2a6SPaolo Bonzini } else if (strstart(prop->type, "child<", NULL)) { 1035a612b2a6SPaolo Bonzini return prop->opaque; 1036a612b2a6SPaolo Bonzini } else { 1037a612b2a6SPaolo Bonzini return NULL; 1038a612b2a6SPaolo Bonzini } 1039a612b2a6SPaolo Bonzini } 1040a612b2a6SPaolo Bonzini 104157c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 104257c9fafeSAnthony Liguori gchar **parts, 104302fe2db6SPaolo Bonzini const char *typename, 104457c9fafeSAnthony Liguori int index) 104557c9fafeSAnthony Liguori { 104657c9fafeSAnthony Liguori Object *child; 104757c9fafeSAnthony Liguori 104857c9fafeSAnthony Liguori if (parts[index] == NULL) { 104902fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 105057c9fafeSAnthony Liguori } 105157c9fafeSAnthony Liguori 105257c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 105302fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 105457c9fafeSAnthony Liguori } 105557c9fafeSAnthony Liguori 1056a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 105757c9fafeSAnthony Liguori if (!child) { 105857c9fafeSAnthony Liguori return NULL; 105957c9fafeSAnthony Liguori } 106057c9fafeSAnthony Liguori 106102fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 106257c9fafeSAnthony Liguori } 106357c9fafeSAnthony Liguori 106457c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 106557c9fafeSAnthony Liguori gchar **parts, 106602fe2db6SPaolo Bonzini const char *typename, 106757c9fafeSAnthony Liguori bool *ambiguous) 106857c9fafeSAnthony Liguori { 106957c9fafeSAnthony Liguori Object *obj; 107057c9fafeSAnthony Liguori ObjectProperty *prop; 107157c9fafeSAnthony Liguori 107202fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 107357c9fafeSAnthony Liguori 107457c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &parent->properties, node) { 107557c9fafeSAnthony Liguori Object *found; 107657c9fafeSAnthony Liguori 107757c9fafeSAnthony Liguori if (!strstart(prop->type, "child<", NULL)) { 107857c9fafeSAnthony Liguori continue; 107957c9fafeSAnthony Liguori } 108057c9fafeSAnthony Liguori 108102fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 108202fe2db6SPaolo Bonzini typename, ambiguous); 108357c9fafeSAnthony Liguori if (found) { 108457c9fafeSAnthony Liguori if (obj) { 108557c9fafeSAnthony Liguori if (ambiguous) { 108657c9fafeSAnthony Liguori *ambiguous = true; 108757c9fafeSAnthony Liguori } 108857c9fafeSAnthony Liguori return NULL; 108957c9fafeSAnthony Liguori } 109057c9fafeSAnthony Liguori obj = found; 109157c9fafeSAnthony Liguori } 109257c9fafeSAnthony Liguori 109357c9fafeSAnthony Liguori if (ambiguous && *ambiguous) { 109457c9fafeSAnthony Liguori return NULL; 109557c9fafeSAnthony Liguori } 109657c9fafeSAnthony Liguori } 109757c9fafeSAnthony Liguori 109857c9fafeSAnthony Liguori return obj; 109957c9fafeSAnthony Liguori } 110057c9fafeSAnthony Liguori 110102fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 110202fe2db6SPaolo Bonzini bool *ambiguous) 110357c9fafeSAnthony Liguori { 110457c9fafeSAnthony Liguori bool partial_path = true; 110557c9fafeSAnthony Liguori Object *obj; 110657c9fafeSAnthony Liguori gchar **parts; 110757c9fafeSAnthony Liguori 110857c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 110957c9fafeSAnthony Liguori if (parts == NULL || parts[0] == NULL) { 111057c9fafeSAnthony Liguori g_strfreev(parts); 111157c9fafeSAnthony Liguori return object_get_root(); 111257c9fafeSAnthony Liguori } 111357c9fafeSAnthony Liguori 111457c9fafeSAnthony Liguori if (strcmp(parts[0], "") == 0) { 111557c9fafeSAnthony Liguori partial_path = false; 111657c9fafeSAnthony Liguori } 111757c9fafeSAnthony Liguori 111857c9fafeSAnthony Liguori if (partial_path) { 111957c9fafeSAnthony Liguori if (ambiguous) { 112057c9fafeSAnthony Liguori *ambiguous = false; 112157c9fafeSAnthony Liguori } 112202fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 112302fe2db6SPaolo Bonzini typename, ambiguous); 112457c9fafeSAnthony Liguori } else { 112502fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 112657c9fafeSAnthony Liguori } 112757c9fafeSAnthony Liguori 112857c9fafeSAnthony Liguori g_strfreev(parts); 112957c9fafeSAnthony Liguori 113057c9fafeSAnthony Liguori return obj; 113157c9fafeSAnthony Liguori } 113257c9fafeSAnthony Liguori 113302fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 113402fe2db6SPaolo Bonzini { 113502fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 113602fe2db6SPaolo Bonzini } 113702fe2db6SPaolo Bonzini 113857c9fafeSAnthony Liguori typedef struct StringProperty 113957c9fafeSAnthony Liguori { 114057c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 114157c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 114257c9fafeSAnthony Liguori } StringProperty; 114357c9fafeSAnthony Liguori 11447b7b7d18SPaolo Bonzini static void property_get_str(Object *obj, Visitor *v, void *opaque, 114557c9fafeSAnthony Liguori const char *name, Error **errp) 114657c9fafeSAnthony Liguori { 114757c9fafeSAnthony Liguori StringProperty *prop = opaque; 114857c9fafeSAnthony Liguori char *value; 114957c9fafeSAnthony Liguori 115057c9fafeSAnthony Liguori value = prop->get(obj, errp); 115157c9fafeSAnthony Liguori if (value) { 115257c9fafeSAnthony Liguori visit_type_str(v, &value, name, errp); 115357c9fafeSAnthony Liguori g_free(value); 115457c9fafeSAnthony Liguori } 115557c9fafeSAnthony Liguori } 115657c9fafeSAnthony Liguori 11577b7b7d18SPaolo Bonzini static void property_set_str(Object *obj, Visitor *v, void *opaque, 115857c9fafeSAnthony Liguori const char *name, Error **errp) 115957c9fafeSAnthony Liguori { 116057c9fafeSAnthony Liguori StringProperty *prop = opaque; 116157c9fafeSAnthony Liguori char *value; 116257c9fafeSAnthony Liguori Error *local_err = NULL; 116357c9fafeSAnthony Liguori 116457c9fafeSAnthony Liguori visit_type_str(v, &value, name, &local_err); 116557c9fafeSAnthony Liguori if (local_err) { 116657c9fafeSAnthony Liguori error_propagate(errp, local_err); 116757c9fafeSAnthony Liguori return; 116857c9fafeSAnthony Liguori } 116957c9fafeSAnthony Liguori 117057c9fafeSAnthony Liguori prop->set(obj, value, errp); 117157c9fafeSAnthony Liguori g_free(value); 117257c9fafeSAnthony Liguori } 117357c9fafeSAnthony Liguori 11747b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 117557c9fafeSAnthony Liguori void *opaque) 117657c9fafeSAnthony Liguori { 117757c9fafeSAnthony Liguori StringProperty *prop = opaque; 117857c9fafeSAnthony Liguori g_free(prop); 117957c9fafeSAnthony Liguori } 118057c9fafeSAnthony Liguori 118157c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 118257c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 118357c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 118457c9fafeSAnthony Liguori Error **errp) 118557c9fafeSAnthony Liguori { 118657c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 118757c9fafeSAnthony Liguori 118857c9fafeSAnthony Liguori prop->get = get; 118957c9fafeSAnthony Liguori prop->set = set; 119057c9fafeSAnthony Liguori 119157c9fafeSAnthony Liguori object_property_add(obj, name, "string", 11927b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 11937b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 11947b7b7d18SPaolo Bonzini property_release_str, 119557c9fafeSAnthony Liguori prop, errp); 119657c9fafeSAnthony Liguori } 1197