From 8e503afeda412c2ebbf5329a4a9e81f7a9ff5c71 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 13 Mar 2012 11:43:54 -0500 Subject: [PATCH] libnm-glib: two object uniqueness fixes First: object creation requests get triggered each time a property that refers to the object is read. That can happen from a couple of places around the same time (like initialization) and to be expected. But when those requests are processed (after we've determined the type of object to create) a previous request may have already created the object. If that's the case don't create a duplicate. Second: properties can also be updated from a few places which don't know about each other (from both regular code and the "pseudo property" signal handlers) so when adding objects to array properties, make sure the object hasn't already been added to that array. --- libnm-glib/nm-object.c | 49 ++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c index 31d6ce9a48..fc9d7f868a 100644 --- a/libnm-glib/nm-object.c +++ b/libnm-glib/nm-object.c @@ -505,16 +505,28 @@ async_got_type (GType type, gpointer user_data) NMObjectTypeAsyncData *async_data = user_data; GObject *object; - if (type != G_TYPE_INVALID) { - object = g_object_new (type, - NM_OBJECT_DBUS_CONNECTION, async_data->connection, - NM_OBJECT_DBUS_PATH, async_data->path, - NULL); - } else { + /* Ensure we don't have the object already; we may get multiple type + * requests for the same object if there are multiple properties on + * other objects that refer to the object at this path. One of those + * other requests may have already completed. + */ + object = (GObject *) _nm_object_cache_get (async_data->path); + if (object) { + create_async_complete (object, async_data); + return; + } + + if (type == G_TYPE_INVALID) { + /* Don't know how to create this object */ create_async_complete (NULL, async_data); return; } + object = g_object_new (type, + NM_OBJECT_DBUS_CONNECTION, async_data->connection, + NM_OBJECT_DBUS_PATH, async_data->path, + NULL); + g_warn_if_fail (object != NULL); g_async_initable_init_async (G_ASYNC_INITABLE (object), G_PRIORITY_DEFAULT, NULL, async_inited, async_data); } @@ -568,6 +580,23 @@ wincaps_to_dash (const char *caps) return g_string_free (str, FALSE); } +/* Adds object to array if it's not already there */ +static void +add_to_object_array_unique (GPtrArray *array, GObject *obj) +{ + guint i; + + g_return_if_fail (array != NULL); + + if (obj != NULL) { + for (i = 0; i < array->len; i++) { + if (g_ptr_array_index (array, i) == obj) + return; + } + g_ptr_array_add (array, obj); + } +} + typedef struct { NMObject *self; PropertyInfo *pi; @@ -593,10 +622,8 @@ object_property_complete (ObjectCreatedData *odata) if (*array) g_boxed_free (NM_TYPE_OBJECT_ARRAY, *array); *array = g_ptr_array_sized_new (odata->length); - for (i = 0; i < odata->length; i++) { - if (odata->objects[i]) - g_ptr_array_add (*array, odata->objects[i]); - } + for (i = 0; i < odata->length; i++) + add_to_object_array_unique (*array, odata->objects[i]); } else { GObject **obj_p = pi->field; @@ -1068,7 +1095,7 @@ pseudo_property_object_created (GObject *obj, gpointer user_data) if (!*list_p) *list_p = g_ptr_array_new (); - g_ptr_array_add (*list_p, obj); + add_to_object_array_unique (*list_p, obj); ppi->added_func (ppi->self, NM_OBJECT (obj)); } }