* [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling @ 2015-10-13 12:37 Daniel P. Berrange 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration Daniel P. Berrange ` (8 more replies) 0 siblings, 9 replies; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber This patch series is a followup to v3: https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02024.html v2: https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg05953.html + https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg01455.html This series introduces a concept of object property iterators to QOM so callers are insulated from the specific data structures used for storing properties against objects/classes. It then converts Object to use a GHashTable for storing properties. Finally it introduces ObjectClass properties. Probably the only controversial thing is the item Pavel points out about object_child_foreach iterators now being forbidden from modifying the object composition tree. Changed in v4: - Create ObjectPropertyIterator struct to allow inline iteration, instead of using callback functions - Convert spapr and net filter code to new iterators too - Extend check-qom-proplist.c test to cover new iterators and class property usage Daniel P. Berrange (6): qom: introduce ObjectPropertyIterator struct for iteration qmp: convert QMP code to use object property iterators vl: convert machine help code to use object property iterators ppc: convert spapr code to use object property iterators net: convert net filter code to use object property iterators qom: allow properties to be registered against classes Pavel Fedin (1): qom: replace object property list with GHashTable hw/ppc/spapr_drc.c | 5 +- include/qom/object.h | 110 ++++++++++++++- net/filter.c | 5 +- qmp.c | 10 +- qom/object.c | 328 ++++++++++++++++++++++++++++++++++++++++----- tests/check-qom-proplist.c | 77 +++++++++-- vl.c | 5 +- 7 files changed, 485 insertions(+), 55 deletions(-) -- 2.4.3 ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-11-05 16:59 ` Andreas Färber 2015-11-17 15:25 ` Markus Armbruster 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators Daniel P. Berrange ` (7 subsequent siblings) 8 siblings, 2 replies; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber Some users of QOM need to be able to iterate over properties defined against an object instance. Currently they are just directly using the QTAIL macros against the object properties data structure. This is bad because it exposes them to changes in the data structure used to store properties, as well as changes in functionality such as ability to register properties against the class. This provides an ObjectPropertyIterator struct which will insulate the callers from the particular data structure used to store properties. It can be used thus ObjectProperty *prop; ObjectProperty *iter; iter = object_property_iter_init(obj); while ((prop = object_property_iter_next(iter))) { ... do something with prop ... } object_property_iter_free(iter); Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- include/qom/object.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 31 ++++++++++++++++++++++++++++ tests/check-qom-proplist.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index be7280c..761ffec 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -960,6 +960,56 @@ void object_property_del(Object *obj, const char *name, Error **errp); ObjectProperty *object_property_find(Object *obj, const char *name, Error **errp); +typedef struct ObjectPropertyIterator ObjectPropertyIterator; + +/** + * object_property_iter_init: + * @obj: the object + * + * Initializes an iterator for traversing all properties + * registered against an object instance. + * + * It is forbidden to modify the property list while iterating, + * whether removing or adding properties. + * + * Typical usage pattern would be + * + * <example> + * <title>Using object property iterators</title> + * <programlisting> + * ObjectProperty *prop; + * ObjectProperty *iter; + * + * iter = object_property_iter_init(obj); + * while ((prop = object_property_iter_next(iter))) { + * ... do something with prop ... + * } + * object_property_iter_free(iter); + * </programlisting> + * </example> + * + * Returns the new iterator + */ +ObjectPropertyIterator *object_property_iter_init(Object *obj); + + +/** + * object_property_iter_free: + * @iter: the iterator instance + * + * Release any resources associated with the iterator + */ +void object_property_iter_free(ObjectPropertyIterator *iter); + +/** + * object_property_iter_next: + * @iter: the iterator instance + * + * Returns the next property, or NULL when all properties + * have been traversed. + */ +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter); + void object_unparent(Object *obj); /** diff --git a/qom/object.c b/qom/object.c index 4805328..7dace59 100644 --- a/qom/object.c +++ b/qom/object.c @@ -67,6 +67,10 @@ struct TypeImpl InterfaceImpl interfaces[MAX_INTERFACES]; }; +struct ObjectPropertyIterator { + ObjectProperty *next; +}; + static Type type_interface; static GHashTable *type_table_get(void) @@ -917,6 +921,33 @@ ObjectProperty *object_property_find(Object *obj, const char *name, return NULL; } +ObjectPropertyIterator *object_property_iter_init(Object *obj) +{ + ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); + ret->next = QTAILQ_FIRST(&obj->properties); + return ret; +} + + +void object_property_iter_free(ObjectPropertyIterator *iter) +{ + if (!iter) { + return; + } + g_free(iter); +} + + +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) +{ + ObjectProperty *ret = iter->next; + if (ret) { + iter->next = QTAILQ_NEXT(iter->next, node); + } + return ret; +} + + void object_property_del(Object *obj, const char *name, Error **errp) { ObjectProperty *prop = object_property_find(obj, name, errp); diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 7400b1f..1be8b9e 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -283,6 +283,51 @@ static void test_dummy_getenum(void) &err); g_assert(err != NULL); error_free(err); + + object_unparent(OBJECT(dobj)); +} + + +static void test_dummy_iterator(void) +{ + Object *parent = object_get_objects_root(); + DummyObject *dobj = DUMMY_OBJECT( + object_new_with_props(TYPE_DUMMY, + parent, + "dummy0", + &error_abort, + "bv", "yes", + "sv", "Hiss hiss hiss", + "av", "platypus", + NULL)); + + ObjectProperty *prop; + ObjectPropertyIterator *iter; + bool seenbv = false, seensv = false, seenav = false, seentype; + + iter = object_property_iter_init(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")) { + seensv = true; + } else if (g_str_equal(prop->name, "av")) { + seenav = true; + } else if (g_str_equal(prop->name, "type")) { + /* This prop comes from the base Object class */ + seentype = true; + } else { + g_printerr("Found prop '%s'\n", prop->name); + g_assert_not_reached(); + } + } + object_property_iter_free(iter); + g_assert(seenbv); + g_assert(seenav); + g_assert(seensv); + g_assert(seentype); + + object_unparent(OBJECT(dobj)); } @@ -297,6 +342,7 @@ int main(int argc, char **argv) g_test_add_func("/qom/proplist/createv", test_dummy_createv); g_test_add_func("/qom/proplist/badenum", test_dummy_badenum); g_test_add_func("/qom/proplist/getenum", test_dummy_getenum); + g_test_add_func("/qom/proplist/iterator", test_dummy_iterator); return g_test_run(); } -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration Daniel P. Berrange @ 2015-11-05 16:59 ` Andreas Färber 2015-11-17 15:25 ` Markus Armbruster 1 sibling, 0 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-05 16:59 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel, Pavel Fedin Cc: Paolo Bonzini, Markus Armbruster Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > Some users of QOM need to be able to iterate over properties > defined against an object instance. Currently they are just > directly using the QTAIL macros against the object properties > data structure. > > This is bad because it exposes them to changes in the data > structure used to store properties, as well as changes in > functionality such as ability to register properties against > the class. > > This provides an ObjectPropertyIterator struct which will > insulate the callers from the particular data structure > used to store properties. It can be used thus > > ObjectProperty *prop; > ObjectProperty *iter; > > iter = object_property_iter_init(obj); > while ((prop = object_property_iter_next(iter))) { > ... do something with prop ... > } > object_property_iter_free(iter); > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > include/qom/object.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ > qom/object.c | 31 ++++++++++++++++++++++++++++ > tests/check-qom-proplist.c | 46 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 127 insertions(+) > > diff --git a/include/qom/object.h b/include/qom/object.h > index be7280c..761ffec 100644 > --- a/include/qom/object.h > +++ b/include/qom/object.h > @@ -960,6 +960,56 @@ void object_property_del(Object *obj, const char *name, Error **errp); > ObjectProperty *object_property_find(Object *obj, const char *name, > Error **errp); > > +typedef struct ObjectPropertyIterator ObjectPropertyIterator; > + > +/** > + * object_property_iter_init: > + * @obj: the object > + * > + * Initializes an iterator for traversing all properties > + * registered against an object instance. > + * > + * It is forbidden to modify the property list while iterating, > + * whether removing or adding properties. > + * > + * Typical usage pattern would be > + * > + * <example> > + * <title>Using object property iterators</title> > + * <programlisting> > + * ObjectProperty *prop; > + * ObjectProperty *iter; Shouldn't this be ObjectPropertyIterator? > + * > + * iter = object_property_iter_init(obj); > + * while ((prop = object_property_iter_next(iter))) { > + * ... do something with prop ... > + * } > + * object_property_iter_free(iter); > + * </programlisting> > + * </example> > + * > + * Returns the new iterator Returns: > + */ > +ObjectPropertyIterator *object_property_iter_init(Object *obj); > + > + Intentionally two lines here? > +/** > + * object_property_iter_free: > + * @iter: the iterator instance > + * > + * Release any resources associated with the iterator Releases ... full stop. > + */ > +void object_property_iter_free(ObjectPropertyIterator *iter); > + > +/** > + * object_property_iter_next: > + * @iter: the iterator instance > + * > + * Returns the next property, or NULL when all properties %NULL > + * have been traversed. > + */ > +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter); > + > void object_unparent(Object *obj); > > /** > diff --git a/qom/object.c b/qom/object.c > index 4805328..7dace59 100644 > --- a/qom/object.c > +++ b/qom/object.c > @@ -67,6 +67,10 @@ struct TypeImpl > InterfaceImpl interfaces[MAX_INTERFACES]; > }; > > +struct ObjectPropertyIterator { > + ObjectProperty *next; > +}; > + > static Type type_interface; > > static GHashTable *type_table_get(void) > @@ -917,6 +921,33 @@ ObjectProperty *object_property_find(Object *obj, const char *name, > return NULL; > } > > +ObjectPropertyIterator *object_property_iter_init(Object *obj) > +{ > + ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); > + ret->next = QTAILQ_FIRST(&obj->properties); > + return ret; > +} > + > + > +void object_property_iter_free(ObjectPropertyIterator *iter) > +{ > + if (!iter) { > + return; > + } > + g_free(iter); > +} > + > + > +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) > +{ > + ObjectProperty *ret = iter->next; > + if (ret) { > + iter->next = QTAILQ_NEXT(iter->next, node); > + } > + return ret; > +} > + > + ? > void object_property_del(Object *obj, const char *name, Error **errp) > { > ObjectProperty *prop = object_property_find(obj, name, errp); > diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c > index 7400b1f..1be8b9e 100644 > --- a/tests/check-qom-proplist.c > +++ b/tests/check-qom-proplist.c > @@ -283,6 +283,51 @@ static void test_dummy_getenum(void) > &err); > g_assert(err != NULL); > error_free(err); > + > + object_unparent(OBJECT(dobj)); > +} > + > + > +static void test_dummy_iterator(void) > +{ > + Object *parent = object_get_objects_root(); > + DummyObject *dobj = DUMMY_OBJECT( > + object_new_with_props(TYPE_DUMMY, > + parent, > + "dummy0", > + &error_abort, > + "bv", "yes", > + "sv", "Hiss hiss hiss", > + "av", "platypus", > + NULL)); > + > + ObjectProperty *prop; > + ObjectPropertyIterator *iter; > + bool seenbv = false, seensv = false, seenav = false, seentype; > + > + iter = object_property_iter_init(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")) { > + seensv = true; > + } else if (g_str_equal(prop->name, "av")) { > + seenav = true; > + } else if (g_str_equal(prop->name, "type")) { > + /* This prop comes from the base Object class */ > + seentype = true; > + } else { > + g_printerr("Found prop '%s'\n", prop->name); > + g_assert_not_reached(); > + } > + } > + object_property_iter_free(iter); > + g_assert(seenbv); > + g_assert(seenav); > + g_assert(seensv); > + g_assert(seentype); > + > + object_unparent(OBJECT(dobj)); > } > > > @@ -297,6 +342,7 @@ int main(int argc, char **argv) > g_test_add_func("/qom/proplist/createv", test_dummy_createv); > g_test_add_func("/qom/proplist/badenum", test_dummy_badenum); > g_test_add_func("/qom/proplist/getenum", test_dummy_getenum); > + g_test_add_func("/qom/proplist/iterator", test_dummy_iterator); > > return g_test_run(); > } Pavel, note that any of you could've found such issues or at least provided a Reviewed-by rather than just pinging. Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration Daniel P. Berrange 2015-11-05 16:59 ` Andreas Färber @ 2015-11-17 15:25 ` Markus Armbruster 2015-11-17 15:27 ` Daniel P. Berrange 1 sibling, 1 reply; 41+ messages in thread From: Markus Armbruster @ 2015-11-17 15:25 UTC (permalink / raw) To: Daniel P. Berrange Cc: Paolo Bonzini, Pavel Fedin, qemu-devel, Andreas Färber I apologize for the lateness of my review. "Daniel P. Berrange" <berrange@redhat.com> writes: > Some users of QOM need to be able to iterate over properties > defined against an object instance. Currently they are just > directly using the QTAIL macros against the object properties > data structure. > > This is bad because it exposes them to changes in the data > structure used to store properties, as well as changes in > functionality such as ability to register properties against > the class. > > This provides an ObjectPropertyIterator struct which will > insulate the callers from the particular data structure > used to store properties. It can be used thus > > ObjectProperty *prop; > ObjectProperty *iter; ObjectPropertyIterator *iter; > > iter = object_property_iter_init(obj); > while ((prop = object_property_iter_next(iter))) { > ... do something with prop ... > } > object_property_iter_free(iter); This is a sane way to do iterators. It combines allocation and initialization, thus requires a free. The name _init() suggests it doesn't, but that's easy enough to fix. I can't find precedence for this way in the tree, however. Another way is ObjectProperty *prop; ObjectPropertyIterator iter; object_property_iter_init(&iter, obj); while ((prop = object_property_iter_next(iter))) { ... do something with prop ... } object_property_iter_fini(iter); // usually not needed Leaves allocation to the caller, which makes it more flexible. Automartic iter often suffices, and can't leak. The _fini() is commonly empty and left out. Precedence: * hbitmap_iter_init() and hbitmap_iter_next() * g_hash_table_iter_init() and g_hash_table_iter_next(), except the latter is a bit different because it returns two values Yet another one is for (prop = object_property_first(obj); prop; prop = object_property_next(prop)) { ... do something with prop ... } This works only when the iterator state is exactly what the _next() returns. Happens to be the case often enough. Here, too, but perhaps you have reasons to prepare for more complex state. Precedence: * qdict_first(), qdict_next() * vma_first(), vma_next() * ... Related: bdrv_next(), blk_next(), ... These guys omit _first() because the set to iterate over is implied. I recommend to pick the precedence you like best for this purpose and follow it. > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > include/qom/object.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ > qom/object.c | 31 ++++++++++++++++++++++++++++ > tests/check-qom-proplist.c | 46 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 127 insertions(+) > > diff --git a/include/qom/object.h b/include/qom/object.h > index be7280c..761ffec 100644 > --- a/include/qom/object.h > +++ b/include/qom/object.h > @@ -960,6 +960,56 @@ void object_property_del(Object *obj, const char *name, Error **errp); > ObjectProperty *object_property_find(Object *obj, const char *name, > Error **errp); > > +typedef struct ObjectPropertyIterator ObjectPropertyIterator; > + > +/** > + * object_property_iter_init: > + * @obj: the object > + * > + * Initializes an iterator for traversing all properties > + * registered against an object instance. > + * > + * It is forbidden to modify the property list while iterating, > + * whether removing or adding properties. > + * > + * Typical usage pattern would be > + * > + * <example> > + * <title>Using object property iterators</title> > + * <programlisting> > + * ObjectProperty *prop; > + * ObjectProperty *iter; > + * > + * iter = object_property_iter_init(obj); > + * while ((prop = object_property_iter_next(iter))) { > + * ... do something with prop ... > + * } > + * object_property_iter_free(iter); > + * </programlisting> > + * </example> > + * > + * Returns the new iterator > + */ > +ObjectPropertyIterator *object_property_iter_init(Object *obj); > + > + > +/** > + * object_property_iter_free: > + * @iter: the iterator instance > + * > + * Release any resources associated with the iterator > + */ > +void object_property_iter_free(ObjectPropertyIterator *iter); > + > +/** > + * object_property_iter_next: > + * @iter: the iterator instance > + * > + * Returns the next property, or NULL when all properties > + * have been traversed. > + */ > +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter); > + > void object_unparent(Object *obj); > > /** > diff --git a/qom/object.c b/qom/object.c > index 4805328..7dace59 100644 > --- a/qom/object.c > +++ b/qom/object.c > @@ -67,6 +67,10 @@ struct TypeImpl > InterfaceImpl interfaces[MAX_INTERFACES]; > }; > > +struct ObjectPropertyIterator { > + ObjectProperty *next; > +}; > + > static Type type_interface; > > static GHashTable *type_table_get(void) > @@ -917,6 +921,33 @@ ObjectProperty *object_property_find(Object *obj, const char *name, > return NULL; > } > > +ObjectPropertyIterator *object_property_iter_init(Object *obj) > +{ > + ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); > + ret->next = QTAILQ_FIRST(&obj->properties); > + return ret; > +} > + > + > +void object_property_iter_free(ObjectPropertyIterator *iter) > +{ > + if (!iter) { > + return; > + } > + g_free(iter); g_free(NULL) is perfectly safe; please drop the conditional. > +} > + > + > +ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) > +{ > + ObjectProperty *ret = iter->next; > + if (ret) { > + iter->next = QTAILQ_NEXT(iter->next, node); > + } > + return ret; > +} > + > + > void object_property_del(Object *obj, const char *name, Error **errp) > { > ObjectProperty *prop = object_property_find(obj, name, errp); [...] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration 2015-11-17 15:25 ` Markus Armbruster @ 2015-11-17 15:27 ` Daniel P. Berrange 2015-11-17 15:35 ` Markus Armbruster 0 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-11-17 15:27 UTC (permalink / raw) To: Markus Armbruster Cc: Paolo Bonzini, Pavel Fedin, qemu-devel, Andreas Färber On Tue, Nov 17, 2015 at 04:25:22PM +0100, Markus Armbruster wrote: > I apologize for the lateness of my review. > > +void object_property_iter_free(ObjectPropertyIterator *iter) > > +{ > > + if (!iter) { > > + return; > > + } > > + g_free(iter); > > g_free(NULL) is perfectly safe; please drop the conditional. The next patch in the series has to free some fields in 'iter' so the check for NULL upfront is not redundant. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration 2015-11-17 15:27 ` Daniel P. Berrange @ 2015-11-17 15:35 ` Markus Armbruster 0 siblings, 0 replies; 41+ messages in thread From: Markus Armbruster @ 2015-11-17 15:35 UTC (permalink / raw) To: Daniel P. Berrange Cc: Paolo Bonzini, Pavel Fedin, qemu-devel, Andreas Färber "Daniel P. Berrange" <berrange@redhat.com> writes: > On Tue, Nov 17, 2015 at 04:25:22PM +0100, Markus Armbruster wrote: >> I apologize for the lateness of my review. > >> > +void object_property_iter_free(ObjectPropertyIterator *iter) >> > +{ >> > + if (!iter) { >> > + return; >> > + } >> > + g_free(iter); >> >> g_free(NULL) is perfectly safe; please drop the conditional. > > The next patch in the series has to free some fields in 'iter' > so the check for NULL upfront is not redundant. I'd add the conditional when it's actually needed, not least to avoid comments from picky reviewers like myself ;) Anyway, not worth a respin by itself. However, I'd very much prefer the iterators to follow precedence in the tree. ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-11-05 17:08 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 3/7] vl: convert machine help " Daniel P. Berrange ` (6 subsequent siblings) 8 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber Stop directly accessing the Object "properties" field data structure and instead use the formal object property iterator APIs. This insulates the code from future data structure changes in the Object struct. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- qmp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/qmp.c b/qmp.c index d9ecede..5d99439 100644 --- a/qmp.c +++ b/qmp.c @@ -208,6 +208,7 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) bool ambiguous = false; ObjectPropertyInfoList *props = NULL; ObjectProperty *prop; + ObjectPropertyIterator *iter; obj = object_resolve_path(path, &ambiguous); if (obj == NULL) { @@ -220,7 +221,8 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) return NULL; } - QTAILQ_FOREACH(prop, &obj->properties, node) { + iter = object_property_iter_init(obj); + while ((prop = object_property_iter_next(iter))) { ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry)); entry->value = g_malloc0(sizeof(ObjectPropertyInfo)); @@ -230,6 +232,7 @@ 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; } @@ -500,6 +503,7 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, ObjectClass *klass; Object *obj; ObjectProperty *prop; + ObjectPropertyIterator *iter; DevicePropertyInfoList *prop_list = NULL; klass = object_class_by_name(typename); @@ -528,7 +532,8 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, obj = object_new(typename); - QTAILQ_FOREACH(prop, &obj->properties, node) { + iter = object_property_iter_init(obj); + while ((prop = object_property_iter_next(iter))) { DevicePropertyInfo *info; DevicePropertyInfoList *entry; @@ -559,6 +564,7 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, entry->next = prop_list; prop_list = entry; } + object_property_iter_free(iter); object_unref(obj); -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators Daniel P. Berrange @ 2015-11-05 17:08 ` Andreas Färber 2015-11-17 15:26 ` Markus Armbruster 0 siblings, 1 reply; 41+ messages in thread From: Andreas Färber @ 2015-11-05 17:08 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel, Markus Armbruster, Luiz Capitulino Cc: Paolo Bonzini, Pavel Fedin Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > Stop directly accessing the Object "properties" field data > structure and instead use the formal object property iterator > APIs. This insulates the code from future data structure > changes in the Object struct. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > qmp.c | 10 ++++++++-- > 1 file changed, 8 insertions(+), 2 deletions(-) Reviewed-by: Andreas Färber <afaerber@suse.de> Markus/Luiz, can you ack this change? Markus requested these iterators, I believe. Thanks, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators 2015-11-05 17:08 ` Andreas Färber @ 2015-11-17 15:26 ` Markus Armbruster 0 siblings, 0 replies; 41+ messages in thread From: Markus Armbruster @ 2015-11-17 15:26 UTC (permalink / raw) To: Andreas Färber Cc: Paolo Bonzini, Pavel Fedin, qemu-devel, Luiz Capitulino Andreas Färber <afaerber@suse.de> writes: > Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: >> Stop directly accessing the Object "properties" field data >> structure and instead use the formal object property iterator >> APIs. This insulates the code from future data structure >> changes in the Object struct. >> >> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> >> --- >> qmp.c | 10 ++++++++-- >> 1 file changed, 8 insertions(+), 2 deletions(-) > > Reviewed-by: Andreas Färber <afaerber@suse.de> > > Markus/Luiz, can you ack this change? Markus requested these iterators, > I believe. See my review of PATCH 1. ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 3/7] vl: convert machine help code to use object property iterators 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration Daniel P. Berrange 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-11-05 17:10 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 4/7] ppc: convert spapr " Daniel P. Berrange ` (5 subsequent siblings) 8 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber Stop directly accessing the Object "properties" field data structure and instead use the formal object property iterator APIs. This insulates the code from future data structure changes in the Object struct. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- vl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 7c806a2..81844ea 100644 --- a/vl.c +++ b/vl.c @@ -1514,12 +1514,14 @@ MachineInfoList *qmp_query_machines(Error **errp) static int machine_help_func(QemuOpts *opts, MachineState *machine) { ObjectProperty *prop; + ObjectPropertyIterator *iter; if (!qemu_opt_has_help_opt(opts)) { return 0; } - QTAILQ_FOREACH(prop, &OBJECT(machine)->properties, node) { + iter = object_property_iter_init(OBJECT(machine)); + while ((prop = object_property_iter_next(iter))) { if (!prop->set) { continue; } @@ -1532,6 +1534,7 @@ static int machine_help_func(QemuOpts *opts, MachineState *machine) error_printf("\n"); } } + object_property_iter_free(iter); return 1; } -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 3/7] vl: convert machine help code to use object property iterators 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 3/7] vl: convert machine help " Daniel P. Berrange @ 2015-11-05 17:10 ` Andreas Färber 0 siblings, 0 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-05 17:10 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel Cc: Paolo Bonzini, Pavel Fedin, Markus Armbruster Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > Stop directly accessing the Object "properties" field data > structure and instead use the formal object property iterator > APIs. This insulates the code from future data structure > changes in the Object struct. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > vl.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) Reviewed-by: Andreas Färber <afaerber@suse.de> Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 4/7] ppc: convert spapr code to use object property iterators 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange ` (2 preceding siblings ...) 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 3/7] vl: convert machine help " Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-11-05 17:16 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 5/7] net: convert net filter " Daniel P. Berrange ` (4 subsequent siblings) 8 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber Stop directly accessing the Object "properties" field data structure and instead use the formal object property iterator APIs. This insulates the code from future data structure changes in the Object struct. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- hw/ppc/spapr_drc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 5d6ea7c..f34bc04 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -657,6 +657,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, { Object *root_container; ObjectProperty *prop; + ObjectPropertyIterator *iter; uint32_t drc_count = 0; GArray *drc_indexes, *drc_power_domains; GString *drc_names, *drc_types; @@ -680,7 +681,8 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, */ root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); - QTAILQ_FOREACH(prop, &root_container->properties, node) { + iter = object_property_iter_init(root_container); + while ((prop = object_property_iter_next(iter))) { Object *obj; sPAPRDRConnector *drc; sPAPRDRConnectorClass *drck; @@ -721,6 +723,7 @@ 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 -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 4/7] ppc: convert spapr code to use object property iterators 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 4/7] ppc: convert spapr " Daniel P. Berrange @ 2015-11-05 17:16 ` Andreas Färber 0 siblings, 0 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-05 17:16 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel Cc: qemu-ppc, Paolo Bonzini, Pavel Fedin, Markus Armbruster, David Gibson Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > Stop directly accessing the Object "properties" field data Object::properties data structure for short. > structure and instead use the formal object property iterator > APIs. This insulates the code from future data structure > changes in the Object struct. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > hw/ppc/spapr_drc.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c > index 5d6ea7c..f34bc04 100644 > --- a/hw/ppc/spapr_drc.c > +++ b/hw/ppc/spapr_drc.c > @@ -657,6 +657,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, > { > Object *root_container; > ObjectProperty *prop; > + ObjectPropertyIterator *iter; > uint32_t drc_count = 0; > GArray *drc_indexes, *drc_power_domains; > GString *drc_names, *drc_types; > @@ -680,7 +681,8 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, > */ > root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); > > - QTAILQ_FOREACH(prop, &root_container->properties, node) { > + iter = object_property_iter_init(root_container); > + while ((prop = object_property_iter_next(iter))) { > Object *obj; > sPAPRDRConnector *drc; > sPAPRDRConnectorClass *drck; > @@ -721,6 +723,7 @@ 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 Reviewed-by: Andreas Färber <afaerber@suse.de> CC'ing PPC for ack. Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 5/7] net: convert net filter code to use object property iterators 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange ` (3 preceding siblings ...) 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 4/7] ppc: convert spapr " Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-11-05 17:18 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable Daniel P. Berrange ` (3 subsequent siblings) 8 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber Stop directly accessing the Object "properties" field data structure and instead use the formal object property iterator APIs. This insulates the code from future data structure changes in the Object struct. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- net/filter.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/filter.c b/net/filter.c index 326f2b5..1365bad 100644 --- a/net/filter.c +++ b/net/filter.c @@ -137,6 +137,7 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) Error *local_err = NULL; char *str, *info; ObjectProperty *prop; + ObjectPropertyIterator *iter; StringOutputVisitor *ov; if (!nf->netdev_id) { @@ -173,7 +174,8 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); /* generate info str */ - QTAILQ_FOREACH(prop, &OBJECT(nf)->properties, node) { + iter = object_property_iter_init(OBJECT(nf)); + while ((prop = object_property_iter_next(iter))) { if (!strcmp(prop->name, "type")) { continue; } @@ -187,6 +189,7 @@ 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) -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 5/7] net: convert net filter code to use object property iterators 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 5/7] net: convert net filter " Daniel P. Berrange @ 2015-11-05 17:18 ` Andreas Färber 0 siblings, 0 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-05 17:18 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel Cc: Paolo Bonzini, Pavel Fedin, Markus Armbruster, Stefan Hajnoczi Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > Stop directly accessing the Object "properties" field data Object::properties data ... > structure and instead use the formal object property iterator > APIs. This insulates the code from future data structure > changes in the Object struct. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > --- > net/filter.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/net/filter.c b/net/filter.c > index 326f2b5..1365bad 100644 > --- a/net/filter.c > +++ b/net/filter.c > @@ -137,6 +137,7 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) > Error *local_err = NULL; > char *str, *info; > ObjectProperty *prop; > + ObjectPropertyIterator *iter; > StringOutputVisitor *ov; > > if (!nf->netdev_id) { > @@ -173,7 +174,8 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) > QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); > > /* generate info str */ > - QTAILQ_FOREACH(prop, &OBJECT(nf)->properties, node) { > + iter = object_property_iter_init(OBJECT(nf)); > + while ((prop = object_property_iter_next(iter))) { > if (!strcmp(prop->name, "type")) { > continue; > } > @@ -187,6 +189,7 @@ 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) Reviewed-by: Andreas Färber <afaerber@suse.de> CC'ing Stefan. Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange ` (4 preceding siblings ...) 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 5/7] net: convert net filter " Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-11-05 18:05 ` Andreas Färber 2015-11-13 18:14 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes Daniel P. Berrange ` (2 subsequent siblings) 8 siblings, 2 replies; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber From: Pavel Fedin <p.fedin@samsung.com> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since every pin is represented as a property, number of these properties becomes very large. Every property add first makes sure there's no duplicates. Traversing the list becomes very slow, therefore qemu initialization takes significant time (several seconds for e. g. 16 CPUs). This patch replaces list with GHashTable, making lookup very fast. The only drawback is that object_child_foreach() and object_child_foreach_recursive() cannot modify their objects during traversal, since GHashTableIter does not have modify-safe version. However, the code seems not to modify objects via these functions. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> --- include/qom/object.h | 10 ++++-- qom/object.c | 98 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 64 insertions(+), 44 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 761ffec..2a54515 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -344,8 +344,6 @@ typedef struct ObjectProperty ObjectPropertyResolve *resolve; ObjectPropertyRelease *release; void *opaque; - - QTAILQ_ENTRY(ObjectProperty) node; } ObjectProperty; /** @@ -405,7 +403,7 @@ struct Object /*< private >*/ ObjectClass *class; ObjectFree *free; - QTAILQ_HEAD(, ObjectProperty) properties; + GHashTable *properties; uint32_t ref; Object *parent; }; @@ -1538,6 +1536,9 @@ void object_property_set_description(Object *obj, const char *name, * Call @fn passing each child of @obj and @opaque to it, until @fn returns * non-zero. * + * It is forbidden to add or remove children from @obj from the @fn + * callback. + * * Returns: The last value returned by @fn, or 0 if there is no child. */ int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), @@ -1553,6 +1554,9 @@ int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), * non-zero. Calls recursively, all child nodes of @obj will also be passed * all the way down to the leaf nodes of the tree. Depth first ordering. * + * It is forbidden to add or remove children from @obj (or its + * child nodes) from the @fn callback. + * * Returns: The last value returned by @fn, or 0 if there is no child. */ int object_child_foreach_recursive(Object *obj, diff --git a/qom/object.c b/qom/object.c index 7dace59..dd01652 100644 --- a/qom/object.c +++ b/qom/object.c @@ -68,7 +68,7 @@ struct TypeImpl }; struct ObjectPropertyIterator { - ObjectProperty *next; + GHashTableIter iter; }; static Type type_interface; @@ -330,6 +330,16 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) } } +static void 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; @@ -344,7 +354,8 @@ void object_initialize_with_type(void *data, size_t size, TypeImpl *type) memset(obj, 0, type->instance_size); obj->class = type->class; object_ref(obj); - QTAILQ_INIT(&obj->properties); + obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, property_free); object_init_with_type(obj, type); object_post_init_with_type(obj, type); } @@ -363,29 +374,35 @@ static inline bool object_property_is_child(ObjectProperty *prop) static void object_property_del_all(Object *obj) { - while (!QTAILQ_EMPTY(&obj->properties)) { - ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); - - QTAILQ_REMOVE(&obj->properties, prop, node); + ObjectProperty *prop; + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; if (prop->release) { prop->release(obj, prop->name, prop->opaque); } - - g_free(prop->name); - g_free(prop->type); - g_free(prop->description); - g_free(prop); } + + g_hash_table_unref(obj->properties); } static void object_property_del_child(Object *obj, Object *child, Error **errp) { ObjectProperty *prop; + GHashTableIter iter; + gpointer key, value; - QTAILQ_FOREACH(prop, &obj->properties, node) { + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; if (object_property_is_child(prop) && prop->opaque == child) { - object_property_del(obj, prop->name, errp); + if (prop->release) { + prop->release(obj, prop->name, prop->opaque); + } + g_hash_table_iter_remove(&iter); break; } } @@ -783,10 +800,12 @@ static int do_object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), void *opaque, bool recurse) { - ObjectProperty *prop, *next; + GHashTableIter iter; + ObjectProperty *prop; int ret = 0; - QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) { + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { if (object_property_is_child(prop)) { Object *child = prop->opaque; @@ -883,13 +902,11 @@ object_property_add(Object *obj, const char *name, const char *type, return ret; } - QTAILQ_FOREACH(prop, &obj->properties, node) { - if (strcmp(prop->name, name) == 0) { - error_setg(errp, "attempt to add duplicate property '%s'" + if (g_hash_table_contains(obj->properties, name)) { + error_setg(errp, "attempt to add duplicate property '%s'" " to object (type '%s')", name, object_get_typename(obj)); - return NULL; - } + return NULL; } prop = g_malloc0(sizeof(*prop)); @@ -902,7 +919,7 @@ object_property_add(Object *obj, const char *name, const char *type, prop->release = release; prop->opaque = opaque; - QTAILQ_INSERT_TAIL(&obj->properties, prop, node); + g_hash_table_insert(obj->properties, prop->name, prop); return prop; } @@ -911,10 +928,9 @@ ObjectProperty *object_property_find(Object *obj, const char *name, { ObjectProperty *prop; - QTAILQ_FOREACH(prop, &obj->properties, node) { - if (strcmp(prop->name, name) == 0) { - return prop; - } + prop = g_hash_table_lookup(obj->properties, name); + if (prop) { + return prop; } error_setg(errp, "Property '.%s' not found", name); @@ -924,7 +940,7 @@ ObjectProperty *object_property_find(Object *obj, const char *name, ObjectPropertyIterator *object_property_iter_init(Object *obj) { ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); - ret->next = QTAILQ_FIRST(&obj->properties); + g_hash_table_iter_init(&ret->iter, obj->properties); return ret; } @@ -940,31 +956,27 @@ void object_property_iter_free(ObjectPropertyIterator *iter) ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) { - ObjectProperty *ret = iter->next; - if (ret) { - iter->next = QTAILQ_NEXT(iter->next, node); + gpointer key, val; + if (!g_hash_table_iter_next(&iter->iter, &key, &val)) { + return NULL; } - return ret; + return val; } void object_property_del(Object *obj, const char *name, Error **errp) { - ObjectProperty *prop = object_property_find(obj, name, errp); - if (prop == NULL) { + ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); + + if (!prop) { + error_setg(errp, "Property '.%s' not found", name); return; } if (prop->release) { prop->release(obj, name, prop->opaque); } - - QTAILQ_REMOVE(&obj->properties, prop, node); - - g_free(prop->name); - g_free(prop->type); - g_free(prop->description); - g_free(prop); + g_hash_table_remove(obj->properties, name); } void object_property_get(Object *obj, Visitor *v, const char *name, @@ -1484,11 +1496,13 @@ void object_property_add_const_link(Object *obj, const char *name, gchar *object_get_canonical_path_component(Object *obj) { ObjectProperty *prop = NULL; + GHashTableIter iter; g_assert(obj); g_assert(obj->parent != NULL); - QTAILQ_FOREACH(prop, &obj->parent->properties, node) { + g_hash_table_iter_init(&iter, obj->parent->properties); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { if (!object_property_is_child(prop)) { continue; } @@ -1572,11 +1586,13 @@ static Object *object_resolve_partial_path(Object *parent, bool *ambiguous) { Object *obj; + GHashTableIter iter; ObjectProperty *prop; obj = object_resolve_abs_path(parent, parts, typename, 0); - QTAILQ_FOREACH(prop, &parent->properties, node) { + g_hash_table_iter_init(&iter, parent->properties); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { Object *found; if (!object_property_is_child(prop)) { -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable Daniel P. Berrange @ 2015-11-05 18:05 ` Andreas Färber 2015-11-06 9:02 ` Pavel Fedin 2015-11-06 9:31 ` Daniel P. Berrange 2015-11-13 18:14 ` Andreas Färber 1 sibling, 2 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-05 18:05 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel, Pavel Fedin, Markus Armbruster Cc: Paolo Bonzini Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > From: Pavel Fedin <p.fedin@samsung.com> > > ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since > every pin is represented as a property, number of these properties becomes > very large. Every property add first makes sure there's no duplicates. > Traversing the list becomes very slow, therefore qemu initialization takes > significant time (several seconds for e. g. 16 CPUs). > > This patch replaces list with GHashTable, making lookup very fast. The only > drawback is that object_child_foreach() and object_child_foreach_recursive() > cannot modify their objects during traversal, since GHashTableIter does not > have modify-safe version. However, the code seems not to modify objects via > these functions. "modify objects" seems a little misleading here; from what I see only adding or removing properties (including child<>s) is forbidden, right? Modifying one ObjectProperty or its value should still be okay. I believe that limitation is fine. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > Signed-off-by: Pavel Fedin <p.fedin@samsung.com> > --- > include/qom/object.h | 10 ++++-- > qom/object.c | 98 ++++++++++++++++++++++++++++++---------------------- > 2 files changed, 64 insertions(+), 44 deletions(-) [...] > diff --git a/qom/object.c b/qom/object.c > index 7dace59..dd01652 100644 > --- a/qom/object.c > +++ b/qom/object.c > @@ -68,7 +68,7 @@ struct TypeImpl > }; > > struct ObjectPropertyIterator { > - ObjectProperty *next; > + GHashTableIter iter; > }; > > static Type type_interface; > @@ -330,6 +330,16 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) > } > } > > +static void property_free(gpointer data) Bikeshed: We might call this object_property_free() unless there's a precedence for property_...? > +{ > + 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; [...] > @@ -363,29 +374,35 @@ static inline bool object_property_is_child(ObjectProperty *prop) > > static void object_property_del_all(Object *obj) > { > - while (!QTAILQ_EMPTY(&obj->properties)) { > - ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); > - > - QTAILQ_REMOVE(&obj->properties, prop, node); > + ObjectProperty *prop; > + GHashTableIter iter; > + gpointer key, value; > > + g_hash_table_iter_init(&iter, obj->properties); > + while (g_hash_table_iter_next(&iter, &key, &value)) { > + prop = value; > if (prop->release) { > prop->release(obj, prop->name, prop->opaque); > } Why is this not in property_free(), too? Is there a timing difference? > - > - g_free(prop->name); > - g_free(prop->type); > - g_free(prop->description); > - g_free(prop); > } > + > + g_hash_table_unref(obj->properties); > } > > static void object_property_del_child(Object *obj, Object *child, Error **errp) > { > ObjectProperty *prop; > + GHashTableIter iter; > + gpointer key, value; > > - QTAILQ_FOREACH(prop, &obj->properties, node) { > + g_hash_table_iter_init(&iter, obj->properties); > + while (g_hash_table_iter_next(&iter, &key, &value)) { > + prop = value; > if (object_property_is_child(prop) && prop->opaque == child) { > - object_property_del(obj, prop->name, errp); > + if (prop->release) { > + prop->release(obj, prop->name, prop->opaque); > + } Ditto? > + g_hash_table_iter_remove(&iter); > break; > } > } [...] > @@ -924,7 +940,7 @@ ObjectProperty *object_property_find(Object *obj, const char *name, > ObjectPropertyIterator *object_property_iter_init(Object *obj) > { > ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); > - ret->next = QTAILQ_FIRST(&obj->properties); > + g_hash_table_iter_init(&ret->iter, obj->properties); > return ret; > } > Is it intentional that our iterator pattern differs? > @@ -940,31 +956,27 @@ void object_property_iter_free(ObjectPropertyIterator *iter) > > ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) > { > - ObjectProperty *ret = iter->next; > - if (ret) { > - iter->next = QTAILQ_NEXT(iter->next, node); > + gpointer key, val; > + if (!g_hash_table_iter_next(&iter->iter, &key, &val)) { > + return NULL; > } > - return ret; > + return val; > } > > > void object_property_del(Object *obj, const char *name, Error **errp) > { > - ObjectProperty *prop = object_property_find(obj, name, errp); > - if (prop == NULL) { > + ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); > + > + if (!prop) { > + error_setg(errp, "Property '.%s' not found", name); Is this a behavioral change? > return; > } > > if (prop->release) { > prop->release(obj, name, prop->opaque); > } property_free()? > - > - QTAILQ_REMOVE(&obj->properties, prop, node); > - > - g_free(prop->name); > - g_free(prop->type); > - g_free(prop->description); > - g_free(prop); > + g_hash_table_remove(obj->properties, name); > } > > void object_property_get(Object *obj, Visitor *v, const char *name, > @@ -1484,11 +1496,13 @@ void object_property_add_const_link(Object *obj, const char *name, > gchar *object_get_canonical_path_component(Object *obj) > { > ObjectProperty *prop = NULL; > + GHashTableIter iter; > > g_assert(obj); > g_assert(obj->parent != NULL); > > - QTAILQ_FOREACH(prop, &obj->parent->properties, node) { > + g_hash_table_iter_init(&iter, obj->parent->properties); > + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { Is this cast needed? > if (!object_property_is_child(prop)) { > continue; > } > @@ -1572,11 +1586,13 @@ static Object *object_resolve_partial_path(Object *parent, > bool *ambiguous) > { > Object *obj; > + GHashTableIter iter; > ObjectProperty *prop; > > obj = object_resolve_abs_path(parent, parts, typename, 0); > > - QTAILQ_FOREACH(prop, &parent->properties, node) { > + g_hash_table_iter_init(&iter, parent->properties); > + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { Ditto? > Object *found; > > if (!object_property_is_child(prop)) { Otherwise looks very good, but third pair of eyes appreciated (Markus?). Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-05 18:05 ` Andreas Färber @ 2015-11-06 9:02 ` Pavel Fedin 2015-11-06 9:31 ` Daniel P. Berrange 1 sibling, 0 replies; 41+ messages in thread From: Pavel Fedin @ 2015-11-06 9:02 UTC (permalink / raw) To: 'Andreas Färber', 'Daniel P. Berrange', qemu-devel, 'Markus Armbruster' Cc: 'Paolo Bonzini' Hello! > > static void object_property_del_all(Object *obj) > > { > > - while (!QTAILQ_EMPTY(&obj->properties)) { > > - ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); > > - > > - QTAILQ_REMOVE(&obj->properties, prop, node); > > + ObjectProperty *prop; > > + GHashTableIter iter; > > + gpointer key, value; > > > > + g_hash_table_iter_init(&iter, obj->properties); > > + while (g_hash_table_iter_next(&iter, &key, &value)) { > > + prop = value; > > if (prop->release) { > > prop->release(obj, prop->name, prop->opaque); > > } > > Why is this not in property_free(), too? Is there a timing difference? This is what i started from, and got NAKed. property_free() gets only ObjectProperty * as argument, but for our release callback we need also 'obj'. In my first version i added Object * backpointer to ObjectProperty and Daniel reported a problem with that: --- cut --- I have a patch which adds property registration against the class, so requiring ObjectProperty to have a back-poointer to an object instance is not desirable. --- cut --- Full message here: https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg01999.html > > > - > > - g_free(prop->name); > > - g_free(prop->type); > > - g_free(prop->description); > > - g_free(prop); > > } > > + > > + g_hash_table_unref(obj->properties); > > } Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-05 18:05 ` Andreas Färber 2015-11-06 9:02 ` Pavel Fedin @ 2015-11-06 9:31 ` Daniel P. Berrange 2015-11-06 9:37 ` Pavel Fedin 1 sibling, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-11-06 9:31 UTC (permalink / raw) To: Andreas Färber Cc: Paolo Bonzini, Pavel Fedin, qemu-devel, Markus Armbruster On Thu, Nov 05, 2015 at 07:05:48PM +0100, Andreas Färber wrote: > Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > > From: Pavel Fedin <p.fedin@samsung.com> > > > > ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since > > every pin is represented as a property, number of these properties becomes > > very large. Every property add first makes sure there's no duplicates. > > Traversing the list becomes very slow, therefore qemu initialization takes > > significant time (several seconds for e. g. 16 CPUs). > > > > This patch replaces list with GHashTable, making lookup very fast. The only > > drawback is that object_child_foreach() and object_child_foreach_recursive() > > cannot modify their objects during traversal, since GHashTableIter does not > > have modify-safe version. However, the code seems not to modify objects via > > these functions. > > "modify objects" seems a little misleading here; from what I see only > adding or removing properties (including child<>s) is forbidden, right? > Modifying one ObjectProperty or its value should still be okay. Yeah, that's correct. > > 2 files changed, 64 insertions(+), 44 deletions(-) > [...] > > diff --git a/qom/object.c b/qom/object.c > > index 7dace59..dd01652 100644 > > --- a/qom/object.c > > +++ b/qom/object.c > > @@ -68,7 +68,7 @@ struct TypeImpl > > }; > > > > struct ObjectPropertyIterator { > > - ObjectProperty *next; > > + GHashTableIter iter; > > }; > > > > static Type type_interface; > > @@ -330,6 +330,16 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) > > } > > } > > > > +static void property_free(gpointer data) > > Bikeshed: We might call this object_property_free() unless there's a > precedence for property_...? Sure, object_property_free() sounds fine. > > > +{ > > + 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; > [...] > > @@ -363,29 +374,35 @@ static inline bool object_property_is_child(ObjectProperty *prop) > > > > static void object_property_del_all(Object *obj) > > { > > - while (!QTAILQ_EMPTY(&obj->properties)) { > > - ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); > > - > > - QTAILQ_REMOVE(&obj->properties, prop, node); > > + ObjectProperty *prop; > > + GHashTableIter iter; > > + gpointer key, value; > > > > + g_hash_table_iter_init(&iter, obj->properties); > > + while (g_hash_table_iter_next(&iter, &key, &value)) { > > + prop = value; > > if (prop->release) { > > prop->release(obj, prop->name, prop->opaque); > > } > > Why is this not in property_free(), too? Is there a timing difference? To have this be part of property_free() would require that the ObjectProperty class have a back-pointer to the Object * that owns it. We want to use ObjectProperty from ObjectClass * too though, so we don't really want to have such a Object * backpointer. > > @@ -924,7 +940,7 @@ ObjectProperty *object_property_find(Object *obj, const char *name, > > ObjectPropertyIterator *object_property_iter_init(Object *obj) > > { > > ObjectPropertyIterator *ret = g_new0(ObjectPropertyIterator, 1); > > - ret->next = QTAILQ_FIRST(&obj->properties); > > + g_hash_table_iter_init(&ret->iter, obj->properties); > > return ret; > > } > > > > Is it intentional that our iterator pattern differs? If you use the GHashTable approach, then the caller needs to allocate the ObjectPropertyIterator which means it has to be a public typedef. I wanted to keep the ObjectPropertyIterator struct contents private, and have object_property_iter_init() return the allocated struct. > > > @@ -940,31 +956,27 @@ void object_property_iter_free(ObjectPropertyIterator *iter) > > > > ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) > > { > > - ObjectProperty *ret = iter->next; > > - if (ret) { > > - iter->next = QTAILQ_NEXT(iter->next, node); > > + gpointer key, val; > > + if (!g_hash_table_iter_next(&iter->iter, &key, &val)) { > > + return NULL; > > } > > - return ret; > > + return val; > > } > > > > > > void object_property_del(Object *obj, const char *name, Error **errp) > > { > > - ObjectProperty *prop = object_property_find(obj, name, errp); > > - if (prop == NULL) { > > + ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); > > + > > + if (!prop) { > > + error_setg(errp, "Property '.%s' not found", name); > > Is this a behavioral change? No, object_property_find() will return exactly the same error as this new code does. > > @@ -1484,11 +1496,13 @@ void object_property_add_const_link(Object *obj, const char *name, > > gchar *object_get_canonical_path_component(Object *obj) > > { > > ObjectProperty *prop = NULL; > > + GHashTableIter iter; > > > > g_assert(obj); > > g_assert(obj->parent != NULL); > > > > - QTAILQ_FOREACH(prop, &obj->parent->properties, node) { > > + g_hash_table_iter_init(&iter, obj->parent->properties); > > + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { > > Is this cast needed? Probably not, as any pointer should coerce to void * without an explicit cast, unless it had a 'const' involved. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-06 9:31 ` Daniel P. Berrange @ 2015-11-06 9:37 ` Pavel Fedin 0 siblings, 0 replies; 41+ messages in thread From: Pavel Fedin @ 2015-11-06 9:37 UTC (permalink / raw) To: 'Daniel P. Berrange', 'Andreas Färber' Cc: 'Paolo Bonzini', qemu-devel, 'Markus Armbruster' Hello! > > > - QTAILQ_FOREACH(prop, &obj->parent->properties, node) { > > > + g_hash_table_iter_init(&iter, obj->parent->properties); > > > + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { > > > > Is this cast needed? > > Probably not, as any pointer should coerce to void * without an > explicit cast, unless it had a 'const' involved. But after '&' it becomes "**", not just "*", and this implicit conversion rule doesn't apply any more. "void **" and "something **" are always considered different. Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable Daniel P. Berrange 2015-11-05 18:05 ` Andreas Färber @ 2015-11-13 18:14 ` Andreas Färber 2015-11-13 21:00 ` Christian Borntraeger 1 sibling, 1 reply; 41+ messages in thread From: Andreas Färber @ 2015-11-13 18:14 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel, Pavel Fedin Cc: Paolo Bonzini, Markus Armbruster, Christian Borntraeger, Peter Maydell Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > From: Pavel Fedin <p.fedin@samsung.com> > > ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since > every pin is represented as a property, number of these properties becomes > very large. Every property add first makes sure there's no duplicates. > Traversing the list becomes very slow, therefore qemu initialization takes > significant time (several seconds for e. g. 16 CPUs). > > This patch replaces list with GHashTable, making lookup very fast. The only > drawback is that object_child_foreach() and object_child_foreach_recursive() > cannot modify their objects during traversal, since GHashTableIter does not > have modify-safe version. However, the code seems not to modify objects via > these functions. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > Signed-off-by: Pavel Fedin <p.fedin@samsung.com> (note these seemed misordered) I have queued things up to 6/7 on qom-next: https://github.com/afaerber/qemu-cpu/commits/qom-next This patch didn't apply and I had to hand-apply one hunk (which I double-checked, but you never know). Unfortunately I run into this test failure: TEST: tests/device-introspect-test... (pid=4094) /s390x/device/introspect/list: OK /s390x/device/introspect/none: OK /s390x/device/introspect/abstract: OK /s390x/device/introspect/concrete: (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion 'ri->version == ri->hash_table->version' failed ** ERROR:/home/andreas/QEMU/qemu/qom/object.c:867:object_unref: assertion failed: (obj->ref > 0) Broken pipe FAIL GTester: last random seed: R02S4fa2068506971129a7ebe2323dbe03b7 (pid=4104) FAIL: tests/device-introspect-test TEST: tests/qom-test... (pid=4105) /s390x/qom/s390-ccw-virtio-2.5: OK /s390x/qom/s390-ccw-virtio-2.4: OK /s390x/qom/none: OK /s390x/qom/s390-virtio: WARNING The s390-virtio machine (non-ccw) is deprecated. It will be removed in 2.6. Please use s390-ccw-virtio OK PASS: tests/qom-test Are you sure you tested all targets? Any hunch where this might stem from? The below patch reveals that the ref count is 0. Might be just a symptom of the actual problem though. diff --git a/qom/object.c b/qom/object.c index 0ac3bc1..9aa6159 100644 --- a/qom/object.c +++ b/qom/object.c @@ -864,7 +864,7 @@ void object_unref(Object *obj) if (!obj) { return; } - g_assert(obj->ref > 0); + g_assert_cmpint(obj->ref, >, 0); /* parent always holds a reference to its children */ if (atomic_fetch_dec(&obj->ref) == 1) { Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-13 18:14 ` Andreas Färber @ 2015-11-13 21:00 ` Christian Borntraeger 2015-11-13 21:25 ` Andreas Färber 2015-11-16 11:35 ` Daniel P. Berrange 0 siblings, 2 replies; 41+ messages in thread From: Christian Borntraeger @ 2015-11-13 21:00 UTC (permalink / raw) To: Andreas Färber, Daniel P. Berrange, qemu-devel, Pavel Fedin Cc: Paolo Bonzini, Markus Armbruster, Peter Maydell On 11/13/2015 07:14 PM, Andreas Färber wrote: > Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: >> From: Pavel Fedin <p.fedin@samsung.com> >> >> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since >> every pin is represented as a property, number of these properties becomes >> very large. Every property add first makes sure there's no duplicates. >> Traversing the list becomes very slow, therefore qemu initialization takes >> significant time (several seconds for e. g. 16 CPUs). >> >> This patch replaces list with GHashTable, making lookup very fast. The only >> drawback is that object_child_foreach() and object_child_foreach_recursive() >> cannot modify their objects during traversal, since GHashTableIter does not >> have modify-safe version. However, the code seems not to modify objects via >> these functions. >> >> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> > > (note these seemed misordered) > > I have queued things up to 6/7 on qom-next: > https://github.com/afaerber/qemu-cpu/commits/qom-next > > This patch didn't apply and I had to hand-apply one hunk (which I > double-checked, but you never know). > > Unfortunately I run into this test failure: > > TEST: tests/device-introspect-test... (pid=4094) > /s390x/device/introspect/list: OK > /s390x/device/introspect/none: OK > /s390x/device/introspect/abstract: OK > /s390x/device/introspect/concrete: > (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > 'ri->version == ri->hash_table->version' failed > > (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > 'ri->version == ri->hash_table->version' failed > > (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion > 'ri->version == ri->hash_table->version' failed > ** > ERROR:/home/andreas/QEMU/qemu/qom/object.c:867:object_unref: assertion > failed: (obj->ref > 0) > Broken pipe > FAIL > GTester: last random seed: R02S4fa2068506971129a7ebe2323dbe03b7 > (pid=4104) > FAIL: tests/device-introspect-test > TEST: tests/qom-test... (pid=4105) > /s390x/qom/s390-ccw-virtio-2.5: OK > /s390x/qom/s390-ccw-virtio-2.4: OK > /s390x/qom/none: OK > /s390x/qom/s390-virtio: > WARNING > The s390-virtio machine (non-ccw) is deprecated. > It will be removed in 2.6. Please use s390-ccw-virtio > OK > PASS: tests/qom-test > > Are you sure you tested all targets? > Any hunch where this might stem from? > > The below patch reveals that the ref count is 0. Might be just a symptom > of the actual problem though. A simpler reproducer is s390x-softmmu/qemu-system-s390x -device sclp,help which fails with this patch and succeeds without. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-13 21:00 ` Christian Borntraeger @ 2015-11-13 21:25 ` Andreas Färber 2015-11-16 7:13 ` Pavel Fedin 2015-11-16 8:53 ` Paolo Bonzini 2015-11-16 11:35 ` Daniel P. Berrange 1 sibling, 2 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-13 21:25 UTC (permalink / raw) To: Christian Borntraeger Cc: Peter Maydell, Pavel Fedin, qemu-devel, Markus Armbruster, Paolo Bonzini Am 13.11.2015 um 22:00 schrieb Christian Borntraeger: > On 11/13/2015 07:14 PM, Andreas Färber wrote: >> Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: >>> From: Pavel Fedin <p.fedin@samsung.com> >>> >>> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since >>> every pin is represented as a property, number of these properties becomes >>> very large. Every property add first makes sure there's no duplicates. >>> Traversing the list becomes very slow, therefore qemu initialization takes >>> significant time (several seconds for e. g. 16 CPUs). >>> >>> This patch replaces list with GHashTable, making lookup very fast. The only >>> drawback is that object_child_foreach() and object_child_foreach_recursive() >>> cannot modify their objects during traversal, since GHashTableIter does not >>> have modify-safe version. However, the code seems not to modify objects via >>> these functions. >>> >>> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> >>> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> >> >> (note these seemed misordered) >> >> I have queued things up to 6/7 on qom-next: >> https://github.com/afaerber/qemu-cpu/commits/qom-next >> >> This patch didn't apply and I had to hand-apply one hunk (which I >> double-checked, but you never know). >> >> Unfortunately I run into this test failure: >> >> TEST: tests/device-introspect-test... (pid=4094) >> /s390x/device/introspect/list: OK >> /s390x/device/introspect/none: OK >> /s390x/device/introspect/abstract: OK >> /s390x/device/introspect/concrete: >> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >> 'ri->version == ri->hash_table->version' failed >> >> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >> 'ri->version == ri->hash_table->version' failed >> >> (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion >> 'ri->version == ri->hash_table->version' failed >> ** >> ERROR:/home/andreas/QEMU/qemu/qom/object.c:867:object_unref: assertion >> failed: (obj->ref > 0) >> Broken pipe >> FAIL >> GTester: last random seed: R02S4fa2068506971129a7ebe2323dbe03b7 >> (pid=4104) >> FAIL: tests/device-introspect-test >> TEST: tests/qom-test... (pid=4105) >> /s390x/qom/s390-ccw-virtio-2.5: OK >> /s390x/qom/s390-ccw-virtio-2.4: OK >> /s390x/qom/none: OK >> /s390x/qom/s390-virtio: >> WARNING >> The s390-virtio machine (non-ccw) is deprecated. >> It will be removed in 2.6. Please use s390-ccw-virtio >> OK >> PASS: tests/qom-test >> >> Are you sure you tested all targets? >> Any hunch where this might stem from? >> >> The below patch reveals that the ref count is 0. Might be just a symptom >> of the actual problem though. > > A simpler reproducer is > s390x-softmmu/qemu-system-s390x -device sclp,help > which fails with this patch and succeeds without. Thanks! sclp_init() seems to violate several QOM design principles in that it uses object_new() during TypeInfo::instance_init() and uses a TYPE_... constant as property name. But nothing else stands out immediately. Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-13 21:25 ` Andreas Färber @ 2015-11-16 7:13 ` Pavel Fedin 2015-11-16 8:16 ` Christian Borntraeger 2015-11-16 8:53 ` Paolo Bonzini 1 sibling, 1 reply; 41+ messages in thread From: Pavel Fedin @ 2015-11-16 7:13 UTC (permalink / raw) To: 'Andreas Färber', 'Christian Borntraeger' Cc: 'Peter Maydell', 'Paolo Bonzini', qemu-devel, 'Markus Armbruster' Hello! > >> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > >> 'ri->version == ri->hash_table->version' failed > >> > >> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > >> 'ri->version == ri->hash_table->version' failed > >> > >> (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion > >> 'ri->version == ri->hash_table->version' failed Wow... Actually this may come from attempts to modify the tree inside iteration. > Thanks! sclp_init() seems to violate several QOM design principles in > that it uses object_new() during TypeInfo::instance_init() and uses a > TYPE_... constant as property name. But nothing else stands out immediately. I think we should refactor this and retry. If not all problems go away, then we are indeed modifying the tree during iteration, and we have to find some solution. I wonder... Could we have both list and hashtable? hashtable for searching by name and list for iteration. In this case we would not have to use glib's iterators, and would be free of problems with them. Just keep the list and hashtable in sync. Or, is there any hashtable implementation out there which would keep iterators valid during modification? OTOH, glib has a function "remove the element at iterator's position", and we could postpone addition. So, perhaps, using both containers would be an overkill, just refactor the code to adapt to the new behavior. Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 7:13 ` Pavel Fedin @ 2015-11-16 8:16 ` Christian Borntraeger 2015-11-16 9:38 ` Andreas Färber 0 siblings, 1 reply; 41+ messages in thread From: Christian Borntraeger @ 2015-11-16 8:16 UTC (permalink / raw) To: Pavel Fedin, 'Andreas Färber' Cc: 'Peter Maydell', qemu-devel, 'Markus Armbruster', David Hildenbrand, Cornelia Huck, 'Paolo Bonzini' On 11/16/2015 08:13 AM, Pavel Fedin wrote: > Hello! > >>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >>>> 'ri->version == ri->hash_table->version' failed >>>> >>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >>>> 'ri->version == ri->hash_table->version' failed >>>> >>>> (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion >>>> 'ri->version == ri->hash_table->version' failed > > Wow... Actually this may come from attempts to modify the tree inside iteration. > >> Thanks! sclp_init() seems to violate several QOM design principles in >> that it uses object_new() during TypeInfo::instance_init() and uses a >> TYPE_... constant as property name. But nothing else stands out immediately. > > I think we should refactor this and retry. If not all problems go away, then we are indeed modifying the tree during iteration, and > we have to find some solution. David, Conny, the current tree of afaerber https://github.com/afaerber/qemu-cpu/commits/qom-next has this patch: > From: Pavel Fedin <p.fedin@samsung.com> > > ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since > every pin is represented as a property, number of these properties becomes > very large. Every property add first makes sure there's no duplicates. > Traversing the list becomes very slow, therefore qemu initialization takes > significant time (several seconds for e. g. 16 CPUs). > > This patch replaces list with GHashTable, making lookup very fast. The only > drawback is that object_child_foreach() and object_child_foreach_recursive() > cannot modify their objects during traversal, since GHashTableIter does not > have modify-safe version. However, the code seems not to modify objects via > these functions. > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > Signed-off-by: Pavel Fedin <p.fedin@samsung.com> which causes failures in make check. A simple reproducer is qemu-system-s390x -device sclp,help any idea what would be the most simple fix? Can we refactor this to create the event facility and the bus in the machine or whatever? > I wonder... Could we have both list and hashtable? hashtable for searching by name and list for iteration. In this case we would > not have to use glib's iterators, and would be free of problems with them. Just keep the list and hashtable in sync. > Or, is there any hashtable implementation out there which would keep iterators valid during modification? > OTOH, glib has a function "remove the element at iterator's position", and we could postpone addition. So, perhaps, using both > containers would be an overkill, just refactor the code to adapt to the new behavior. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 8:16 ` Christian Borntraeger @ 2015-11-16 9:38 ` Andreas Färber 2015-11-16 10:31 ` Pavel Fedin 2015-11-16 16:44 ` Andreas Färber 0 siblings, 2 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-16 9:38 UTC (permalink / raw) To: Christian Borntraeger, Pavel Fedin Cc: 'Peter Maydell', qemu-devel, 'Markus Armbruster', David Hildenbrand, Cornelia Huck, 'Paolo Bonzini' Am 16.11.2015 um 09:16 schrieb Christian Borntraeger: > On 11/16/2015 08:13 AM, Pavel Fedin wrote: >>>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >>>>> 'ri->version == ri->hash_table->version' failed >>>>> >>>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >>>>> 'ri->version == ri->hash_table->version' failed >>>>> >>>>> (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion >>>>> 'ri->version == ri->hash_table->version' failed >> >> Wow... Actually this may come from attempts to modify the tree inside iteration. >> >>> Thanks! sclp_init() seems to violate several QOM design principles in >>> that it uses object_new() during TypeInfo::instance_init() and uses a >>> TYPE_... constant as property name. But nothing else stands out immediately. >> >> I think we should refactor this and retry. If not all problems go away, then we are indeed modifying the tree during iteration, and >> we have to find some solution. > > David, Conny, > > the current tree of afaerber > > https://github.com/afaerber/qemu-cpu/commits/qom-next > > has this patch: > >> From: Pavel Fedin <p.fedin@samsung.com> >> >> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since >> every pin is represented as a property, number of these properties becomes >> very large. Every property add first makes sure there's no duplicates. >> Traversing the list becomes very slow, therefore qemu initialization takes >> significant time (several seconds for e. g. 16 CPUs). >> >> This patch replaces list with GHashTable, making lookup very fast. The only >> drawback is that object_child_foreach() and object_child_foreach_recursive() >> cannot modify their objects during traversal, since GHashTableIter does not >> have modify-safe version. However, the code seems not to modify objects via >> these functions. >> >> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> > > which causes failures in make check. A simple reproducer is > > qemu-system-s390x -device sclp,help > > > any idea what would be the most simple fix? > Can we refactor this to create the event facility and the bus in the > machine or whatever? I believe it is rather a very general problem with the new object_property_del_all() implementation. It iterates through properties, releasing child<> and link<> properties, which results in an unref, which at some point unparents that device, removing it in the parent's properties hashtable while the parent is iterating through it. In this case it seems to be about the bus child<> on the event facility. >> I wonder... Could we have both list and hashtable? hashtable for searching by name and list for iteration. In this case we would >> not have to use glib's iterators, and would be free of problems with them. Just keep the list and hashtable in sync. >> Or, is there any hashtable implementation out there which would keep iterators valid during modification? >> OTOH, glib has a function "remove the element at iterator's position", and we could postpone addition. So, perhaps, using both >> containers would be an overkill, just refactor the code to adapt to the new behavior. My idea, which I wanted to investigate after the weekend, is iterating through the hashtable to create a list of prop->release functions and call them only after finishing the iteration. That might not work either, so we may need to loop over the releasing to allow for released properties to disappear after prop->release(). Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 9:38 ` Andreas Färber @ 2015-11-16 10:31 ` Pavel Fedin 2015-11-16 16:44 ` Andreas Färber 1 sibling, 0 replies; 41+ messages in thread From: Pavel Fedin @ 2015-11-16 10:31 UTC (permalink / raw) To: 'Andreas Färber', 'Christian Borntraeger' Cc: 'Peter Maydell', qemu-devel, 'Markus Armbruster', 'David Hildenbrand', 'Cornelia Huck', 'Paolo Bonzini' Hello! > My idea, which I wanted to investigate after the weekend, is iterating > through the hashtable to create a list of prop->release functions and > call them only after finishing the iteration. That might not work > either, so we may need to loop over the releasing to allow for released > properties to disappear after prop->release(). Hm... May be instead of actually deleting a property, while we are iterating, we should mark it as pending for deletion, and then, after iteration is done, actually remove them? This would cost one 'bool delete_pending' per property. Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 9:38 ` Andreas Färber 2015-11-16 10:31 ` Pavel Fedin @ 2015-11-16 16:44 ` Andreas Färber 2015-11-16 16:53 ` Daniel P. Berrange 1 sibling, 1 reply; 41+ messages in thread From: Andreas Färber @ 2015-11-16 16:44 UTC (permalink / raw) To: Christian Borntraeger, Pavel Fedin, Daniel P. Berrange Cc: 'Peter Maydell', qemu-devel, 'Markus Armbruster', David Hildenbrand, Cornelia Huck, 'Paolo Bonzini' [-- Attachment #1: Type: text/plain, Size: 4177 bytes --] Am 16.11.2015 um 10:38 schrieb Andreas Färber: > Am 16.11.2015 um 09:16 schrieb Christian Borntraeger: >> On 11/16/2015 08:13 AM, Pavel Fedin wrote: >>>>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >>>>>> 'ri->version == ri->hash_table->version' failed >>>>>> >>>>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion >>>>>> 'ri->version == ri->hash_table->version' failed >>>>>> >>>>>> (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion >>>>>> 'ri->version == ri->hash_table->version' failed >>> >>> Wow... Actually this may come from attempts to modify the tree inside iteration. >>> >>>> Thanks! sclp_init() seems to violate several QOM design principles in >>>> that it uses object_new() during TypeInfo::instance_init() and uses a >>>> TYPE_... constant as property name. But nothing else stands out immediately. >>> >>> I think we should refactor this and retry. If not all problems go away, then we are indeed modifying the tree during iteration, and >>> we have to find some solution. >> >> David, Conny, >> >> the current tree of afaerber >> >> https://github.com/afaerber/qemu-cpu/commits/qom-next >> >> has this patch: >> >>> From: Pavel Fedin <p.fedin@samsung.com> >>> >>> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since >>> every pin is represented as a property, number of these properties becomes >>> very large. Every property add first makes sure there's no duplicates. >>> Traversing the list becomes very slow, therefore qemu initialization takes >>> significant time (several seconds for e. g. 16 CPUs). >>> >>> This patch replaces list with GHashTable, making lookup very fast. The only >>> drawback is that object_child_foreach() and object_child_foreach_recursive() >>> cannot modify their objects during traversal, since GHashTableIter does not >>> have modify-safe version. However, the code seems not to modify objects via >>> these functions. >>> >>> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> >>> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> >> >> which causes failures in make check. A simple reproducer is >> >> qemu-system-s390x -device sclp,help >> >> >> any idea what would be the most simple fix? >> Can we refactor this to create the event facility and the bus in the >> machine or whatever? > > I believe it is rather a very general problem with the new > object_property_del_all() implementation. It iterates through > properties, releasing child<> and link<> properties, which results in an > unref, which at some point unparents that device, removing it in the > parent's properties hashtable while the parent is iterating through it. > > In this case it seems to be about the bus child<> on the event facility. > >>> I wonder... Could we have both list and hashtable? hashtable for searching by name and list for iteration. In this case we would >>> not have to use glib's iterators, and would be free of problems with them. Just keep the list and hashtable in sync. >>> Or, is there any hashtable implementation out there which would keep iterators valid during modification? >>> OTOH, glib has a function "remove the element at iterator's position", and we could postpone addition. So, perhaps, using both >>> containers would be an overkill, just refactor the code to adapt to the new behavior. > > My idea, which I wanted to investigate after the weekend, is iterating > through the hashtable to create a list of prop->release functions and > call them only after finishing the iteration. That might not work > either, so we may need to loop over the releasing to allow for released > properties to disappear after prop->release(). I went with the latter and squashed the attached fixup (without last two hunks, preparing a separate patch for that), interrupting each iteration after prop->release() to be safe. That seems to fix it. Will prepend and test Dan's unit test next. Thanks, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) [-- Attachment #2: 00.diff --] [-- Type: text/x-patch, Size: 2129 bytes --] diff --git a/qom/object.c b/qom/object.c index 0ac3bc1..284fa38 100644 --- a/qom/object.c +++ b/qom/object.c @@ -377,14 +377,22 @@ static void object_property_del_all(Object *obj) ObjectProperty *prop; GHashTableIter iter; gpointer key, value; + bool released; - g_hash_table_iter_init(&iter, obj->properties); - while (g_hash_table_iter_next(&iter, &key, &value)) { - prop = value; - if (prop->release) { - prop->release(obj, prop->name, prop->opaque); + do { + released = false; + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; + if (prop->release) { + prop->release(obj, prop->name, prop->opaque); + prop->release = NULL; + released = true; + break; + } + g_hash_table_iter_remove(&iter); } - } + } while (released); g_hash_table_unref(obj->properties); } @@ -401,7 +409,15 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp) if (object_property_is_child(prop) && prop->opaque == child) { if (prop->release) { prop->release(obj, prop->name, prop->opaque); + prop->release = NULL; } + break; + } + } + g_hash_table_iter_init(&iter, obj->properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + prop = value; + if (object_property_is_child(prop) && prop->opaque == child) { g_hash_table_iter_remove(&iter); break; } @@ -856,7 +872,7 @@ void object_ref(Object *obj) if (!obj) { return; } - atomic_inc(&obj->ref); + atomic_inc(&obj->ref); } void object_unref(Object *obj) @@ -864,7 +880,7 @@ void object_unref(Object *obj) if (!obj) { return; } - g_assert(obj->ref > 0); + g_assert_cmpint(obj->ref, >, 0); /* parent always holds a reference to its children */ if (atomic_fetch_dec(&obj->ref) == 1) { ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 16:44 ` Andreas Färber @ 2015-11-16 16:53 ` Daniel P. Berrange 0 siblings, 0 replies; 41+ messages in thread From: Daniel P. Berrange @ 2015-11-16 16:53 UTC (permalink / raw) To: Andreas Färber Cc: 'Peter Maydell', David Hildenbrand, Pavel Fedin, qemu-devel, 'Markus Armbruster', Christian Borntraeger, Cornelia Huck, 'Paolo Bonzini' On Mon, Nov 16, 2015 at 05:44:35PM +0100, Andreas Färber wrote: > Am 16.11.2015 um 10:38 schrieb Andreas Färber: > > Am 16.11.2015 um 09:16 schrieb Christian Borntraeger: > >> On 11/16/2015 08:13 AM, Pavel Fedin wrote: > >>>>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > >>>>>> 'ri->version == ri->hash_table->version' failed > >>>>>> > >>>>>> (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > >>>>>> 'ri->version == ri->hash_table->version' failed > >>>>>> > >>>>>> (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion > >>>>>> 'ri->version == ri->hash_table->version' failed > >>> > >>> Wow... Actually this may come from attempts to modify the tree inside iteration. > >>> > >>>> Thanks! sclp_init() seems to violate several QOM design principles in > >>>> that it uses object_new() during TypeInfo::instance_init() and uses a > >>>> TYPE_... constant as property name. But nothing else stands out immediately. > >>> > >>> I think we should refactor this and retry. If not all problems go away, then we are indeed modifying the tree during iteration, and > >>> we have to find some solution. > >> > >> David, Conny, > >> > >> the current tree of afaerber > >> > >> https://github.com/afaerber/qemu-cpu/commits/qom-next > >> > >> has this patch: > >> > >>> From: Pavel Fedin <p.fedin@samsung.com> > >>> > >>> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since > >>> every pin is represented as a property, number of these properties becomes > >>> very large. Every property add first makes sure there's no duplicates. > >>> Traversing the list becomes very slow, therefore qemu initialization takes > >>> significant time (several seconds for e. g. 16 CPUs). > >>> > >>> This patch replaces list with GHashTable, making lookup very fast. The only > >>> drawback is that object_child_foreach() and object_child_foreach_recursive() > >>> cannot modify their objects during traversal, since GHashTableIter does not > >>> have modify-safe version. However, the code seems not to modify objects via > >>> these functions. > >>> > >>> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > >>> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> > >> > >> which causes failures in make check. A simple reproducer is > >> > >> qemu-system-s390x -device sclp,help > >> > >> > >> any idea what would be the most simple fix? > >> Can we refactor this to create the event facility and the bus in the > >> machine or whatever? > > > > I believe it is rather a very general problem with the new > > object_property_del_all() implementation. It iterates through > > properties, releasing child<> and link<> properties, which results in an > > unref, which at some point unparents that device, removing it in the > > parent's properties hashtable while the parent is iterating through it. > > > > In this case it seems to be about the bus child<> on the event facility. > > > >>> I wonder... Could we have both list and hashtable? hashtable for searching by name and list for iteration. In this case we would > >>> not have to use glib's iterators, and would be free of problems with them. Just keep the list and hashtable in sync. > >>> Or, is there any hashtable implementation out there which would keep iterators valid during modification? > >>> OTOH, glib has a function "remove the element at iterator's position", and we could postpone addition. So, perhaps, using both > >>> containers would be an overkill, just refactor the code to adapt to the new behavior. > > > > My idea, which I wanted to investigate after the weekend, is iterating > > through the hashtable to create a list of prop->release functions and > > call them only after finishing the iteration. That might not work > > either, so we may need to loop over the releasing to allow for released > > properties to disappear after prop->release(). > > I went with the latter and squashed the attached fixup (without last two > hunks, preparing a separate patch for that), interrupting each iteration > after prop->release() to be safe. That seems to fix it. > > Will prepend and test Dan's unit test next. > diff --git a/qom/object.c b/qom/object.c > index 0ac3bc1..284fa38 100644 > --- a/qom/object.c > +++ b/qom/object.c > @@ -377,14 +377,22 @@ static void object_property_del_all(Object *obj) > ObjectProperty *prop; > GHashTableIter iter; > gpointer key, value; > + bool released; > > - g_hash_table_iter_init(&iter, obj->properties); > - while (g_hash_table_iter_next(&iter, &key, &value)) { > - prop = value; > - if (prop->release) { > - prop->release(obj, prop->name, prop->opaque); > + do { > + released = false; > + g_hash_table_iter_init(&iter, obj->properties); > + while (g_hash_table_iter_next(&iter, &key, &value)) { > + prop = value; > + if (prop->release) { > + prop->release(obj, prop->name, prop->opaque); > + prop->release = NULL; > + released = true; > + break; > + } > + g_hash_table_iter_remove(&iter); > } > - } > + } while (released); > > g_hash_table_unref(obj->properties); > } > @@ -401,7 +409,15 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp) > if (object_property_is_child(prop) && prop->opaque == child) { > if (prop->release) { > prop->release(obj, prop->name, prop->opaque); > + prop->release = NULL; > } > + break; > + } > + } > + g_hash_table_iter_init(&iter, obj->properties); > + while (g_hash_table_iter_next(&iter, &key, &value)) { > + prop = value; > + if (object_property_is_child(prop) && prop->opaque == child) { > g_hash_table_iter_remove(&iter); > break; > } > @@ -856,7 +872,7 @@ void object_ref(Object *obj) > if (!obj) { > return; > } > - atomic_inc(&obj->ref); > + atomic_inc(&obj->ref); > } > > void object_unref(Object *obj) > @@ -864,7 +880,7 @@ void object_unref(Object *obj) > if (!obj) { > return; > } > - g_assert(obj->ref > 0); > + g_assert_cmpint(obj->ref, >, 0); > > /* parent always holds a reference to its children */ > if (atomic_fetch_dec(&obj->ref) == 1) { This looks good to me so can add Signed-off-by: Daniel P. Berrange to this change. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-13 21:25 ` Andreas Färber 2015-11-16 7:13 ` Pavel Fedin @ 2015-11-16 8:53 ` Paolo Bonzini 2015-11-16 9:48 ` Andreas Färber 1 sibling, 1 reply; 41+ messages in thread From: Paolo Bonzini @ 2015-11-16 8:53 UTC (permalink / raw) To: Andreas Färber, Christian Borntraeger Cc: Peter Maydell, Pavel Fedin, qemu-devel, Markus Armbruster On 13/11/2015 22:25, Andreas Färber wrote: > Thanks! sclp_init() seems to violate several QOM design principles in > that it uses object_new() during TypeInfo::instance_init() There's nothing wrong with that. It's wrong however to use qdev_set_parent_bus in instance_init. That should be moved to sclp_realize, before the realized property is set to true. Otherwise, sclp->event_facility outlives its parent. I'm not sure why that works only with the list and not with the hash table though. It may well be a bug in this patch. > and uses a TYPE_... constant as property name. That's just a little weird, it doesn't break anything per se. Paolo ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 8:53 ` Paolo Bonzini @ 2015-11-16 9:48 ` Andreas Färber 2015-11-16 9:50 ` Paolo Bonzini 0 siblings, 1 reply; 41+ messages in thread From: Andreas Färber @ 2015-11-16 9:48 UTC (permalink / raw) To: Paolo Bonzini Cc: Christian Borntraeger, Pavel Fedin, qemu-devel, Markus Armbruster, Peter Maydell Am 16.11.2015 um 09:53 schrieb Paolo Bonzini: > On 13/11/2015 22:25, Andreas Färber wrote: >> Thanks! sclp_init() seems to violate several QOM design principles in >> that it uses object_new() during TypeInfo::instance_init() > > There's nothing wrong with that. It's wrong however to use > qdev_set_parent_bus in instance_init. That should be moved to > sclp_realize, before the realized property is set to true. Negative, realize is too late. Since there are two call sites for initialization, I don't see a better place for it. > Otherwise, sclp->event_facility outlives its parent. I'm not sure why > that works only with the list and not with the hash table though. It > may well be a bug in this patch. Luckily that's not the problem here. The unref should account for its lifetime. >> and uses a TYPE_... constant as property name. > > That's just a little weird, it doesn't break anything per se. It risks renaming the type causing the property to change name, which affects ABI stability. Therefore we always "inline" property names. Will adjust after I have a fix. Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-16 9:48 ` Andreas Färber @ 2015-11-16 9:50 ` Paolo Bonzini 0 siblings, 0 replies; 41+ messages in thread From: Paolo Bonzini @ 2015-11-16 9:50 UTC (permalink / raw) To: Andreas Färber Cc: Christian Borntraeger, Pavel Fedin, qemu-devel, Markus Armbruster, Peter Maydell On 16/11/2015 10:48, Andreas Färber wrote: > > > Thanks! sclp_init() seems to violate several QOM design principles in > > > that it uses object_new() during TypeInfo::instance_init() > > > > There's nothing wrong with that. It's wrong however to use > > qdev_set_parent_bus in instance_init. That should be moved to > > sclp_realize, before the realized property is set to true. > > Negative, realize is too late. Since there are two call sites for > initialization, I don't see a better place for it. Why is realize too late to set the parent bus? Paolo ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable 2015-11-13 21:00 ` Christian Borntraeger 2015-11-13 21:25 ` Andreas Färber @ 2015-11-16 11:35 ` Daniel P. Berrange 1 sibling, 0 replies; 41+ messages in thread From: Daniel P. Berrange @ 2015-11-16 11:35 UTC (permalink / raw) To: Christian Borntraeger Cc: Peter Maydell, Pavel Fedin, Markus Armbruster, qemu-devel, Paolo Bonzini, Andreas Färber On Fri, Nov 13, 2015 at 10:00:58PM +0100, Christian Borntraeger wrote: > On 11/13/2015 07:14 PM, Andreas Färber wrote: > > Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > >> From: Pavel Fedin <p.fedin@samsung.com> > >> > >> ARM GICv3 systems with large number of CPUs create lots of IRQ pins. Since > >> every pin is represented as a property, number of these properties becomes > >> very large. Every property add first makes sure there's no duplicates. > >> Traversing the list becomes very slow, therefore qemu initialization takes > >> significant time (several seconds for e. g. 16 CPUs). > >> > >> This patch replaces list with GHashTable, making lookup very fast. The only > >> drawback is that object_child_foreach() and object_child_foreach_recursive() > >> cannot modify their objects during traversal, since GHashTableIter does not > >> have modify-safe version. However, the code seems not to modify objects via > >> these functions. > >> > >> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> > >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> > > > > (note these seemed misordered) > > > > I have queued things up to 6/7 on qom-next: > > https://github.com/afaerber/qemu-cpu/commits/qom-next > > > > This patch didn't apply and I had to hand-apply one hunk (which I > > double-checked, but you never know). > > > > Unfortunately I run into this test failure: > > > > TEST: tests/device-introspect-test... (pid=4094) > > /s390x/device/introspect/list: OK > > /s390x/device/introspect/none: OK > > /s390x/device/introspect/abstract: OK > > /s390x/device/introspect/concrete: > > (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > > 'ri->version == ri->hash_table->version' failed > > > > (process:4102): GLib-CRITICAL **: g_hash_table_iter_next: assertion > > 'ri->version == ri->hash_table->version' failed > > > > (process:4102): GLib-CRITICAL **: iter_remove_or_steal: assertion > > 'ri->version == ri->hash_table->version' failed > > ** > > ERROR:/home/andreas/QEMU/qemu/qom/object.c:867:object_unref: assertion > > failed: (obj->ref > 0) > > Broken pipe > > FAIL > > GTester: last random seed: R02S4fa2068506971129a7ebe2323dbe03b7 > > (pid=4104) > > FAIL: tests/device-introspect-test > > TEST: tests/qom-test... (pid=4105) > > /s390x/qom/s390-ccw-virtio-2.5: OK > > /s390x/qom/s390-ccw-virtio-2.4: OK > > /s390x/qom/none: OK > > /s390x/qom/s390-virtio: > > WARNING > > The s390-virtio machine (non-ccw) is deprecated. > > It will be removed in 2.6. Please use s390-ccw-virtio > > OK > > PASS: tests/qom-test > > > > Are you sure you tested all targets? > > Any hunch where this might stem from? > > > > The below patch reveals that the ref count is 0. Might be just a symptom > > of the actual problem though. > > A simpler reproducer is > s390x-softmmu/qemu-system-s390x -device sclp,help > which fails with this patch and succeeds without. The problems arise when unref'ing the object, which is where we iterate over properties deleting them. From my investigation it seems we have a re-entrancy issue where by child objects are calling back to the parent to delete properties while iteration is taking place. The glib hash iterators are not re-entrant safe, so this causes the glib errors showing we're modifying the hash table while iteration is taking place. (qemu-system-s390x:21872): GLib-CRITICAL **: iter_remove_or_steal: assertion 'ri->version == ri->hash_table->version' failed I'm looking into how to fix this now... Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ^ permalink raw reply [flat|nested] 41+ messages in thread
* [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange ` (5 preceding siblings ...) 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable Daniel P. Berrange @ 2015-10-13 12:37 ` Daniel P. Berrange 2015-10-13 13:18 ` Pavel Fedin 2015-10-13 12:54 ` [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Andreas Färber 2015-10-14 6:57 ` Pavel Fedin 8 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:37 UTC (permalink / raw) To: qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini, Andreas Färber 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 <berrange@redhat.com> --- include/qom/object.h | 50 ++++++++++ qom/object.c | 237 ++++++++++++++++++++++++++++++++++++++++++--- tests/check-qom-proplist.c | 31 ++++-- 3 files changed, 293 insertions(+), 25 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 2a54515..38f41d3 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; }; /** @@ -947,6 +949,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 @@ -957,6 +966,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; @@ -964,8 +975,14 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; * object_property_iter_init: * @obj: the object * +<<<<<<< HEAD * Initializes an iterator for traversing all properties * registered against an object instance. +======= + * Iterates over all properties defined against the object + * instance, its class and all parent classes, calling + * @iter for each property. +>>>>>>> 0ca9307... qom: allow properties to be registered against classes * * It is forbidden to modify the property list while iterating, * whether removing or adding properties. @@ -1375,6 +1392,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 @@ -1391,6 +1414,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 @@ -1410,6 +1438,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 @@ -1424,6 +1459,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 @@ -1436,6 +1475,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: @@ -1449,6 +1490,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: @@ -1462,6 +1505,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: @@ -1475,6 +1520,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: @@ -1526,6 +1573,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 dd01652..f41edf4 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 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(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, 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, property_free); } ti->class->type = ti; @@ -330,16 +346,6 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) } } -static void 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; @@ -902,10 +908,11 @@ object_property_add(Object *obj, const char *name, const char *type, return ret; } - if (g_hash_table_contains(obj->properties, name)) { + + 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; } @@ -923,10 +930,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) { @@ -941,6 +988,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; } @@ -957,12 +1005,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) { @@ -1717,6 +1790,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 **); @@ -1784,6 +1880,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) { @@ -1847,6 +1965,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; @@ -1926,6 +2069,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)); @@ -1970,6 +2132,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) { @@ -1977,6 +2146,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) { @@ -1984,6 +2160,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) { @@ -1991,6 +2174,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; @@ -2088,6 +2278,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 1be8b9e..87de80b 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, }; static void test_dummy_createv(void) -- 2.4.3 ^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes Daniel P. Berrange @ 2015-10-13 13:18 ` Pavel Fedin 2015-11-05 18:12 ` Andreas Färber 0 siblings, 1 reply; 41+ messages in thread From: Pavel Fedin @ 2015-10-13 13:18 UTC (permalink / raw) To: 'Daniel P. Berrange', qemu-devel Cc: 'Paolo Bonzini', 'Markus Armbruster', 'Andreas Färber' Hello! > -----Original Message----- > From: qemu-devel-bounces+p.fedin=samsung.com@nongnu.org [mailto:qemu-devel- > bounces+p.fedin=samsung.com@nongnu.org] On Behalf Of Daniel P. Berrange > Sent: Tuesday, October 13, 2015 3:38 PM > To: qemu-devel@nongnu.org > Cc: Pavel Fedin; Markus Armbruster; Paolo Bonzini; Andreas Färber > Subject: [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes > > 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 <berrange@redhat.com> > --- > include/qom/object.h | 50 ++++++++++ > qom/object.c | 237 ++++++++++++++++++++++++++++++++++++++++++--- > tests/check-qom-proplist.c | 31 ++++-- > 3 files changed, 293 insertions(+), 25 deletions(-) > > diff --git a/include/qom/object.h b/include/qom/object.h > index 2a54515..38f41d3 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; > }; > > /** > @@ -947,6 +949,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 > @@ -957,6 +966,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; > > @@ -964,8 +975,14 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; > * object_property_iter_init: > * @obj: the object > * > +<<<<<<< HEAD > * Initializes an iterator for traversing all properties > * registered against an object instance. > +======= > + * Iterates over all properties defined against the object > + * instance, its class and all parent classes, calling > + * @iter for each property. > +>>>>>>> 0ca9307... qom: allow properties to be registered against classes Conflict markers slipped in the comment > * > * It is forbidden to modify the property list while iterating, > * whether removing or adding properties. > @@ -1375,6 +1392,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 > @@ -1391,6 +1414,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 > @@ -1410,6 +1438,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 > @@ -1424,6 +1459,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 > @@ -1436,6 +1475,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: > @@ -1449,6 +1490,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: > @@ -1462,6 +1505,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: > @@ -1475,6 +1520,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: > @@ -1526,6 +1573,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 dd01652..f41edf4 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 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(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, 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, property_free); > } > > ti->class->type = ti; > @@ -330,16 +346,6 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti) > } > } > > -static void 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; > @@ -902,10 +908,11 @@ object_property_add(Object *obj, const char *name, const char *type, > return ret; > } > > - if (g_hash_table_contains(obj->properties, name)) { > + > + 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; > } > > @@ -923,10 +930,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) { > @@ -941,6 +988,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; > } > > @@ -957,12 +1005,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) > { > @@ -1717,6 +1790,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 **); > @@ -1784,6 +1880,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) > { > @@ -1847,6 +1965,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; > @@ -1926,6 +2069,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)); > @@ -1970,6 +2132,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) > { > @@ -1977,6 +2146,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) > { > @@ -1984,6 +2160,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) > { > @@ -1991,6 +2174,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; > @@ -2088,6 +2278,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 1be8b9e..87de80b 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, > }; > > static void test_dummy_createv(void) > -- > 2.4.3 Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes 2015-10-13 13:18 ` Pavel Fedin @ 2015-11-05 18:12 ` Andreas Färber 2015-11-06 9:32 ` Daniel P. Berrange 0 siblings, 1 reply; 41+ messages in thread From: Andreas Färber @ 2015-11-05 18:12 UTC (permalink / raw) To: Pavel Fedin, 'Daniel P. Berrange', qemu-devel Cc: 'Paolo Bonzini', 'Markus Armbruster' Am 13.10.2015 um 15:18 schrieb Pavel Fedin: >> diff --git a/include/qom/object.h b/include/qom/object.h >> index 2a54515..38f41d3 100644 >> --- a/include/qom/object.h >> +++ b/include/qom/object.h [...] >> @@ -964,8 +975,14 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; >> * object_property_iter_init: >> * @obj: the object >> * >> +<<<<<<< HEAD >> * Initializes an iterator for traversing all properties >> * registered against an object instance. >> +======= >> + * Iterates over all properties defined against the object >> + * instance, its class and all parent classes, calling >> + * @iter for each property. >> +>>>>>>> 0ca9307... qom: allow properties to be registered against classes > > Conflict markers slipped in the comment There is no v5 fixing this yet? If agreement has been reached, I would at least start applying from the front, to avoid another lengthy review cycle; I could try to resolve the conflict myself if it's the only nit. Regards, Andreas P.S. Pavel, please delete unneeded quotation from your reply, I only found that one line of inline comment. -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes 2015-11-05 18:12 ` Andreas Färber @ 2015-11-06 9:32 ` Daniel P. Berrange 2015-11-18 23:35 ` Andreas Färber 0 siblings, 1 reply; 41+ messages in thread From: Daniel P. Berrange @ 2015-11-06 9:32 UTC (permalink / raw) To: Andreas Färber Cc: 'Paolo Bonzini', Pavel Fedin, qemu-devel, 'Markus Armbruster' On Thu, Nov 05, 2015 at 07:12:39PM +0100, Andreas Färber wrote: > Am 13.10.2015 um 15:18 schrieb Pavel Fedin: > >> diff --git a/include/qom/object.h b/include/qom/object.h > >> index 2a54515..38f41d3 100644 > >> --- a/include/qom/object.h > >> +++ b/include/qom/object.h > [...] > >> @@ -964,8 +975,14 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; > >> * object_property_iter_init: > >> * @obj: the object > >> * > >> +<<<<<<< HEAD > >> * Initializes an iterator for traversing all properties > >> * registered against an object instance. > >> +======= > >> + * Iterates over all properties defined against the object > >> + * instance, its class and all parent classes, calling > >> + * @iter for each property. > >> +>>>>>>> 0ca9307... qom: allow properties to be registered against classes > > > > Conflict markers slipped in the comment > > There is no v5 fixing this yet? If agreement has been reached, I would > at least start applying from the front, to avoid another lengthy review > cycle; I could try to resolve the conflict myself if it's the only nit. Opps, I missed this comment. No, I've not sent a v5, but it looks like it is just this comment that's the problem which is why I didn't catch it during compilation. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes 2015-11-06 9:32 ` Daniel P. Berrange @ 2015-11-18 23:35 ` Andreas Färber 0 siblings, 0 replies; 41+ messages in thread From: Andreas Färber @ 2015-11-18 23:35 UTC (permalink / raw) To: Daniel P. Berrange Cc: 'Paolo Bonzini', Pavel Fedin, qemu-devel, 'Markus Armbruster' Am 06.11.2015 um 10:32 schrieb Daniel P. Berrange: > On Thu, Nov 05, 2015 at 07:12:39PM +0100, Andreas Färber wrote: >> Am 13.10.2015 um 15:18 schrieb Pavel Fedin: >>>> diff --git a/include/qom/object.h b/include/qom/object.h >>>> index 2a54515..38f41d3 100644 >>>> --- a/include/qom/object.h >>>> +++ b/include/qom/object.h >> [...] >>>> @@ -964,8 +975,14 @@ typedef struct ObjectPropertyIterator ObjectPropertyIterator; >>>> * object_property_iter_init: >>>> * @obj: the object >>>> * >>>> +<<<<<<< HEAD >>>> * Initializes an iterator for traversing all properties >>>> * registered against an object instance. >>>> +======= >>>> + * Iterates over all properties defined against the object >>>> + * instance, its class and all parent classes, calling >>>> + * @iter for each property. >>>> +>>>>>>> 0ca9307... qom: allow properties to be registered against classes >>> >>> Conflict markers slipped in the comment >> >> There is no v5 fixing this yet? If agreement has been reached, I would >> at least start applying from the front, to avoid another lengthy review >> cycle; I could try to resolve the conflict myself if it's the only nit. > > Opps, I missed this comment. No, I've not sent a v5, but it looks like > it is just this comment that's the problem which is why I didn't catch > it during compilation. Fixed up and queued on qom-next for next merge window: https://github.com/afaerber/qemu-cpu/commits/qom-next Thanks, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange ` (6 preceding siblings ...) 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes Daniel P. Berrange @ 2015-10-13 12:54 ` Andreas Färber 2015-10-13 12:59 ` Daniel P. Berrange 2015-10-14 6:57 ` Pavel Fedin 8 siblings, 1 reply; 41+ messages in thread From: Andreas Färber @ 2015-10-13 12:54 UTC (permalink / raw) To: Daniel P. Berrange, qemu-devel Cc: Pavel Fedin, Markus Armbruster, Paolo Bonzini Daniel, Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > This patch series is a followup to > > v3: https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02024.html > v2: https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg05953.html > + > https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg01455.html > > This series introduces a concept of object property iterators > to QOM so callers are insulated from the specific data structures > used for storing properties against objects/classes. It then > converts Object to use a GHashTable for storing properties. > Finally it introduces ObjectClass properties. > > Probably the only controversial thing is the item Pavel points > out about object_child_foreach iterators now being forbidden > from modifying the object composition tree. Before this grows even larger, can't we just apply your v2 and go on from there? I had reviewed that okay, just have it in my to-test queue... Regards, Andreas -- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg) ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling 2015-10-13 12:54 ` [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Andreas Färber @ 2015-10-13 12:59 ` Daniel P. Berrange 0 siblings, 0 replies; 41+ messages in thread From: Daniel P. Berrange @ 2015-10-13 12:59 UTC (permalink / raw) To: Andreas Färber Cc: Paolo Bonzini, Pavel Fedin, qemu-devel, Markus Armbruster On Tue, Oct 13, 2015 at 02:54:14PM +0200, Andreas Färber wrote: > Daniel, > > Am 13.10.2015 um 14:37 schrieb Daniel P. Berrange: > > This patch series is a followup to > > > > v3: https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg02024.html > > v2: https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg05953.html > > + > > https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg01455.html > > > > This series introduces a concept of object property iterators > > to QOM so callers are insulated from the specific data structures > > used for storing properties against objects/classes. It then > > converts Object to use a GHashTable for storing properties. > > Finally it introduces ObjectClass properties. > > > > Probably the only controversial thing is the item Pavel points > > out about object_child_foreach iterators now being forbidden > > from modifying the object composition tree. > > Before this grows even larger, can't we just apply your v2 and go on > from there? I had reviewed that okay, just have it in my to-test queue... I don't mind either way - if you want to queue my v2 I can rebase on top of that. Just beware though that my v2 had a latent bug that will trigger when any code starts to use class level properties - they don't get reported by QMP. So we'd have to make sure to apply this new series I have posted in order to fix that bug before we convert any code to use class props. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange ` (7 preceding siblings ...) 2015-10-13 12:54 ` [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Andreas Färber @ 2015-10-14 6:57 ` Pavel Fedin 8 siblings, 0 replies; 41+ messages in thread From: Pavel Fedin @ 2015-10-14 6:57 UTC (permalink / raw) To: 'Daniel P. Berrange', qemu-devel Cc: 'Paolo Bonzini', 'Markus Armbruster', 'Andreas Färber' Hello! > This series introduces a concept of object property iterators > to QOM so callers are insulated from the specific data structures > used for storing properties against objects/classes. It then > converts Object to use a GHashTable for storing properties. > Finally it introduces ObjectClass properties. Tested-by: Pavel Fedin <p.fedin@samsung.com> > Probably the only controversial thing is the item Pavel points > out about object_child_foreach iterators now being forbidden > from modifying the object composition tree. As i already wrote, current code does not modify the tree. If necessary, it is possible to work around (e. g. make a decision about modification, stop iteration, then do the modification). I think this would pop up anyway if we change list to anything else. IMHO it's better just to acknowledge that we should not modify our tree inside iterator. Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia ^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2015-11-18 23:35 UTC | newest] Thread overview: 41+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-10-13 12:37 [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Daniel P. Berrange 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 1/7] qom: introduce ObjectPropertyIterator struct for iteration Daniel P. Berrange 2015-11-05 16:59 ` Andreas Färber 2015-11-17 15:25 ` Markus Armbruster 2015-11-17 15:27 ` Daniel P. Berrange 2015-11-17 15:35 ` Markus Armbruster 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 2/7] qmp: convert QMP code to use object property iterators Daniel P. Berrange 2015-11-05 17:08 ` Andreas Färber 2015-11-17 15:26 ` Markus Armbruster 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 3/7] vl: convert machine help " Daniel P. Berrange 2015-11-05 17:10 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 4/7] ppc: convert spapr " Daniel P. Berrange 2015-11-05 17:16 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 5/7] net: convert net filter " Daniel P. Berrange 2015-11-05 17:18 ` Andreas Färber 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 6/7] qom: replace object property list with GHashTable Daniel P. Berrange 2015-11-05 18:05 ` Andreas Färber 2015-11-06 9:02 ` Pavel Fedin 2015-11-06 9:31 ` Daniel P. Berrange 2015-11-06 9:37 ` Pavel Fedin 2015-11-13 18:14 ` Andreas Färber 2015-11-13 21:00 ` Christian Borntraeger 2015-11-13 21:25 ` Andreas Färber 2015-11-16 7:13 ` Pavel Fedin 2015-11-16 8:16 ` Christian Borntraeger 2015-11-16 9:38 ` Andreas Färber 2015-11-16 10:31 ` Pavel Fedin 2015-11-16 16:44 ` Andreas Färber 2015-11-16 16:53 ` Daniel P. Berrange 2015-11-16 8:53 ` Paolo Bonzini 2015-11-16 9:48 ` Andreas Färber 2015-11-16 9:50 ` Paolo Bonzini 2015-11-16 11:35 ` Daniel P. Berrange 2015-10-13 12:37 ` [Qemu-devel] [PATCH v4 7/7] qom: allow properties to be registered against classes Daniel P. Berrange 2015-10-13 13:18 ` Pavel Fedin 2015-11-05 18:12 ` Andreas Färber 2015-11-06 9:32 ` Daniel P. Berrange 2015-11-18 23:35 ` Andreas Färber 2015-10-13 12:54 ` [Qemu-devel] [PATCH v4 0/7] qom: more efficient object property handling Andreas Färber 2015-10-13 12:59 ` Daniel P. Berrange 2015-10-14 6:57 ` Pavel Fedin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).