12f28d2ffSAnthony Liguori /* 22f28d2ffSAnthony Liguori * QEMU Object Model 32f28d2ffSAnthony Liguori * 42f28d2ffSAnthony Liguori * Copyright IBM, Corp. 2011 52f28d2ffSAnthony Liguori * 62f28d2ffSAnthony Liguori * Authors: 72f28d2ffSAnthony Liguori * Anthony Liguori <aliguori@us.ibm.com> 82f28d2ffSAnthony Liguori * 92f28d2ffSAnthony Liguori * This work is licensed under the terms of the GNU GPL, version 2 or later. 102f28d2ffSAnthony Liguori * See the COPYING file in the top-level directory. 112f28d2ffSAnthony Liguori */ 122f28d2ffSAnthony Liguori 1314cccb61SPaolo Bonzini #include "qom/object.h" 142f28d2ffSAnthony Liguori #include "qemu-common.h" 157b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 16b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h" 17b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h" 187b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 19fa131d94SPaolo Bonzini #include "trace.h" 202f28d2ffSAnthony Liguori 217b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency 227b7b7d18SPaolo Bonzini * of the QOM core on QObject? */ 2314cccb61SPaolo Bonzini #include "qom/qom-qobject.h" 247b1b5d19SPaolo Bonzini #include "qapi/qmp/qobject.h" 257b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h" 267b1b5d19SPaolo Bonzini #include "qapi/qmp/qint.h" 277b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h" 287b7b7d18SPaolo Bonzini 292f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 302f28d2ffSAnthony Liguori 312f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 322f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 332f28d2ffSAnthony Liguori 342f28d2ffSAnthony Liguori struct InterfaceImpl 352f28d2ffSAnthony Liguori { 3633e95c63SAnthony Liguori const char *typename; 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); 483b50e311SPaolo Bonzini void (*class_base_init)(ObjectClass *klass, void *data); 492f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 502f28d2ffSAnthony Liguori 512f28d2ffSAnthony Liguori void *class_data; 522f28d2ffSAnthony Liguori 532f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 542f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 552f28d2ffSAnthony Liguori 562f28d2ffSAnthony Liguori bool abstract; 572f28d2ffSAnthony Liguori 582f28d2ffSAnthony Liguori const char *parent; 592f28d2ffSAnthony Liguori TypeImpl *parent_type; 602f28d2ffSAnthony Liguori 612f28d2ffSAnthony Liguori ObjectClass *class; 622f28d2ffSAnthony Liguori 632f28d2ffSAnthony Liguori int num_interfaces; 642f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 652f28d2ffSAnthony Liguori }; 662f28d2ffSAnthony Liguori 679970bd88SPaolo Bonzini static Type type_interface; 689970bd88SPaolo Bonzini 692f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 702f28d2ffSAnthony Liguori { 712f28d2ffSAnthony Liguori static GHashTable *type_table; 722f28d2ffSAnthony Liguori 732f28d2ffSAnthony Liguori if (type_table == NULL) { 742f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 752f28d2ffSAnthony Liguori } 762f28d2ffSAnthony Liguori 772f28d2ffSAnthony Liguori return type_table; 782f28d2ffSAnthony Liguori } 792f28d2ffSAnthony Liguori 802f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 812f28d2ffSAnthony Liguori { 822f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 832f28d2ffSAnthony Liguori } 842f28d2ffSAnthony Liguori 852f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 862f28d2ffSAnthony Liguori { 872f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 882f28d2ffSAnthony Liguori } 892f28d2ffSAnthony Liguori 90049cb3cfSPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info) 912f28d2ffSAnthony Liguori { 922f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 9333e95c63SAnthony Liguori int i; 942f28d2ffSAnthony Liguori 952f28d2ffSAnthony Liguori g_assert(info->name != NULL); 962f28d2ffSAnthony Liguori 9773093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 9873093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 9973093354SAnthony Liguori abort(); 10073093354SAnthony Liguori } 10173093354SAnthony Liguori 1022f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1032f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1042f28d2ffSAnthony Liguori 1052f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1062f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1072f28d2ffSAnthony Liguori 1082f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1093b50e311SPaolo Bonzini ti->class_base_init = info->class_base_init; 1102f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1112f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1122f28d2ffSAnthony Liguori 1132f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1142f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1152f28d2ffSAnthony Liguori 1162f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1172f28d2ffSAnthony Liguori 11833e95c63SAnthony Liguori for (i = 0; info->interfaces && info->interfaces[i].type; i++) { 11933e95c63SAnthony Liguori ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); 1202f28d2ffSAnthony Liguori } 12133e95c63SAnthony Liguori ti->num_interfaces = i; 1222f28d2ffSAnthony Liguori 1232f28d2ffSAnthony Liguori type_table_add(ti); 1242f28d2ffSAnthony Liguori 1252f28d2ffSAnthony Liguori return ti; 1262f28d2ffSAnthony Liguori } 1272f28d2ffSAnthony Liguori 128049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info) 129049cb3cfSPaolo Bonzini { 130049cb3cfSPaolo Bonzini assert(info->parent); 131049cb3cfSPaolo Bonzini return type_register_internal(info); 132049cb3cfSPaolo Bonzini } 133049cb3cfSPaolo Bonzini 1342f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1352f28d2ffSAnthony Liguori { 1362f28d2ffSAnthony Liguori return type_register(info); 1372f28d2ffSAnthony Liguori } 1382f28d2ffSAnthony Liguori 1392f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1402f28d2ffSAnthony Liguori { 1412f28d2ffSAnthony Liguori if (name == NULL) { 1422f28d2ffSAnthony Liguori return NULL; 1432f28d2ffSAnthony Liguori } 1442f28d2ffSAnthony Liguori 1452f28d2ffSAnthony Liguori return type_table_lookup(name); 1462f28d2ffSAnthony Liguori } 1472f28d2ffSAnthony Liguori 1482f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1492f28d2ffSAnthony Liguori { 1502f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1512f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1522f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1532f28d2ffSAnthony Liguori } 1542f28d2ffSAnthony Liguori 1552f28d2ffSAnthony Liguori return type->parent_type; 1562f28d2ffSAnthony Liguori } 1572f28d2ffSAnthony Liguori 1582f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1592f28d2ffSAnthony Liguori { 1602f28d2ffSAnthony Liguori return (type->parent != NULL); 1612f28d2ffSAnthony Liguori } 1622f28d2ffSAnthony Liguori 1632f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1642f28d2ffSAnthony Liguori { 1652f28d2ffSAnthony Liguori if (ti->class_size) { 1662f28d2ffSAnthony Liguori return ti->class_size; 1672f28d2ffSAnthony Liguori } 1682f28d2ffSAnthony Liguori 1692f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1702f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1712f28d2ffSAnthony Liguori } 1722f28d2ffSAnthony Liguori 1732f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1742f28d2ffSAnthony Liguori } 1752f28d2ffSAnthony Liguori 176aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 177aca59af6SIgor Mitsyanko { 178aca59af6SIgor Mitsyanko if (ti->instance_size) { 179aca59af6SIgor Mitsyanko return ti->instance_size; 180aca59af6SIgor Mitsyanko } 181aca59af6SIgor Mitsyanko 182aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 183aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 184aca59af6SIgor Mitsyanko } 185aca59af6SIgor Mitsyanko 186aca59af6SIgor Mitsyanko return 0; 187aca59af6SIgor Mitsyanko } 188aca59af6SIgor Mitsyanko 18933e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 1902f28d2ffSAnthony Liguori { 19133e95c63SAnthony Liguori assert(target_type); 1922f28d2ffSAnthony Liguori 19333e95c63SAnthony Liguori /* Check if typename is a direct ancestor of type */ 19433e95c63SAnthony Liguori while (type) { 19533e95c63SAnthony Liguori if (type == target_type) { 19633e95c63SAnthony Liguori return true; 19733e95c63SAnthony Liguori } 19833e95c63SAnthony Liguori 19933e95c63SAnthony Liguori type = type_get_parent(type); 20033e95c63SAnthony Liguori } 20133e95c63SAnthony Liguori 20233e95c63SAnthony Liguori return false; 20333e95c63SAnthony Liguori } 20433e95c63SAnthony Liguori 20533e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti); 20633e95c63SAnthony Liguori 20733e95c63SAnthony Liguori static void type_initialize_interface(TypeImpl *ti, const char *parent) 20833e95c63SAnthony Liguori { 20933e95c63SAnthony Liguori InterfaceClass *new_iface; 21033e95c63SAnthony Liguori TypeInfo info = { }; 21133e95c63SAnthony Liguori TypeImpl *iface_impl; 21233e95c63SAnthony Liguori 21333e95c63SAnthony Liguori info.parent = parent; 21433e95c63SAnthony Liguori info.name = g_strdup_printf("%s::%s", ti->name, info.parent); 21533e95c63SAnthony Liguori info.abstract = true; 21633e95c63SAnthony Liguori 21733e95c63SAnthony Liguori iface_impl = type_register(&info); 21833e95c63SAnthony Liguori type_initialize(iface_impl); 21933e95c63SAnthony Liguori g_free((char *)info.name); 22033e95c63SAnthony Liguori 22133e95c63SAnthony Liguori new_iface = (InterfaceClass *)iface_impl->class; 22233e95c63SAnthony Liguori new_iface->concrete_class = ti->class; 22333e95c63SAnthony Liguori 22433e95c63SAnthony Liguori ti->class->interfaces = g_slist_append(ti->class->interfaces, 22533e95c63SAnthony Liguori iface_impl->class); 2262f28d2ffSAnthony Liguori } 2272f28d2ffSAnthony Liguori 228ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2292f28d2ffSAnthony Liguori { 230745549c8SPaolo Bonzini TypeImpl *parent; 2312f28d2ffSAnthony Liguori 2322f28d2ffSAnthony Liguori if (ti->class) { 2332f28d2ffSAnthony Liguori return; 2342f28d2ffSAnthony Liguori } 2352f28d2ffSAnthony Liguori 2362f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 237aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2382f28d2ffSAnthony Liguori 2392f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 2402f28d2ffSAnthony Liguori 241745549c8SPaolo Bonzini parent = type_get_parent(ti); 242745549c8SPaolo Bonzini if (parent) { 243ac451033SIgor Mitsyanko type_initialize(parent); 24433e95c63SAnthony Liguori GSList *e; 24533e95c63SAnthony Liguori int i; 2462f28d2ffSAnthony Liguori 2472f28d2ffSAnthony Liguori g_assert(parent->class_size <= ti->class_size); 248745549c8SPaolo Bonzini memcpy(ti->class, parent->class, parent->class_size); 2493e407de4SPeter Crosthwaite ti->class->interfaces = NULL; 25033e95c63SAnthony Liguori 25133e95c63SAnthony Liguori for (e = parent->class->interfaces; e; e = e->next) { 25233e95c63SAnthony Liguori ObjectClass *iface = e->data; 25333e95c63SAnthony Liguori type_initialize_interface(ti, object_class_get_name(iface)); 25433e95c63SAnthony Liguori } 25533e95c63SAnthony Liguori 25633e95c63SAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 25733e95c63SAnthony Liguori TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); 25833e95c63SAnthony Liguori for (e = ti->class->interfaces; e; e = e->next) { 25933e95c63SAnthony Liguori TypeImpl *target_type = OBJECT_CLASS(e->data)->type; 26033e95c63SAnthony Liguori 26133e95c63SAnthony Liguori if (type_is_ancestor(target_type, t)) { 26233e95c63SAnthony Liguori break; 26333e95c63SAnthony Liguori } 26433e95c63SAnthony Liguori } 26533e95c63SAnthony Liguori 26633e95c63SAnthony Liguori if (e) { 26733e95c63SAnthony Liguori continue; 26833e95c63SAnthony Liguori } 26933e95c63SAnthony Liguori 27033e95c63SAnthony Liguori type_initialize_interface(ti, ti->interfaces[i].typename); 27133e95c63SAnthony Liguori } 272745549c8SPaolo Bonzini } 2732f28d2ffSAnthony Liguori 274745549c8SPaolo Bonzini ti->class->type = ti; 2753b50e311SPaolo Bonzini 2763b50e311SPaolo Bonzini while (parent) { 2773b50e311SPaolo Bonzini if (parent->class_base_init) { 2783b50e311SPaolo Bonzini parent->class_base_init(ti->class, ti->class_data); 2793b50e311SPaolo Bonzini } 2803b50e311SPaolo Bonzini parent = type_get_parent(parent); 2813b50e311SPaolo Bonzini } 2822f28d2ffSAnthony Liguori 2832f28d2ffSAnthony Liguori if (ti->class_init) { 2842f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 2852f28d2ffSAnthony Liguori } 2862f28d2ffSAnthony Liguori 2872f28d2ffSAnthony Liguori 2882f28d2ffSAnthony Liguori } 2892f28d2ffSAnthony Liguori 2902f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 2912f28d2ffSAnthony Liguori { 2922f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 2932f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 2942f28d2ffSAnthony Liguori } 2952f28d2ffSAnthony Liguori 2962f28d2ffSAnthony Liguori if (ti->instance_init) { 2972f28d2ffSAnthony Liguori ti->instance_init(obj); 2982f28d2ffSAnthony Liguori } 2992f28d2ffSAnthony Liguori } 3002f28d2ffSAnthony Liguori 3012f28d2ffSAnthony Liguori void object_initialize_with_type(void *data, TypeImpl *type) 3022f28d2ffSAnthony Liguori { 3032f28d2ffSAnthony Liguori Object *obj = data; 3042f28d2ffSAnthony Liguori 3052f28d2ffSAnthony Liguori g_assert(type != NULL); 306ac451033SIgor Mitsyanko type_initialize(type); 307aca59af6SIgor Mitsyanko 308aca59af6SIgor Mitsyanko g_assert(type->instance_size >= sizeof(Object)); 3092f28d2ffSAnthony Liguori g_assert(type->abstract == false); 3102f28d2ffSAnthony Liguori 3112f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 3122f28d2ffSAnthony Liguori obj->class = type->class; 313764b6312SPaolo Bonzini object_ref(obj); 31457c9fafeSAnthony Liguori QTAILQ_INIT(&obj->properties); 3152f28d2ffSAnthony Liguori object_init_with_type(obj, type); 3162f28d2ffSAnthony Liguori } 3172f28d2ffSAnthony Liguori 3182f28d2ffSAnthony Liguori void object_initialize(void *data, const char *typename) 3192f28d2ffSAnthony Liguori { 3202f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 3212f28d2ffSAnthony Liguori 3222f28d2ffSAnthony Liguori object_initialize_with_type(data, type); 3232f28d2ffSAnthony Liguori } 3242f28d2ffSAnthony Liguori 3255d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop) 3265d9d3f47SAndreas Färber { 3275d9d3f47SAndreas Färber return strstart(prop->type, "child<", NULL); 3285d9d3f47SAndreas Färber } 3295d9d3f47SAndreas Färber 3305d9d3f47SAndreas Färber static inline bool object_property_is_link(ObjectProperty *prop) 3315d9d3f47SAndreas Färber { 3325d9d3f47SAndreas Färber return strstart(prop->type, "link<", NULL); 3335d9d3f47SAndreas Färber } 3345d9d3f47SAndreas Färber 33557c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 33657c9fafeSAnthony Liguori { 33757c9fafeSAnthony Liguori while (!QTAILQ_EMPTY(&obj->properties)) { 33857c9fafeSAnthony Liguori ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); 33957c9fafeSAnthony Liguori 34057c9fafeSAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 34157c9fafeSAnthony Liguori 34257c9fafeSAnthony Liguori if (prop->release) { 34357c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 34457c9fafeSAnthony Liguori } 34557c9fafeSAnthony Liguori 34657c9fafeSAnthony Liguori g_free(prop->name); 34757c9fafeSAnthony Liguori g_free(prop->type); 34857c9fafeSAnthony Liguori g_free(prop); 34957c9fafeSAnthony Liguori } 35057c9fafeSAnthony Liguori } 35157c9fafeSAnthony Liguori 35257c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 35357c9fafeSAnthony Liguori { 35457c9fafeSAnthony Liguori ObjectProperty *prop; 35557c9fafeSAnthony Liguori 35657c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 3575d9d3f47SAndreas Färber if (object_property_is_child(prop) && prop->opaque == child) { 35857c9fafeSAnthony Liguori object_property_del(obj, prop->name, errp); 3596c1fdcf9SPaolo Bonzini break; 36057c9fafeSAnthony Liguori } 36157c9fafeSAnthony Liguori } 36257c9fafeSAnthony Liguori } 36357c9fafeSAnthony Liguori 36457c9fafeSAnthony Liguori void object_unparent(Object *obj) 36557c9fafeSAnthony Liguori { 366e0a83fc2SPaolo Bonzini if (!obj->parent) { 367e0a83fc2SPaolo Bonzini return; 368e0a83fc2SPaolo Bonzini } 369e0a83fc2SPaolo Bonzini 37052e636cdSPaolo Bonzini object_ref(obj); 371667d22d1SPaolo Bonzini if (obj->class->unparent) { 372667d22d1SPaolo Bonzini (obj->class->unparent)(obj); 373667d22d1SPaolo Bonzini } 374e998fa8dSMichael S. Tsirkin if (obj->parent) { 375e998fa8dSMichael S. Tsirkin object_property_del_child(obj->parent, obj, NULL); 376e998fa8dSMichael S. Tsirkin } 37752e636cdSPaolo Bonzini object_unref(obj); 37857c9fafeSAnthony Liguori } 37957c9fafeSAnthony Liguori 3802f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 3812f28d2ffSAnthony Liguori { 3822f28d2ffSAnthony Liguori if (type->instance_finalize) { 3832f28d2ffSAnthony Liguori type->instance_finalize(obj); 3842f28d2ffSAnthony Liguori } 3852f28d2ffSAnthony Liguori 3862f28d2ffSAnthony Liguori if (type_has_parent(type)) { 3872f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 3882f28d2ffSAnthony Liguori } 3892f28d2ffSAnthony Liguori } 3902f28d2ffSAnthony Liguori 391339c2708SPaolo Bonzini static void object_finalize(void *data) 3922f28d2ffSAnthony Liguori { 3932f28d2ffSAnthony Liguori Object *obj = data; 3942f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 3952f28d2ffSAnthony Liguori 3962f28d2ffSAnthony Liguori object_deinit(obj, ti); 39757c9fafeSAnthony Liguori object_property_del_all(obj); 398db85b575SAnthony Liguori 399db85b575SAnthony Liguori g_assert(obj->ref == 0); 400fde9bf44SPaolo Bonzini if (obj->free) { 401fde9bf44SPaolo Bonzini obj->free(obj); 402fde9bf44SPaolo Bonzini } 4032f28d2ffSAnthony Liguori } 4042f28d2ffSAnthony Liguori 4052f28d2ffSAnthony Liguori Object *object_new_with_type(Type type) 4062f28d2ffSAnthony Liguori { 4072f28d2ffSAnthony Liguori Object *obj; 4082f28d2ffSAnthony Liguori 4092f28d2ffSAnthony Liguori g_assert(type != NULL); 410ac451033SIgor Mitsyanko type_initialize(type); 4112f28d2ffSAnthony Liguori 4122f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 4132f28d2ffSAnthony Liguori object_initialize_with_type(obj, type); 414fde9bf44SPaolo Bonzini obj->free = g_free; 4152f28d2ffSAnthony Liguori 4162f28d2ffSAnthony Liguori return obj; 4172f28d2ffSAnthony Liguori } 4182f28d2ffSAnthony Liguori 4192f28d2ffSAnthony Liguori Object *object_new(const char *typename) 4202f28d2ffSAnthony Liguori { 4212f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 4222f28d2ffSAnthony Liguori 4232f28d2ffSAnthony Liguori return object_new_with_type(ti); 4242f28d2ffSAnthony Liguori } 4252f28d2ffSAnthony Liguori 4262f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 4272f28d2ffSAnthony Liguori { 428b7f43fe4SPaolo Bonzini if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { 429acc4af3fSPaolo Bonzini return obj; 430acc4af3fSPaolo Bonzini } 431acc4af3fSPaolo Bonzini 4322f28d2ffSAnthony Liguori return NULL; 4332f28d2ffSAnthony Liguori } 4342f28d2ffSAnthony Liguori 435be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename, 436be17f18bSPaolo Bonzini const char *file, int line, const char *func) 4372f28d2ffSAnthony Liguori { 438fa131d94SPaolo Bonzini trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", 439fa131d94SPaolo Bonzini typename, file, line, func); 440fa131d94SPaolo Bonzini 441*3556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG 442*3556c233SPaolo Bonzini Object *inst = object_dynamic_cast(obj, typename); 4432f28d2ffSAnthony Liguori 444b7f43fe4SPaolo Bonzini if (!inst && obj) { 445be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 446be17f18bSPaolo Bonzini file, line, func, obj, typename); 4472f28d2ffSAnthony Liguori abort(); 4482f28d2ffSAnthony Liguori } 4492f28d2ffSAnthony Liguori 450*3556c233SPaolo Bonzini assert(obj == inst); 451*3556c233SPaolo Bonzini #endif 452*3556c233SPaolo Bonzini return obj; 4532f28d2ffSAnthony Liguori } 4542f28d2ffSAnthony Liguori 4552f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 4562f28d2ffSAnthony Liguori const char *typename) 4572f28d2ffSAnthony Liguori { 45833e95c63SAnthony Liguori ObjectClass *ret = NULL; 459bf0fda34SPaolo Bonzini TypeImpl *target_type; 460bf0fda34SPaolo Bonzini TypeImpl *type; 4612f28d2ffSAnthony Liguori 462bf0fda34SPaolo Bonzini if (!class) { 463bf0fda34SPaolo Bonzini return NULL; 464bf0fda34SPaolo Bonzini } 465bf0fda34SPaolo Bonzini 466793c96b5SPaolo Bonzini /* A simple fast path that can trigger a lot for leaf classes. */ 467bf0fda34SPaolo Bonzini type = class->type; 468793c96b5SPaolo Bonzini if (type->name == typename) { 469793c96b5SPaolo Bonzini return class; 470793c96b5SPaolo Bonzini } 471793c96b5SPaolo Bonzini 472bf0fda34SPaolo Bonzini target_type = type_get_by_name(typename); 4739ab880b3SAlexander Graf if (!target_type) { 4749ab880b3SAlexander Graf /* target class type unknown, so fail the cast */ 4759ab880b3SAlexander Graf return NULL; 4769ab880b3SAlexander Graf } 4779ab880b3SAlexander Graf 47800e2ceaeSPeter Crosthwaite if (type->class->interfaces && 47900e2ceaeSPeter Crosthwaite type_is_ancestor(target_type, type_interface)) { 48033e95c63SAnthony Liguori int found = 0; 48133e95c63SAnthony Liguori GSList *i; 48233e95c63SAnthony Liguori 48333e95c63SAnthony Liguori for (i = class->interfaces; i; i = i->next) { 48433e95c63SAnthony Liguori ObjectClass *target_class = i->data; 48533e95c63SAnthony Liguori 48633e95c63SAnthony Liguori if (type_is_ancestor(target_class->type, target_type)) { 48733e95c63SAnthony Liguori ret = target_class; 48833e95c63SAnthony Liguori found++; 48933e95c63SAnthony Liguori } 4902f28d2ffSAnthony Liguori } 4912f28d2ffSAnthony Liguori 49233e95c63SAnthony Liguori /* The match was ambiguous, don't allow a cast */ 49333e95c63SAnthony Liguori if (found > 1) { 49433e95c63SAnthony Liguori ret = NULL; 49533e95c63SAnthony Liguori } 49633e95c63SAnthony Liguori } else if (type_is_ancestor(type, target_type)) { 49733e95c63SAnthony Liguori ret = class; 4982f28d2ffSAnthony Liguori } 4992f28d2ffSAnthony Liguori 50033e95c63SAnthony Liguori return ret; 5012f28d2ffSAnthony Liguori } 5022f28d2ffSAnthony Liguori 5032f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 504be17f18bSPaolo Bonzini const char *typename, 505be17f18bSPaolo Bonzini const char *file, int line, 506be17f18bSPaolo Bonzini const char *func) 5072f28d2ffSAnthony Liguori { 508fa131d94SPaolo Bonzini ObjectClass *ret; 5092f28d2ffSAnthony Liguori 510fa131d94SPaolo Bonzini trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", 511fa131d94SPaolo Bonzini typename, file, line, func); 512fa131d94SPaolo Bonzini 513*3556c233SPaolo Bonzini #ifndef CONFIG_QOM_CAST_DEBUG 514*3556c233SPaolo Bonzini if (!class->interfaces) { 515*3556c233SPaolo Bonzini return class; 516*3556c233SPaolo Bonzini } 517*3556c233SPaolo Bonzini #endif 518*3556c233SPaolo Bonzini 519fa131d94SPaolo Bonzini ret = object_class_dynamic_cast(class, typename); 520bf0fda34SPaolo Bonzini if (!ret && class) { 521be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 522be17f18bSPaolo Bonzini file, line, func, class, typename); 5232f28d2ffSAnthony Liguori abort(); 5242f28d2ffSAnthony Liguori } 5252f28d2ffSAnthony Liguori 5262f28d2ffSAnthony Liguori return ret; 5272f28d2ffSAnthony Liguori } 5282f28d2ffSAnthony Liguori 5292f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj) 5302f28d2ffSAnthony Liguori { 5312f28d2ffSAnthony Liguori return obj->class->type->name; 5322f28d2ffSAnthony Liguori } 5332f28d2ffSAnthony Liguori 5342f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 5352f28d2ffSAnthony Liguori { 5362f28d2ffSAnthony Liguori return obj->class; 5372f28d2ffSAnthony Liguori } 5382f28d2ffSAnthony Liguori 53917862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass) 54017862378SAndreas Färber { 54117862378SAndreas Färber return klass->type->abstract; 54217862378SAndreas Färber } 54317862378SAndreas Färber 5442f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 5452f28d2ffSAnthony Liguori { 5462f28d2ffSAnthony Liguori return klass->type->name; 5472f28d2ffSAnthony Liguori } 5482f28d2ffSAnthony Liguori 5492f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 5502f28d2ffSAnthony Liguori { 5512f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 5522f28d2ffSAnthony Liguori 5532f28d2ffSAnthony Liguori if (!type) { 5542f28d2ffSAnthony Liguori return NULL; 5552f28d2ffSAnthony Liguori } 5562f28d2ffSAnthony Liguori 557ac451033SIgor Mitsyanko type_initialize(type); 5582f28d2ffSAnthony Liguori 5592f28d2ffSAnthony Liguori return type->class; 5602f28d2ffSAnthony Liguori } 5612f28d2ffSAnthony Liguori 562e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class) 563e7cce67fSPaolo Bonzini { 564e7cce67fSPaolo Bonzini TypeImpl *type = type_get_parent(class->type); 565e7cce67fSPaolo Bonzini 566e7cce67fSPaolo Bonzini if (!type) { 567e7cce67fSPaolo Bonzini return NULL; 568e7cce67fSPaolo Bonzini } 569e7cce67fSPaolo Bonzini 570e7cce67fSPaolo Bonzini type_initialize(type); 571e7cce67fSPaolo Bonzini 572e7cce67fSPaolo Bonzini return type->class; 573e7cce67fSPaolo Bonzini } 574e7cce67fSPaolo Bonzini 5752f28d2ffSAnthony Liguori typedef struct OCFData 5762f28d2ffSAnthony Liguori { 5772f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 57893c511a1SAnthony Liguori const char *implements_type; 57993c511a1SAnthony Liguori bool include_abstract; 5802f28d2ffSAnthony Liguori void *opaque; 5812f28d2ffSAnthony Liguori } OCFData; 5822f28d2ffSAnthony Liguori 5832f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 5842f28d2ffSAnthony Liguori gpointer opaque) 5852f28d2ffSAnthony Liguori { 5862f28d2ffSAnthony Liguori OCFData *data = opaque; 5872f28d2ffSAnthony Liguori TypeImpl *type = value; 58893c511a1SAnthony Liguori ObjectClass *k; 5892f28d2ffSAnthony Liguori 590ac451033SIgor Mitsyanko type_initialize(type); 59193c511a1SAnthony Liguori k = type->class; 5922f28d2ffSAnthony Liguori 59393c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 59493c511a1SAnthony Liguori return; 59593c511a1SAnthony Liguori } 59693c511a1SAnthony Liguori 59793c511a1SAnthony Liguori if (data->implements_type && 59893c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 59993c511a1SAnthony Liguori return; 60093c511a1SAnthony Liguori } 60193c511a1SAnthony Liguori 60293c511a1SAnthony Liguori data->fn(k, data->opaque); 6032f28d2ffSAnthony Liguori } 6042f28d2ffSAnthony Liguori 6052f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 60693c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 6072f28d2ffSAnthony Liguori void *opaque) 6082f28d2ffSAnthony Liguori { 60993c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 6102f28d2ffSAnthony Liguori 6112f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 6122f28d2ffSAnthony Liguori } 61357c9fafeSAnthony Liguori 61432efc535SPaolo Bonzini int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), 61532efc535SPaolo Bonzini void *opaque) 61632efc535SPaolo Bonzini { 61732efc535SPaolo Bonzini ObjectProperty *prop; 61832efc535SPaolo Bonzini int ret = 0; 61932efc535SPaolo Bonzini 62032efc535SPaolo Bonzini QTAILQ_FOREACH(prop, &obj->properties, node) { 62132efc535SPaolo Bonzini if (object_property_is_child(prop)) { 62232efc535SPaolo Bonzini ret = fn(prop->opaque, opaque); 62332efc535SPaolo Bonzini if (ret != 0) { 62432efc535SPaolo Bonzini break; 62532efc535SPaolo Bonzini } 62632efc535SPaolo Bonzini } 62732efc535SPaolo Bonzini } 62832efc535SPaolo Bonzini return ret; 62932efc535SPaolo Bonzini } 63032efc535SPaolo Bonzini 631418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 632418ba9e5SAndreas Färber { 633418ba9e5SAndreas Färber GSList **list = opaque; 634418ba9e5SAndreas Färber 635418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 636418ba9e5SAndreas Färber } 637418ba9e5SAndreas Färber 638418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 639418ba9e5SAndreas Färber bool include_abstract) 640418ba9e5SAndreas Färber { 641418ba9e5SAndreas Färber GSList *list = NULL; 642418ba9e5SAndreas Färber 643418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 644418ba9e5SAndreas Färber implements_type, include_abstract, &list); 645418ba9e5SAndreas Färber return list; 646418ba9e5SAndreas Färber } 647418ba9e5SAndreas Färber 64857c9fafeSAnthony Liguori void object_ref(Object *obj) 64957c9fafeSAnthony Liguori { 65057c9fafeSAnthony Liguori obj->ref++; 65157c9fafeSAnthony Liguori } 65257c9fafeSAnthony Liguori 65357c9fafeSAnthony Liguori void object_unref(Object *obj) 65457c9fafeSAnthony Liguori { 65557c9fafeSAnthony Liguori g_assert(obj->ref > 0); 65657c9fafeSAnthony Liguori obj->ref--; 65757c9fafeSAnthony Liguori 65857c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 65957c9fafeSAnthony Liguori if (obj->ref == 0) { 66057c9fafeSAnthony Liguori object_finalize(obj); 66157c9fafeSAnthony Liguori } 66257c9fafeSAnthony Liguori } 66357c9fafeSAnthony Liguori 66457c9fafeSAnthony Liguori void object_property_add(Object *obj, const char *name, const char *type, 66557c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 66657c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 66757c9fafeSAnthony Liguori ObjectPropertyRelease *release, 66857c9fafeSAnthony Liguori void *opaque, Error **errp) 66957c9fafeSAnthony Liguori { 67054852b03SPeter Maydell ObjectProperty *prop; 67154852b03SPeter Maydell 67254852b03SPeter Maydell QTAILQ_FOREACH(prop, &obj->properties, node) { 67354852b03SPeter Maydell if (strcmp(prop->name, name) == 0) { 67454852b03SPeter Maydell error_setg(errp, "attempt to add duplicate property '%s'" 67554852b03SPeter Maydell " to object (type '%s')", name, 67654852b03SPeter Maydell object_get_typename(obj)); 67754852b03SPeter Maydell return; 67854852b03SPeter Maydell } 67954852b03SPeter Maydell } 68054852b03SPeter Maydell 68154852b03SPeter Maydell prop = g_malloc0(sizeof(*prop)); 68257c9fafeSAnthony Liguori 68357c9fafeSAnthony Liguori prop->name = g_strdup(name); 68457c9fafeSAnthony Liguori prop->type = g_strdup(type); 68557c9fafeSAnthony Liguori 68657c9fafeSAnthony Liguori prop->get = get; 68757c9fafeSAnthony Liguori prop->set = set; 68857c9fafeSAnthony Liguori prop->release = release; 68957c9fafeSAnthony Liguori prop->opaque = opaque; 69057c9fafeSAnthony Liguori 69157c9fafeSAnthony Liguori QTAILQ_INSERT_TAIL(&obj->properties, prop, node); 69257c9fafeSAnthony Liguori } 69357c9fafeSAnthony Liguori 69489bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name, 69589bfe000SPaolo Bonzini Error **errp) 69657c9fafeSAnthony Liguori { 69757c9fafeSAnthony Liguori ObjectProperty *prop; 69857c9fafeSAnthony Liguori 69957c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 70057c9fafeSAnthony Liguori if (strcmp(prop->name, name) == 0) { 70157c9fafeSAnthony Liguori return prop; 70257c9fafeSAnthony Liguori } 70357c9fafeSAnthony Liguori } 70457c9fafeSAnthony Liguori 70589bfe000SPaolo Bonzini error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 70657c9fafeSAnthony Liguori return NULL; 70757c9fafeSAnthony Liguori } 70857c9fafeSAnthony Liguori 70957c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 71057c9fafeSAnthony Liguori { 71189bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 7120866aca1SAnthony Liguori if (prop == NULL) { 7130866aca1SAnthony Liguori return; 7140866aca1SAnthony Liguori } 71557c9fafeSAnthony Liguori 7160866aca1SAnthony Liguori if (prop->release) { 7170866aca1SAnthony Liguori prop->release(obj, name, prop->opaque); 7180866aca1SAnthony Liguori } 7190866aca1SAnthony Liguori 7200866aca1SAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 72157c9fafeSAnthony Liguori 72257c9fafeSAnthony Liguori g_free(prop->name); 72357c9fafeSAnthony Liguori g_free(prop->type); 72457c9fafeSAnthony Liguori g_free(prop); 72557c9fafeSAnthony Liguori } 72657c9fafeSAnthony Liguori 72757c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 72857c9fafeSAnthony Liguori Error **errp) 72957c9fafeSAnthony Liguori { 73089bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 73157c9fafeSAnthony Liguori if (prop == NULL) { 73257c9fafeSAnthony Liguori return; 73357c9fafeSAnthony Liguori } 73457c9fafeSAnthony Liguori 73557c9fafeSAnthony Liguori if (!prop->get) { 73657c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 73757c9fafeSAnthony Liguori } else { 73857c9fafeSAnthony Liguori prop->get(obj, v, prop->opaque, name, errp); 73957c9fafeSAnthony Liguori } 74057c9fafeSAnthony Liguori } 74157c9fafeSAnthony Liguori 74257c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 74357c9fafeSAnthony Liguori Error **errp) 74457c9fafeSAnthony Liguori { 74589bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 74657c9fafeSAnthony Liguori if (prop == NULL) { 74757c9fafeSAnthony Liguori return; 74857c9fafeSAnthony Liguori } 74957c9fafeSAnthony Liguori 75057c9fafeSAnthony Liguori if (!prop->set) { 75157c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 75257c9fafeSAnthony Liguori } else { 75357c9fafeSAnthony Liguori prop->set(obj, v, prop->opaque, name, errp); 75457c9fafeSAnthony Liguori } 75557c9fafeSAnthony Liguori } 75657c9fafeSAnthony Liguori 7577b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 7587b7b7d18SPaolo Bonzini const char *name, Error **errp) 7597b7b7d18SPaolo Bonzini { 7607b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 7617b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 7627b7b7d18SPaolo Bonzini 7637b7b7d18SPaolo Bonzini QDECREF(qstr); 7647b7b7d18SPaolo Bonzini } 7657b7b7d18SPaolo Bonzini 7667b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 7677b7b7d18SPaolo Bonzini Error **errp) 7687b7b7d18SPaolo Bonzini { 7697b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 7707b7b7d18SPaolo Bonzini QString *qstring; 7717b7b7d18SPaolo Bonzini char *retval; 7727b7b7d18SPaolo Bonzini 7737b7b7d18SPaolo Bonzini if (!ret) { 7747b7b7d18SPaolo Bonzini return NULL; 7757b7b7d18SPaolo Bonzini } 7767b7b7d18SPaolo Bonzini qstring = qobject_to_qstring(ret); 7777b7b7d18SPaolo Bonzini if (!qstring) { 7787b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 7797b7b7d18SPaolo Bonzini retval = NULL; 7807b7b7d18SPaolo Bonzini } else { 7817b7b7d18SPaolo Bonzini retval = g_strdup(qstring_get_str(qstring)); 7827b7b7d18SPaolo Bonzini } 7837b7b7d18SPaolo Bonzini 7847b7b7d18SPaolo Bonzini QDECREF(qstring); 7857b7b7d18SPaolo Bonzini return retval; 7867b7b7d18SPaolo Bonzini } 7877b7b7d18SPaolo Bonzini 7881d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 7891d9c5a12SPaolo Bonzini const char *name, Error **errp) 7901d9c5a12SPaolo Bonzini { 7911d9c5a12SPaolo Bonzini object_property_set_str(obj, object_get_canonical_path(value), 7921d9c5a12SPaolo Bonzini name, errp); 7931d9c5a12SPaolo Bonzini } 7941d9c5a12SPaolo Bonzini 7951d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 7961d9c5a12SPaolo Bonzini Error **errp) 7971d9c5a12SPaolo Bonzini { 7981d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 7991d9c5a12SPaolo Bonzini Object *target = NULL; 8001d9c5a12SPaolo Bonzini 8011d9c5a12SPaolo Bonzini if (str && *str) { 8021d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 8031d9c5a12SPaolo Bonzini if (!target) { 8041d9c5a12SPaolo Bonzini error_set(errp, QERR_DEVICE_NOT_FOUND, str); 8051d9c5a12SPaolo Bonzini } 8061d9c5a12SPaolo Bonzini } 8071d9c5a12SPaolo Bonzini 8081d9c5a12SPaolo Bonzini g_free(str); 8091d9c5a12SPaolo Bonzini return target; 8101d9c5a12SPaolo Bonzini } 8111d9c5a12SPaolo Bonzini 8127b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 8137b7b7d18SPaolo Bonzini const char *name, Error **errp) 8147b7b7d18SPaolo Bonzini { 8157b7b7d18SPaolo Bonzini QBool *qbool = qbool_from_int(value); 8167b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 8177b7b7d18SPaolo Bonzini 8187b7b7d18SPaolo Bonzini QDECREF(qbool); 8197b7b7d18SPaolo Bonzini } 8207b7b7d18SPaolo Bonzini 8217b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 8227b7b7d18SPaolo Bonzini Error **errp) 8237b7b7d18SPaolo Bonzini { 8247b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 8257b7b7d18SPaolo Bonzini QBool *qbool; 8267b7b7d18SPaolo Bonzini bool retval; 8277b7b7d18SPaolo Bonzini 8287b7b7d18SPaolo Bonzini if (!ret) { 8297b7b7d18SPaolo Bonzini return false; 8307b7b7d18SPaolo Bonzini } 8317b7b7d18SPaolo Bonzini qbool = qobject_to_qbool(ret); 8327b7b7d18SPaolo Bonzini if (!qbool) { 8337b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 8347b7b7d18SPaolo Bonzini retval = false; 8357b7b7d18SPaolo Bonzini } else { 8367b7b7d18SPaolo Bonzini retval = qbool_get_int(qbool); 8377b7b7d18SPaolo Bonzini } 8387b7b7d18SPaolo Bonzini 8397b7b7d18SPaolo Bonzini QDECREF(qbool); 8407b7b7d18SPaolo Bonzini return retval; 8417b7b7d18SPaolo Bonzini } 8427b7b7d18SPaolo Bonzini 8437b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 8447b7b7d18SPaolo Bonzini const char *name, Error **errp) 8457b7b7d18SPaolo Bonzini { 8467b7b7d18SPaolo Bonzini QInt *qint = qint_from_int(value); 8477b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qint), name, errp); 8487b7b7d18SPaolo Bonzini 8497b7b7d18SPaolo Bonzini QDECREF(qint); 8507b7b7d18SPaolo Bonzini } 8517b7b7d18SPaolo Bonzini 8527b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 8537b7b7d18SPaolo Bonzini Error **errp) 8547b7b7d18SPaolo Bonzini { 8557b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 8567b7b7d18SPaolo Bonzini QInt *qint; 8577b7b7d18SPaolo Bonzini int64_t retval; 8587b7b7d18SPaolo Bonzini 8597b7b7d18SPaolo Bonzini if (!ret) { 8607b7b7d18SPaolo Bonzini return -1; 8617b7b7d18SPaolo Bonzini } 8627b7b7d18SPaolo Bonzini qint = qobject_to_qint(ret); 8637b7b7d18SPaolo Bonzini if (!qint) { 8647b7b7d18SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 8657b7b7d18SPaolo Bonzini retval = -1; 8667b7b7d18SPaolo Bonzini } else { 8677b7b7d18SPaolo Bonzini retval = qint_get_int(qint); 8687b7b7d18SPaolo Bonzini } 8697b7b7d18SPaolo Bonzini 8707b7b7d18SPaolo Bonzini QDECREF(qint); 8717b7b7d18SPaolo Bonzini return retval; 8727b7b7d18SPaolo Bonzini } 8737b7b7d18SPaolo Bonzini 874b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 875b2cd7deeSPaolo Bonzini const char *name, Error **errp) 876b2cd7deeSPaolo Bonzini { 877b2cd7deeSPaolo Bonzini StringInputVisitor *mi; 878b2cd7deeSPaolo Bonzini mi = string_input_visitor_new(string); 879b2cd7deeSPaolo Bonzini object_property_set(obj, string_input_get_visitor(mi), name, errp); 880b2cd7deeSPaolo Bonzini 881b2cd7deeSPaolo Bonzini string_input_visitor_cleanup(mi); 882b2cd7deeSPaolo Bonzini } 883b2cd7deeSPaolo Bonzini 884b2cd7deeSPaolo Bonzini char *object_property_print(Object *obj, const char *name, 885b2cd7deeSPaolo Bonzini Error **errp) 886b2cd7deeSPaolo Bonzini { 887b2cd7deeSPaolo Bonzini StringOutputVisitor *mo; 888b2cd7deeSPaolo Bonzini char *string; 889b2cd7deeSPaolo Bonzini 890b2cd7deeSPaolo Bonzini mo = string_output_visitor_new(); 8918185bfc1SPaolo Bonzini object_property_get(obj, string_output_get_visitor(mo), name, errp); 892b2cd7deeSPaolo Bonzini string = string_output_get_string(mo); 893b2cd7deeSPaolo Bonzini string_output_visitor_cleanup(mo); 894b2cd7deeSPaolo Bonzini return string; 895b2cd7deeSPaolo Bonzini } 896b2cd7deeSPaolo Bonzini 89757c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 89857c9fafeSAnthony Liguori { 89989bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 90057c9fafeSAnthony Liguori if (prop == NULL) { 90157c9fafeSAnthony Liguori return NULL; 90257c9fafeSAnthony Liguori } 90357c9fafeSAnthony Liguori 90457c9fafeSAnthony Liguori return prop->type; 90557c9fafeSAnthony Liguori } 90657c9fafeSAnthony Liguori 90757c9fafeSAnthony Liguori Object *object_get_root(void) 90857c9fafeSAnthony Liguori { 9098b45d447SAnthony Liguori static Object *root; 91057c9fafeSAnthony Liguori 9118b45d447SAnthony Liguori if (!root) { 9128b45d447SAnthony Liguori root = object_new("container"); 91357c9fafeSAnthony Liguori } 91457c9fafeSAnthony Liguori 9158b45d447SAnthony Liguori return root; 91657c9fafeSAnthony Liguori } 91757c9fafeSAnthony Liguori 91857c9fafeSAnthony Liguori static void object_get_child_property(Object *obj, Visitor *v, void *opaque, 91957c9fafeSAnthony Liguori const char *name, Error **errp) 92057c9fafeSAnthony Liguori { 92157c9fafeSAnthony Liguori Object *child = opaque; 92257c9fafeSAnthony Liguori gchar *path; 92357c9fafeSAnthony Liguori 92457c9fafeSAnthony Liguori path = object_get_canonical_path(child); 92557c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 92657c9fafeSAnthony Liguori g_free(path); 92757c9fafeSAnthony Liguori } 92857c9fafeSAnthony Liguori 929db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 930db85b575SAnthony Liguori void *opaque) 931db85b575SAnthony Liguori { 932db85b575SAnthony Liguori Object *child = opaque; 933db85b575SAnthony Liguori 934db85b575SAnthony Liguori object_unref(child); 935db85b575SAnthony Liguori } 936db85b575SAnthony Liguori 93757c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 93857c9fafeSAnthony Liguori Object *child, Error **errp) 93957c9fafeSAnthony Liguori { 94057c9fafeSAnthony Liguori gchar *type; 94157c9fafeSAnthony Liguori 94257c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 94357c9fafeSAnthony Liguori 94457c9fafeSAnthony Liguori object_property_add(obj, name, type, object_get_child_property, 945db85b575SAnthony Liguori NULL, object_finalize_child_property, child, errp); 94657c9fafeSAnthony Liguori 94757c9fafeSAnthony Liguori object_ref(child); 94857c9fafeSAnthony Liguori g_assert(child->parent == NULL); 94957c9fafeSAnthony Liguori child->parent = obj; 95057c9fafeSAnthony Liguori 95157c9fafeSAnthony Liguori g_free(type); 95257c9fafeSAnthony Liguori } 95357c9fafeSAnthony Liguori 95457c9fafeSAnthony Liguori static void object_get_link_property(Object *obj, Visitor *v, void *opaque, 95557c9fafeSAnthony Liguori const char *name, Error **errp) 95657c9fafeSAnthony Liguori { 95757c9fafeSAnthony Liguori Object **child = opaque; 95857c9fafeSAnthony Liguori gchar *path; 95957c9fafeSAnthony Liguori 96057c9fafeSAnthony Liguori if (*child) { 96157c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 96257c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 96357c9fafeSAnthony Liguori g_free(path); 96457c9fafeSAnthony Liguori } else { 96557c9fafeSAnthony Liguori path = (gchar *)""; 96657c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 96757c9fafeSAnthony Liguori } 96857c9fafeSAnthony Liguori } 96957c9fafeSAnthony Liguori 97057c9fafeSAnthony Liguori static void object_set_link_property(Object *obj, Visitor *v, void *opaque, 97157c9fafeSAnthony Liguori const char *name, Error **errp) 97257c9fafeSAnthony Liguori { 97357c9fafeSAnthony Liguori Object **child = opaque; 974f0cdc966SAlexander Barabash Object *old_target; 97557c9fafeSAnthony Liguori bool ambiguous = false; 97657c9fafeSAnthony Liguori const char *type; 97757c9fafeSAnthony Liguori char *path; 97811e35bfdSPaolo Bonzini gchar *target_type; 97957c9fafeSAnthony Liguori 98057c9fafeSAnthony Liguori type = object_property_get_type(obj, name, NULL); 98157c9fafeSAnthony Liguori 98257c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 98357c9fafeSAnthony Liguori 984f0cdc966SAlexander Barabash old_target = *child; 98511e35bfdSPaolo Bonzini *child = NULL; 98657c9fafeSAnthony Liguori 98757c9fafeSAnthony Liguori if (strcmp(path, "") != 0) { 98857c9fafeSAnthony Liguori Object *target; 98957c9fafeSAnthony Liguori 9908f770d39SPaolo Bonzini /* Go from link<FOO> to FOO. */ 99111e35bfdSPaolo Bonzini target_type = g_strndup(&type[5], strlen(type) - 6); 99211e35bfdSPaolo Bonzini target = object_resolve_path_type(path, target_type, &ambiguous); 99311e35bfdSPaolo Bonzini 99411e35bfdSPaolo Bonzini if (ambiguous) { 99511e35bfdSPaolo Bonzini error_set(errp, QERR_AMBIGUOUS_PATH, path); 99611e35bfdSPaolo Bonzini } else if (target) { 99757c9fafeSAnthony Liguori object_ref(target); 998fe40e627SAnthony Liguori *child = target; 99957c9fafeSAnthony Liguori } else { 100011e35bfdSPaolo Bonzini target = object_resolve_path(path, &ambiguous); 100111e35bfdSPaolo Bonzini if (target || ambiguous) { 100211e35bfdSPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 100357c9fafeSAnthony Liguori } else { 100457c9fafeSAnthony Liguori error_set(errp, QERR_DEVICE_NOT_FOUND, path); 100557c9fafeSAnthony Liguori } 100611e35bfdSPaolo Bonzini } 100711e35bfdSPaolo Bonzini g_free(target_type); 100857c9fafeSAnthony Liguori } 100957c9fafeSAnthony Liguori 101057c9fafeSAnthony Liguori g_free(path); 1011f0cdc966SAlexander Barabash 1012f0cdc966SAlexander Barabash if (old_target != NULL) { 1013f0cdc966SAlexander Barabash object_unref(old_target); 1014f0cdc966SAlexander Barabash } 101557c9fafeSAnthony Liguori } 101657c9fafeSAnthony Liguori 101757c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 101857c9fafeSAnthony Liguori const char *type, Object **child, 101957c9fafeSAnthony Liguori Error **errp) 102057c9fafeSAnthony Liguori { 102157c9fafeSAnthony Liguori gchar *full_type; 102257c9fafeSAnthony Liguori 102357c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 102457c9fafeSAnthony Liguori 102557c9fafeSAnthony Liguori object_property_add(obj, name, full_type, 102657c9fafeSAnthony Liguori object_get_link_property, 102757c9fafeSAnthony Liguori object_set_link_property, 102857c9fafeSAnthony Liguori NULL, child, errp); 102957c9fafeSAnthony Liguori 103057c9fafeSAnthony Liguori g_free(full_type); 103157c9fafeSAnthony Liguori } 103257c9fafeSAnthony Liguori 103357c9fafeSAnthony Liguori gchar *object_get_canonical_path(Object *obj) 103457c9fafeSAnthony Liguori { 103557c9fafeSAnthony Liguori Object *root = object_get_root(); 103657c9fafeSAnthony Liguori char *newpath = NULL, *path = NULL; 103757c9fafeSAnthony Liguori 103857c9fafeSAnthony Liguori while (obj != root) { 103957c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 104057c9fafeSAnthony Liguori 104157c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 104257c9fafeSAnthony Liguori 104357c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->parent->properties, node) { 10445d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 104557c9fafeSAnthony Liguori continue; 104657c9fafeSAnthony Liguori } 104757c9fafeSAnthony Liguori 104857c9fafeSAnthony Liguori if (prop->opaque == obj) { 104957c9fafeSAnthony Liguori if (path) { 105057c9fafeSAnthony Liguori newpath = g_strdup_printf("%s/%s", prop->name, path); 105157c9fafeSAnthony Liguori g_free(path); 105257c9fafeSAnthony Liguori path = newpath; 105357c9fafeSAnthony Liguori } else { 105457c9fafeSAnthony Liguori path = g_strdup(prop->name); 105557c9fafeSAnthony Liguori } 105657c9fafeSAnthony Liguori break; 105757c9fafeSAnthony Liguori } 105857c9fafeSAnthony Liguori } 105957c9fafeSAnthony Liguori 106057c9fafeSAnthony Liguori g_assert(prop != NULL); 106157c9fafeSAnthony Liguori 106257c9fafeSAnthony Liguori obj = obj->parent; 106357c9fafeSAnthony Liguori } 106457c9fafeSAnthony Liguori 106557c9fafeSAnthony Liguori newpath = g_strdup_printf("/%s", path); 106657c9fafeSAnthony Liguori g_free(path); 106757c9fafeSAnthony Liguori 106857c9fafeSAnthony Liguori return newpath; 106957c9fafeSAnthony Liguori } 107057c9fafeSAnthony Liguori 10713e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part) 1072a612b2a6SPaolo Bonzini { 107389bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part, NULL); 1074a612b2a6SPaolo Bonzini if (prop == NULL) { 1075a612b2a6SPaolo Bonzini return NULL; 1076a612b2a6SPaolo Bonzini } 1077a612b2a6SPaolo Bonzini 10785d9d3f47SAndreas Färber if (object_property_is_link(prop)) { 1079a612b2a6SPaolo Bonzini return *(Object **)prop->opaque; 10805d9d3f47SAndreas Färber } else if (object_property_is_child(prop)) { 1081a612b2a6SPaolo Bonzini return prop->opaque; 1082a612b2a6SPaolo Bonzini } else { 1083a612b2a6SPaolo Bonzini return NULL; 1084a612b2a6SPaolo Bonzini } 1085a612b2a6SPaolo Bonzini } 1086a612b2a6SPaolo Bonzini 108757c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 108857c9fafeSAnthony Liguori gchar **parts, 108902fe2db6SPaolo Bonzini const char *typename, 109057c9fafeSAnthony Liguori int index) 109157c9fafeSAnthony Liguori { 109257c9fafeSAnthony Liguori Object *child; 109357c9fafeSAnthony Liguori 109457c9fafeSAnthony Liguori if (parts[index] == NULL) { 109502fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 109657c9fafeSAnthony Liguori } 109757c9fafeSAnthony Liguori 109857c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 109902fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 110057c9fafeSAnthony Liguori } 110157c9fafeSAnthony Liguori 1102a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 110357c9fafeSAnthony Liguori if (!child) { 110457c9fafeSAnthony Liguori return NULL; 110557c9fafeSAnthony Liguori } 110657c9fafeSAnthony Liguori 110702fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 110857c9fafeSAnthony Liguori } 110957c9fafeSAnthony Liguori 111057c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 111157c9fafeSAnthony Liguori gchar **parts, 111202fe2db6SPaolo Bonzini const char *typename, 111357c9fafeSAnthony Liguori bool *ambiguous) 111457c9fafeSAnthony Liguori { 111557c9fafeSAnthony Liguori Object *obj; 111657c9fafeSAnthony Liguori ObjectProperty *prop; 111757c9fafeSAnthony Liguori 111802fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 111957c9fafeSAnthony Liguori 112057c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &parent->properties, node) { 112157c9fafeSAnthony Liguori Object *found; 112257c9fafeSAnthony Liguori 11235d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 112457c9fafeSAnthony Liguori continue; 112557c9fafeSAnthony Liguori } 112657c9fafeSAnthony Liguori 112702fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 112802fe2db6SPaolo Bonzini typename, ambiguous); 112957c9fafeSAnthony Liguori if (found) { 113057c9fafeSAnthony Liguori if (obj) { 113157c9fafeSAnthony Liguori if (ambiguous) { 113257c9fafeSAnthony Liguori *ambiguous = true; 113357c9fafeSAnthony Liguori } 113457c9fafeSAnthony Liguori return NULL; 113557c9fafeSAnthony Liguori } 113657c9fafeSAnthony Liguori obj = found; 113757c9fafeSAnthony Liguori } 113857c9fafeSAnthony Liguori 113957c9fafeSAnthony Liguori if (ambiguous && *ambiguous) { 114057c9fafeSAnthony Liguori return NULL; 114157c9fafeSAnthony Liguori } 114257c9fafeSAnthony Liguori } 114357c9fafeSAnthony Liguori 114457c9fafeSAnthony Liguori return obj; 114557c9fafeSAnthony Liguori } 114657c9fafeSAnthony Liguori 114702fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 114802fe2db6SPaolo Bonzini bool *ambiguous) 114957c9fafeSAnthony Liguori { 115057c9fafeSAnthony Liguori Object *obj; 115157c9fafeSAnthony Liguori gchar **parts; 115257c9fafeSAnthony Liguori 115357c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 11542e1103f6SPaolo Bonzini assert(parts); 115557c9fafeSAnthony Liguori 11562e1103f6SPaolo Bonzini if (parts[0] == NULL || strcmp(parts[0], "") != 0) { 115757c9fafeSAnthony Liguori if (ambiguous) { 115857c9fafeSAnthony Liguori *ambiguous = false; 115957c9fafeSAnthony Liguori } 116002fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 116102fe2db6SPaolo Bonzini typename, ambiguous); 116257c9fafeSAnthony Liguori } else { 116302fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 116457c9fafeSAnthony Liguori } 116557c9fafeSAnthony Liguori 116657c9fafeSAnthony Liguori g_strfreev(parts); 116757c9fafeSAnthony Liguori 116857c9fafeSAnthony Liguori return obj; 116957c9fafeSAnthony Liguori } 117057c9fafeSAnthony Liguori 117102fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 117202fe2db6SPaolo Bonzini { 117302fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 117402fe2db6SPaolo Bonzini } 117502fe2db6SPaolo Bonzini 117657c9fafeSAnthony Liguori typedef struct StringProperty 117757c9fafeSAnthony Liguori { 117857c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 117957c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 118057c9fafeSAnthony Liguori } StringProperty; 118157c9fafeSAnthony Liguori 11827b7b7d18SPaolo Bonzini static void property_get_str(Object *obj, Visitor *v, void *opaque, 118357c9fafeSAnthony Liguori const char *name, Error **errp) 118457c9fafeSAnthony Liguori { 118557c9fafeSAnthony Liguori StringProperty *prop = opaque; 118657c9fafeSAnthony Liguori char *value; 118757c9fafeSAnthony Liguori 118857c9fafeSAnthony Liguori value = prop->get(obj, errp); 118957c9fafeSAnthony Liguori if (value) { 119057c9fafeSAnthony Liguori visit_type_str(v, &value, name, errp); 119157c9fafeSAnthony Liguori g_free(value); 119257c9fafeSAnthony Liguori } 119357c9fafeSAnthony Liguori } 119457c9fafeSAnthony Liguori 11957b7b7d18SPaolo Bonzini static void property_set_str(Object *obj, Visitor *v, void *opaque, 119657c9fafeSAnthony Liguori const char *name, Error **errp) 119757c9fafeSAnthony Liguori { 119857c9fafeSAnthony Liguori StringProperty *prop = opaque; 119957c9fafeSAnthony Liguori char *value; 120057c9fafeSAnthony Liguori Error *local_err = NULL; 120157c9fafeSAnthony Liguori 120257c9fafeSAnthony Liguori visit_type_str(v, &value, name, &local_err); 120357c9fafeSAnthony Liguori if (local_err) { 120457c9fafeSAnthony Liguori error_propagate(errp, local_err); 120557c9fafeSAnthony Liguori return; 120657c9fafeSAnthony Liguori } 120757c9fafeSAnthony Liguori 120857c9fafeSAnthony Liguori prop->set(obj, value, errp); 120957c9fafeSAnthony Liguori g_free(value); 121057c9fafeSAnthony Liguori } 121157c9fafeSAnthony Liguori 12127b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 121357c9fafeSAnthony Liguori void *opaque) 121457c9fafeSAnthony Liguori { 121557c9fafeSAnthony Liguori StringProperty *prop = opaque; 121657c9fafeSAnthony Liguori g_free(prop); 121757c9fafeSAnthony Liguori } 121857c9fafeSAnthony Liguori 121957c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 122057c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 122157c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 122257c9fafeSAnthony Liguori Error **errp) 122357c9fafeSAnthony Liguori { 122457c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 122557c9fafeSAnthony Liguori 122657c9fafeSAnthony Liguori prop->get = get; 122757c9fafeSAnthony Liguori prop->set = set; 122857c9fafeSAnthony Liguori 122957c9fafeSAnthony Liguori object_property_add(obj, name, "string", 12307b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 12317b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 12327b7b7d18SPaolo Bonzini property_release_str, 123357c9fafeSAnthony Liguori prop, errp); 123457c9fafeSAnthony Liguori } 1235745549c8SPaolo Bonzini 12360e558843SAnthony Liguori typedef struct BoolProperty 12370e558843SAnthony Liguori { 12380e558843SAnthony Liguori bool (*get)(Object *, Error **); 12390e558843SAnthony Liguori void (*set)(Object *, bool, Error **); 12400e558843SAnthony Liguori } BoolProperty; 12410e558843SAnthony Liguori 12420e558843SAnthony Liguori static void property_get_bool(Object *obj, Visitor *v, void *opaque, 12430e558843SAnthony Liguori const char *name, Error **errp) 12440e558843SAnthony Liguori { 12450e558843SAnthony Liguori BoolProperty *prop = opaque; 12460e558843SAnthony Liguori bool value; 12470e558843SAnthony Liguori 12480e558843SAnthony Liguori value = prop->get(obj, errp); 12490e558843SAnthony Liguori visit_type_bool(v, &value, name, errp); 12500e558843SAnthony Liguori } 12510e558843SAnthony Liguori 12520e558843SAnthony Liguori static void property_set_bool(Object *obj, Visitor *v, void *opaque, 12530e558843SAnthony Liguori const char *name, Error **errp) 12540e558843SAnthony Liguori { 12550e558843SAnthony Liguori BoolProperty *prop = opaque; 12560e558843SAnthony Liguori bool value; 12570e558843SAnthony Liguori Error *local_err = NULL; 12580e558843SAnthony Liguori 12590e558843SAnthony Liguori visit_type_bool(v, &value, name, &local_err); 12600e558843SAnthony Liguori if (local_err) { 12610e558843SAnthony Liguori error_propagate(errp, local_err); 12620e558843SAnthony Liguori return; 12630e558843SAnthony Liguori } 12640e558843SAnthony Liguori 12650e558843SAnthony Liguori prop->set(obj, value, errp); 12660e558843SAnthony Liguori } 12670e558843SAnthony Liguori 12680e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name, 12690e558843SAnthony Liguori void *opaque) 12700e558843SAnthony Liguori { 12710e558843SAnthony Liguori BoolProperty *prop = opaque; 12720e558843SAnthony Liguori g_free(prop); 12730e558843SAnthony Liguori } 12740e558843SAnthony Liguori 12750e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name, 12760e558843SAnthony Liguori bool (*get)(Object *, Error **), 12770e558843SAnthony Liguori void (*set)(Object *, bool, Error **), 12780e558843SAnthony Liguori Error **errp) 12790e558843SAnthony Liguori { 12800e558843SAnthony Liguori BoolProperty *prop = g_malloc0(sizeof(*prop)); 12810e558843SAnthony Liguori 12820e558843SAnthony Liguori prop->get = get; 12830e558843SAnthony Liguori prop->set = set; 12840e558843SAnthony Liguori 12850e558843SAnthony Liguori object_property_add(obj, name, "bool", 12860e558843SAnthony Liguori get ? property_get_bool : NULL, 12870e558843SAnthony Liguori set ? property_set_bool : NULL, 12880e558843SAnthony Liguori property_release_bool, 12890e558843SAnthony Liguori prop, errp); 12900e558843SAnthony Liguori } 12910e558843SAnthony Liguori 12922f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp) 12932f262e06SPaolo Bonzini { 12942f262e06SPaolo Bonzini return g_strdup(object_get_typename(obj)); 12952f262e06SPaolo Bonzini } 12962f262e06SPaolo Bonzini 12972f262e06SPaolo Bonzini static void object_instance_init(Object *obj) 12982f262e06SPaolo Bonzini { 12992f262e06SPaolo Bonzini object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); 13002f262e06SPaolo Bonzini } 13012f262e06SPaolo Bonzini 1302745549c8SPaolo Bonzini static void register_types(void) 1303745549c8SPaolo Bonzini { 1304745549c8SPaolo Bonzini static TypeInfo interface_info = { 1305745549c8SPaolo Bonzini .name = TYPE_INTERFACE, 130633e95c63SAnthony Liguori .class_size = sizeof(InterfaceClass), 1307745549c8SPaolo Bonzini .abstract = true, 1308745549c8SPaolo Bonzini }; 1309745549c8SPaolo Bonzini 1310745549c8SPaolo Bonzini static TypeInfo object_info = { 1311745549c8SPaolo Bonzini .name = TYPE_OBJECT, 1312745549c8SPaolo Bonzini .instance_size = sizeof(Object), 13132f262e06SPaolo Bonzini .instance_init = object_instance_init, 1314745549c8SPaolo Bonzini .abstract = true, 1315745549c8SPaolo Bonzini }; 1316745549c8SPaolo Bonzini 1317049cb3cfSPaolo Bonzini type_interface = type_register_internal(&interface_info); 1318049cb3cfSPaolo Bonzini type_register_internal(&object_info); 1319745549c8SPaolo Bonzini } 1320745549c8SPaolo Bonzini 1321745549c8SPaolo Bonzini type_init(register_types) 1322