From 16bf7f522a2ff68993f80631ed86254c71eaf5d4 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 13 Oct 2015 13:37:46 +0100 Subject: [PATCH 1/4] qom: Allow properties to be registered against classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there are many instances of a given class, registering properties against the instance is wasteful of resources. The majority of objects have a statically defined list of possible properties, so most of the properties are easily registerable against the class. Only those properties which are conditionally registered at runtime need be recorded against the klass. Registering properties against classes also makes it possible to provide static introspection of QOM - currently introspection is only possible after creating an instance of a class, which severely limits its usefulness. This impl only supports simple scalar properties. It does not attempt to allow child object / link object properties against the class. There are ways to support those too, but it would make this patch more complicated, so it is left as an exercise for the future. There is no equivalent to object_property_del() provided, since classes must be immutable once they are defined. Signed-off-by: Daniel P. Berrange Signed-off-by: Andreas Färber --- include/qom/object.h | 46 +++++++- qom/object.c | 236 ++++++++++++++++++++++++++++++++++--- tests/check-qom-proplist.c | 31 +++-- 3 files changed, 287 insertions(+), 26 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 4509166f6f..37d414a6bf 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -381,6 +381,8 @@ struct ObjectClass const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE]; ObjectUnparent *unparent; + + GHashTable *properties; }; /** @@ -944,6 +946,13 @@ ObjectProperty *object_property_add(Object *obj, const char *name, void object_property_del(Object *obj, const char *name, Error **errp); +ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); + /** * object_property_find: * @obj: the object @@ -954,6 +963,8 @@ void object_property_del(Object *obj, const char *name, Error **errp); */ ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp); +ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, + Error **errp); typedef struct ObjectPropertyIterator ObjectPropertyIterator; @@ -962,7 +973,7 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; * @obj: the object * * Initializes an iterator for traversing all properties - * registered against an object instance. + * registered against an object instance, its class and all parent classes. * * It is forbidden to modify the property list while iterating, * whether removing or adding properties. @@ -1371,6 +1382,12 @@ void object_property_add_str(Object *obj, const char *name, void (*set)(Object *, const char *, Error **), Error **errp); +void object_class_property_add_str(ObjectClass *klass, const char *name, + char *(*get)(Object *, Error **), + void (*set)(Object *, const char *, + Error **), + Error **errp); + /** * object_property_add_bool: * @obj: the object to add a property to @@ -1387,6 +1404,11 @@ void object_property_add_bool(Object *obj, const char *name, void (*set)(Object *, bool, Error **), Error **errp); +void object_class_property_add_bool(ObjectClass *klass, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp); + /** * object_property_add_enum: * @obj: the object to add a property to @@ -1406,6 +1428,13 @@ void object_property_add_enum(Object *obj, const char *name, void (*set)(Object *, int, Error **), Error **errp); +void object_class_property_add_enum(ObjectClass *klass, const char *name, + const char *typename, + const char * const *strings, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp); + /** * object_property_add_tm: * @obj: the object to add a property to @@ -1420,6 +1449,10 @@ void object_property_add_tm(Object *obj, const char *name, void (*get)(Object *, struct tm *, Error **), Error **errp); +void object_class_property_add_tm(ObjectClass *klass, const char *name, + void (*get)(Object *, struct tm *, Error **), + Error **errp); + /** * object_property_add_uint8_ptr: * @obj: the object to add a property to @@ -1432,6 +1465,8 @@ void object_property_add_tm(Object *obj, const char *name, */ void object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, Error **errp); +void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, + const uint8_t *v, Error **errp); /** * object_property_add_uint16_ptr: @@ -1445,6 +1480,8 @@ void object_property_add_uint8_ptr(Object *obj, const char *name, */ void object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, Error **errp); +void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, + const uint16_t *v, Error **errp); /** * object_property_add_uint32_ptr: @@ -1458,6 +1495,8 @@ void object_property_add_uint16_ptr(Object *obj, const char *name, */ void object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, Error **errp); +void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, + const uint32_t *v, Error **errp); /** * object_property_add_uint64_ptr: @@ -1471,6 +1510,8 @@ void object_property_add_uint32_ptr(Object *obj, const char *name, */ void object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, Error **Errp); +void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, + const uint64_t *v, Error **Errp); /** * object_property_add_alias: @@ -1522,6 +1563,9 @@ void object_property_add_const_link(Object *obj, const char *name, */ void object_property_set_description(Object *obj, const char *name, const char *description, Error **errp); +void object_class_property_set_description(ObjectClass *klass, const char *name, + const char *description, + Error **errp); /** * object_child_foreach: diff --git a/qom/object.c b/qom/object.c index d7515697a3..5d4c80b102 100644 --- a/qom/object.c +++ b/qom/object.c @@ -68,6 +68,7 @@ struct TypeImpl }; struct ObjectPropertyIterator { + ObjectClass *nextclass; GHashTableIter iter; }; @@ -246,6 +247,16 @@ static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, iface_impl->class); } +static void object_property_free(gpointer data) +{ + ObjectProperty *prop = data; + + g_free(prop->name); + g_free(prop->type); + g_free(prop->description); + g_free(prop); +} + static void type_initialize(TypeImpl *ti) { TypeImpl *parent; @@ -268,6 +279,8 @@ static void type_initialize(TypeImpl *ti) g_assert_cmpint(parent->class_size, <=, ti->class_size); memcpy(ti->class, parent->class, parent->class_size); ti->class->interfaces = NULL; + ti->class->properties = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, object_property_free); for (e = parent->class->interfaces; e; e = e->next) { InterfaceClass *iface = e->data; @@ -292,6 +305,9 @@ static void type_initialize(TypeImpl *ti) type_initialize_interface(ti, t, t); } + } else { + ti->class->properties = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, object_property_free); } ti->class->type = ti; @@ -330,16 +346,6 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) } } -static void object_property_free(gpointer data) -{ - ObjectProperty *prop = data; - - g_free(prop->name); - g_free(prop->type); - g_free(prop->description); - g_free(prop); -} - void object_initialize_with_type(void *data, size_t size, TypeImpl *type) { Object *obj = data; @@ -918,10 +924,10 @@ object_property_add(Object *obj, const char *name, const char *type, return ret; } - if (g_hash_table_lookup(obj->properties, name) != NULL) { + if (object_property_find(obj, name, NULL) != NULL) { error_setg(errp, "attempt to add duplicate property '%s'" - " to object (type '%s')", name, - object_get_typename(obj)); + " to object (type '%s')", name, + object_get_typename(obj)); return NULL; } @@ -939,10 +945,50 @@ object_property_add(Object *obj, const char *name, const char *type, return prop; } +ObjectProperty * +object_class_property_add(ObjectClass *klass, + const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, + Error **errp) +{ + ObjectProperty *prop; + + if (object_class_property_find(klass, name, NULL) != NULL) { + error_setg(errp, "attempt to add duplicate property '%s'" + " to object (type '%s')", name, + object_class_get_name(klass)); + return NULL; + } + + prop = g_malloc0(sizeof(*prop)); + + prop->name = g_strdup(name); + prop->type = g_strdup(type); + + prop->get = get; + prop->set = set; + prop->release = release; + prop->opaque = opaque; + + g_hash_table_insert(klass->properties, g_strdup(name), prop); + + return prop; +} + ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp) { ObjectProperty *prop; + ObjectClass *klass = object_get_class(obj); + + prop = object_class_property_find(klass, name, NULL); + if (prop) { + return prop; + } prop = g_hash_table_lookup(obj->properties, name); if (prop) { @@ -957,6 +1003,7 @@ ObjectPropertyIterator *object_property_iter_init(Object *obj) { ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); g_hash_table_iter_init(&ret->iter, obj->properties); + ret->nextclass = object_get_class(obj); return ret; } @@ -971,12 +1018,37 @@ void object_property_iter_free(ObjectPropertyIterator *iter) ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) { gpointer key, val; - if (!g_hash_table_iter_next(&iter->iter, &key, &val)) { - return NULL; + while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { + if (!iter->nextclass) { + return NULL; + } + g_hash_table_iter_init(&iter->iter, iter->nextclass->properties); + iter->nextclass = object_class_get_parent(iter->nextclass); } return val; } +ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, + Error **errp) +{ + ObjectProperty *prop; + ObjectClass *parent_klass; + + parent_klass = object_class_get_parent(klass); + if (parent_klass) { + prop = object_class_property_find(parent_klass, name, NULL); + if (prop) { + return prop; + } + } + + prop = g_hash_table_lookup(klass->properties, name); + if (!prop) { + error_setg(errp, "Property '.%s' not found", name); + } + return prop; +} + void object_property_del(Object *obj, const char *name, Error **errp) { ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); @@ -1730,6 +1802,29 @@ void object_property_add_str(Object *obj, const char *name, } } +void object_class_property_add_str(ObjectClass *klass, const char *name, + char *(*get)(Object *, Error **), + void (*set)(Object *, const char *, + Error **), + Error **errp) +{ + Error *local_err = NULL; + StringProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, "string", + get ? property_get_str : NULL, + set ? property_set_str : NULL, + property_release_str, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + typedef struct BoolProperty { bool (*get)(Object *, Error **); @@ -1797,6 +1892,28 @@ void object_property_add_bool(Object *obj, const char *name, } } +void object_class_property_add_bool(ObjectClass *klass, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp) +{ + Error *local_err = NULL; + BoolProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + property_release_bool, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + static void property_get_enum(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -1860,6 +1977,31 @@ void object_property_add_enum(Object *obj, const char *name, } } +void object_class_property_add_enum(ObjectClass *klass, const char *name, + const char *typename, + const char * const *strings, + int (*get)(Object *, Error **), + void (*set)(Object *, int, Error **), + Error **errp) +{ + Error *local_err = NULL; + EnumProperty *prop = g_malloc(sizeof(*prop)); + + prop->strings = strings; + prop->get = get; + prop->set = set; + + object_class_property_add(klass, name, typename, + get ? property_get_enum : NULL, + set ? property_set_enum : NULL, + property_release_enum, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + typedef struct TMProperty { void (*get)(Object *, struct tm *, Error **); } TMProperty; @@ -1939,6 +2081,25 @@ void object_property_add_tm(Object *obj, const char *name, } } +void object_class_property_add_tm(ObjectClass *klass, const char *name, + void (*get)(Object *, struct tm *, Error **), + Error **errp) +{ + Error *local_err = NULL; + TMProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + + object_class_property_add(klass, name, "struct tm", + get ? property_get_tm : NULL, NULL, + property_release_tm, + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } +} + static char *qdev_get_type(Object *obj, Error **errp) { return g_strdup(object_get_typename(obj)); @@ -1983,6 +2144,13 @@ void object_property_add_uint8_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, + const uint8_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint8", property_get_uint8_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, Error **errp) { @@ -1990,6 +2158,13 @@ void object_property_add_uint16_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, + const uint16_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint16", property_get_uint16_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, Error **errp) { @@ -1997,6 +2172,13 @@ void object_property_add_uint32_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, + const uint32_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint32", property_get_uint32_ptr, + NULL, NULL, (void *)v, errp); +} + void object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, Error **errp) { @@ -2004,6 +2186,13 @@ void object_property_add_uint64_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, + const uint64_t *v, Error **errp) +{ + object_class_property_add(klass, name, "uint64", property_get_uint64_ptr, + NULL, NULL, (void *)v, errp); +} + typedef struct { Object *target_obj; char *target_name; @@ -2101,6 +2290,23 @@ void object_property_set_description(Object *obj, const char *name, op->description = g_strdup(description); } +void object_class_property_set_description(ObjectClass *klass, + const char *name, + const char *description, + Error **errp) +{ + ObjectProperty *op; + + op = g_hash_table_lookup(klass->properties, name); + if (!op) { + error_setg(errp, "Property '.%s' not found", name); + return; + } + + g_free(op->description); + op->description = g_strdup(description); +} + static void object_instance_init(Object *obj) { object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index e674c0fa89..5167e78e93 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -123,18 +123,28 @@ static void dummy_init(Object *obj) dummy_get_bv, dummy_set_bv, NULL); - object_property_add_str(obj, "sv", - dummy_get_sv, - dummy_set_sv, - NULL); - object_property_add_enum(obj, "av", - "DummyAnimal", - dummy_animal_map, - dummy_get_av, - dummy_set_av, - NULL); } + +static void dummy_class_init(ObjectClass *cls, void *data) +{ + object_class_property_add_bool(cls, "bv", + dummy_get_bv, + dummy_set_bv, + NULL); + object_class_property_add_str(cls, "sv", + dummy_get_sv, + dummy_set_sv, + NULL); + object_class_property_add_enum(cls, "av", + "DummyAnimal", + dummy_animal_map, + dummy_get_av, + dummy_set_av, + NULL); +} + + static void dummy_finalize(Object *obj) { DummyObject *dobj = DUMMY_OBJECT(obj); @@ -150,6 +160,7 @@ static const TypeInfo dummy_info = { .instance_init = dummy_init, .instance_finalize = dummy_finalize, .class_size = sizeof(DummyObjectClass), + .class_init = dummy_class_init, }; From 7746abd8e9ee9db20c0b0fdb19504f163ba3cbea Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 9 Dec 2015 12:34:02 +0000 Subject: [PATCH 2/4] qom: Change object property iterator API contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the ObjectProperty iterator API works as follows: ObjectPropertyIterator *iter; iter = object_property_iter_init(obj); while ((prop = object_property_iter_next(iter))) { ... } object_property_iter_free(iter); This has the benefit that the ObjectPropertyIterator struct can be opaque, but has the downside that callers need to explicitly call a free function. It is also not in keeping with iterator style used elsewhere in QEMU/GLib2. This patch changes the API to use stack allocation instead: ObjectPropertyIterator iter; object_property_iter_init(&iter, obj); while ((prop = object_property_iter_next(&iter))) { ... } Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Reviewed-by: Markus Armbruster [AF: Fused ObjectPropertyIterator struct with typedef] Signed-off-by: Andreas Färber --- hw/ppc/spapr_drc.c | 7 +++---- include/qom/object.h | 30 ++++++++++++++---------------- net/filter.c | 7 +++---- qmp.c | 14 ++++++-------- qom/object.c | 22 ++++------------------ tests/check-qom-proplist.c | 7 +++---- vl.c | 7 +++---- 7 files changed, 36 insertions(+), 58 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 4fb86a68c4..dccb908c31 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -684,7 +684,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, { Object *root_container; ObjectProperty *prop; - ObjectPropertyIterator *iter; + ObjectPropertyIterator iter; uint32_t drc_count = 0; GArray *drc_indexes, *drc_power_domains; GString *drc_names, *drc_types; @@ -708,8 +708,8 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, */ root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); - iter = object_property_iter_init(root_container); - while ((prop = object_property_iter_next(iter))) { + object_property_iter_init(&iter, root_container); + while ((prop = object_property_iter_next(&iter))) { Object *obj; sPAPRDRConnector *drc; sPAPRDRConnectorClass *drck; @@ -750,7 +750,6 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, spapr_drc_get_type_str(drc->type)); drc_types = g_string_insert_len(drc_types, -1, "\0", 1); } - object_property_iter_free(iter); /* now write the drc count into the space we reserved at the * beginning of the arrays previously diff --git a/include/qom/object.h b/include/qom/object.h index 37d414a6bf..d0dafe986c 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -966,7 +966,10 @@ ObjectProperty *object_property_find(Object *obj, const char *name, ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, Error **errp); -typedef struct ObjectPropertyIterator ObjectPropertyIterator; +typedef struct ObjectPropertyIterator { + ObjectClass *nextclass; + GHashTableIter iter; +} ObjectPropertyIterator; /** * object_property_iter_init: @@ -984,32 +987,27 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; * Using object property iterators * * ObjectProperty *prop; - * ObjectPropertyIterator *iter; + * ObjectPropertyIterator iter; * - * iter = object_property_iter_init(obj); - * while ((prop = object_property_iter_next(iter))) { + * object_property_iter_init(&iter, obj); + * while ((prop = object_property_iter_next(&iter))) { * ... do something with prop ... * } - * object_property_iter_free(iter); * * - * - * Returns: the new iterator */ -ObjectPropertyIterator *object_property_iter_init(Object *obj); - -/** - * object_property_iter_free: - * @iter: the iterator instance - * - * Releases any resources associated with the iterator. - */ -void object_property_iter_free(ObjectPropertyIterator *iter); +void object_property_iter_init(ObjectPropertyIterator *iter, + Object *obj); /** * object_property_iter_next: * @iter: the iterator instance * + * Return the next available property. If no further properties + * are available, a %NULL value will be returned and the @iter + * pointer should not be used again after this point without + * re-initializing it. + * * Returns: the next property, or %NULL when all properties * have been traversed. */ diff --git a/net/filter.c b/net/filter.c index f777ba2899..5d90f83429 100644 --- a/net/filter.c +++ b/net/filter.c @@ -137,7 +137,7 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) Error *local_err = NULL; char *str, *info; ObjectProperty *prop; - ObjectPropertyIterator *iter; + ObjectPropertyIterator iter; StringOutputVisitor *ov; if (!nf->netdev_id) { @@ -174,8 +174,8 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); /* generate info str */ - iter = object_property_iter_init(OBJECT(nf)); - while ((prop = object_property_iter_next(iter))) { + object_property_iter_init(&iter, OBJECT(nf)); + while ((prop = object_property_iter_next(&iter))) { if (!strcmp(prop->name, "type")) { continue; } @@ -189,7 +189,6 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) g_free(str); g_free(info); } - object_property_iter_free(iter); } static void netfilter_finalize(Object *obj) diff --git a/qmp.c b/qmp.c index 0a1fa19925..3ff6db79b9 100644 --- a/qmp.c +++ b/qmp.c @@ -210,7 +210,7 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) bool ambiguous = false; ObjectPropertyInfoList *props = NULL; ObjectProperty *prop; - ObjectPropertyIterator *iter; + ObjectPropertyIterator iter; obj = object_resolve_path(path, &ambiguous); if (obj == NULL) { @@ -223,8 +223,8 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) return NULL; } - iter = object_property_iter_init(obj); - while ((prop = object_property_iter_next(iter))) { + object_property_iter_init(&iter, obj); + while ((prop = object_property_iter_next(&iter))) { ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry)); entry->value = g_malloc0(sizeof(ObjectPropertyInfo)); @@ -234,7 +234,6 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) entry->value->name = g_strdup(prop->name); entry->value->type = g_strdup(prop->type); } - object_property_iter_free(iter); return props; } @@ -506,7 +505,7 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, ObjectClass *klass; Object *obj; ObjectProperty *prop; - ObjectPropertyIterator *iter; + ObjectPropertyIterator iter; DevicePropertyInfoList *prop_list = NULL; klass = object_class_by_name(typename); @@ -535,8 +534,8 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, obj = object_new(typename); - iter = object_property_iter_init(obj); - while ((prop = object_property_iter_next(iter))) { + object_property_iter_init(&iter, obj); + while ((prop = object_property_iter_next(&iter))) { DevicePropertyInfo *info; DevicePropertyInfoList *entry; @@ -567,7 +566,6 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, entry->next = prop_list; prop_list = entry; } - object_property_iter_free(iter); object_unref(obj); diff --git a/qom/object.c b/qom/object.c index 5d4c80b102..5ff97ab91e 100644 --- a/qom/object.c +++ b/qom/object.c @@ -67,11 +67,6 @@ struct TypeImpl InterfaceImpl interfaces[MAX_INTERFACES]; }; -struct ObjectPropertyIterator { - ObjectClass *nextclass; - GHashTableIter iter; -}; - static Type type_interface; static GHashTable *type_table_get(void) @@ -999,20 +994,11 @@ ObjectProperty *object_property_find(Object *obj, const char *name, return NULL; } -ObjectPropertyIterator *object_property_iter_init(Object *obj) +void object_property_iter_init(ObjectPropertyIterator *iter, + Object *obj) { - ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); - g_hash_table_iter_init(&ret->iter, obj->properties); - ret->nextclass = object_get_class(obj); - return ret; -} - -void object_property_iter_free(ObjectPropertyIterator *iter) -{ - if (!iter) { - return; - } - g_free(iter); + g_hash_table_iter_init(&iter->iter, obj->properties); + iter->nextclass = object_get_class(obj); } ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 5167e78e93..448d270b68 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -455,11 +455,11 @@ static void test_dummy_iterator(void) NULL)); ObjectProperty *prop; - ObjectPropertyIterator *iter; + ObjectPropertyIterator iter; bool seenbv = false, seensv = false, seenav = false, seentype; - iter = object_property_iter_init(OBJECT(dobj)); - while ((prop = object_property_iter_next(iter))) { + object_property_iter_init(&iter, OBJECT(dobj)); + while ((prop = object_property_iter_next(&iter))) { if (g_str_equal(prop->name, "bv")) { seenbv = true; } else if (g_str_equal(prop->name, "sv")) { @@ -474,7 +474,6 @@ static void test_dummy_iterator(void) g_assert_not_reached(); } } - object_property_iter_free(iter); g_assert(seenbv); g_assert(seenav); g_assert(seensv); diff --git a/vl.c b/vl.c index b7a083eb56..f043009f67 100644 --- a/vl.c +++ b/vl.c @@ -1535,14 +1535,14 @@ MachineInfoList *qmp_query_machines(Error **errp) static int machine_help_func(QemuOpts *opts, MachineState *machine) { ObjectProperty *prop; - ObjectPropertyIterator *iter; + ObjectPropertyIterator iter; if (!qemu_opt_has_help_opt(opts)) { return 0; } - iter = object_property_iter_init(OBJECT(machine)); - while ((prop = object_property_iter_next(iter))) { + object_property_iter_init(&iter, OBJECT(machine)); + while ((prop = object_property_iter_next(&iter))) { if (!prop->set) { continue; } @@ -1555,7 +1555,6 @@ static int machine_help_func(QemuOpts *opts, MachineState *machine) error_printf("\n"); } } - object_property_iter_free(iter); return 1; } From abed886ec60cf239a03515cf0b30fb11fa964c44 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Oct 2015 13:11:39 +0200 Subject: [PATCH 3/4] qdev: Free QemuOpts when the QOM path goes away MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise there is a race where the DEVICE_DELETED event has been sent but attempts to reuse the ID will fail. Note that similar races exist for other QemuOpts, which this patch does not attempt to fix. For example, if the device is a block device, then unplugging it also deletes its backend. However, this backend's get deleted in drive_info_del(), which is only called when properties are destroyed. Just like device_finalize(), drive_info_del() is called some time after DEVICE_DELETED is sent. A separate patch series has been sent to plug this other bug. Character devices also have yet to be fixed. Reported-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini Reviewed-by: Markus Armbruster Signed-off-by: Andreas Färber --- hw/core/qdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2c7101d91d..44bf790b01 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -1206,7 +1206,6 @@ static void device_finalize(Object *obj) NamedGPIOList *ngl, *next; DeviceState *dev = DEVICE(obj); - qemu_opts_del(dev->opts); QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { QLIST_REMOVE(ngl, node); @@ -1254,6 +1253,9 @@ static void device_unparent(Object *obj) qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort); g_free(path); } + + qemu_opts_del(dev->opts); + dev->opts = NULL; } static void device_class_init(ObjectClass *class, void *data) From 300b115ce804cb6a20acc0003cc17687545b728d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 18 Jan 2016 18:19:35 +0100 Subject: [PATCH 4/4] MAINTAINERS: Fix sPAPR entry heading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_maintainers.pl does not handle parenthesis in maintenance areas well in connection with list emails (here: qemu-ppc@nongnu.org). Resolve a recurring CC issue breaking git-send-email by reverting part of commit 085eb217dfb3ee12e7985c11f71f8a038394735a ("Add David Gibson for sPAPR in MAINTAINERS file"). Cc: David Gibson Signed-off-by: Andreas Färber --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8f44dca48a..4030e2749d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -587,7 +587,7 @@ F: hw/ppc/prep.c F: hw/pci-host/prep.[hc] F: hw/isa/pc87312.[hc] -sPAPR (pseries) +sPAPR M: David Gibson M: Alexander Graf L: qemu-ppc@nongnu.org