diff options
Diffstat (limited to 'libnm/nm-object.c')
| -rw-r--r-- | libnm/nm-object.c | 217 |
1 files changed, 119 insertions, 98 deletions
diff --git a/libnm/nm-object.c b/libnm/nm-object.c index 3b41041e..20395ce8 100644 --- a/libnm/nm-object.c +++ b/libnm/nm-object.c @@ -95,6 +95,8 @@ typedef struct { GSList *reload_results; guint reload_remaining; GError *reload_error; + + GSList *pending; /* ordered list of pending property updates. */ } NMObjectPrivate; enum { @@ -447,7 +449,7 @@ typedef struct { GObject **objects; int length, remaining; - GPtrArray *array; + gboolean array; const char *property_name; } ObjectCreatedData; @@ -458,12 +460,10 @@ odata_free (gpointer data) g_object_unref (odata->self); g_free (odata->objects); - if (odata->array) - g_ptr_array_unref (odata->array); g_slice_free (ObjectCreatedData, odata); } -static void object_property_maybe_complete (ObjectCreatedData *odata); +static void object_property_maybe_complete (NMObject *self); typedef void (*NMObjectCreateCallbackFunc) (GObject *, const char *, gpointer); @@ -488,14 +488,29 @@ create_async_complete (GObject *object, NMObjectTypeAsyncData *async_data) static void create_async_inited (GObject *object, GAsyncResult *result, gpointer user_data) { + NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object); + NMObjectPrivate *odata_priv; NMObjectTypeAsyncData *async_data = user_data; GError *error = NULL; + ObjectCreatedData *odata; - NM_OBJECT_GET_PRIVATE (object)->inited = TRUE; + priv->inited = TRUE; if (!g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, &error)) { dbgmsg ("Could not create object for %s: %s", nm_object_get_path (NM_OBJECT (object)), error->message); + + while (priv->waiters) { + odata = priv->waiters->data; + odata_priv = NM_OBJECT_GET_PRIVATE (odata->self); + + priv->waiters = g_slist_remove (priv->waiters, odata); + if (!odata_priv->reload_error) + odata_priv->reload_error = g_error_copy (error); + odata_priv->reload_remaining--; + reload_complete (odata->self, FALSE); + } + g_error_free (error); g_clear_object (&object); } @@ -503,15 +518,12 @@ create_async_inited (GObject *object, GAsyncResult *result, gpointer user_data) create_async_complete (object, async_data); if (object) { - NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object); - /* There are some object properties whose creation couldn't proceed * because it depended on this object. */ while (priv->waiters) { - ObjectCreatedData *odata = priv->waiters->data; - + odata = priv->waiters->data; priv->waiters = g_slist_remove (priv->waiters, odata); - object_property_maybe_complete (odata); + object_property_maybe_complete (odata->self); } } } @@ -716,104 +728,117 @@ already_awaits (ObjectCreatedData *odata, GObject *object) } static void -object_property_maybe_complete (ObjectCreatedData *odata) +object_property_maybe_complete (NMObject *self) { - NMObject *self = odata->self; NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self); - PropertyInfo *pi = odata->pi; - gboolean different = TRUE; + /* The odata may hold the last reference. */ + _nm_unused gs_unref_object NMObject *self_keep_alive = g_object_ref (self); int i; - /* Only complete the array property load when all the objects are initialized. */ - for (i = 0; i < odata->length; i++) { - GObject *obj = odata->objects[i]; - NMObjectPrivate *obj_priv; - - /* Could not load the object. Perhaps it was removed. */ - if (!obj) - continue; + while (priv->pending) { + ObjectCreatedData *odata = priv->pending->data; + PropertyInfo *pi = odata->pi; + gboolean different = TRUE; - obj_priv = NM_OBJECT_GET_PRIVATE (obj); - if (!obj_priv->inited) { - - /* The object is not finished because we block its creation. */ - if (already_awaits (odata, obj)) - continue; - - if (!g_slist_find (obj_priv->waiters, odata)) - obj_priv->waiters = g_slist_prepend (obj_priv->waiters, odata); + if (odata->remaining > 0) return; - } - } - - if (odata->array) { - GPtrArray *pi_old = *((GPtrArray **) pi->field); - GPtrArray *old = odata->array; - GPtrArray *new; - - /* Build up new array */ - new = g_ptr_array_new_full (odata->length, g_object_unref); - for (i = 0; i < odata->length; i++) - add_to_object_array_unique (new, odata->objects[i]); - *((GPtrArray **) pi->field) = new; + /* Only complete the array property load when all the objects are initialized. */ + for (i = 0; i < odata->length; i++) { + GObject *obj = odata->objects[i]; + NMObjectPrivate *obj_priv; - if (pi->signal_prefix) { - GPtrArray *added = g_ptr_array_sized_new (3); - GPtrArray *removed = g_ptr_array_sized_new (3); + /* Could not load the object. Perhaps it was removed. */ + if (!obj) + continue; - /* Find objects in 'old' that do not exist in 'new' */ - array_diff (old, new, removed); + obj_priv = NM_OBJECT_GET_PRIVATE (obj); + if (!obj_priv->inited) { - /* Find objects in 'new' that do not exist in old */ - array_diff (new, old, added); + /* The object is not finished because we block its creation. */ + if (already_awaits (odata, obj)) + continue; - /* Emit added & removed */ - for (i = 0; i < removed->len; i++) { - queue_added_removed_signal (self, - pi->signal_prefix, - g_ptr_array_index (removed, i), - FALSE); + if (!g_slist_find (obj_priv->waiters, odata)) + obj_priv->waiters = g_slist_prepend (obj_priv->waiters, odata); + return; } + } - for (i = 0; i < added->len; i++) { - queue_added_removed_signal (self, - pi->signal_prefix, - g_ptr_array_index (added, i), - TRUE); + if (odata->array) { + GPtrArray *old = *((GPtrArray **) pi->field); + GPtrArray *new; + + /* Build up new array */ + new = g_ptr_array_new_full (odata->length, g_object_unref); + for (i = 0; i < odata->length; i++) + add_to_object_array_unique (new, odata->objects[i]); + + *((GPtrArray **) pi->field) = new; + + if (pi->signal_prefix) { + GPtrArray *added = g_ptr_array_sized_new (3); + GPtrArray *removed = g_ptr_array_sized_new (3); + + if (old) { + /* Find objects in 'old' that do not exist in 'new' */ + array_diff (old, new, removed); + + /* Find objects in 'new' that do not exist in old */ + array_diff (new, old, added); + } else { + for (i = 0; i < new->len; i++) + g_ptr_array_add (added, g_ptr_array_index (new, i)); + } + + /* Emit added & removed */ + for (i = 0; i < removed->len; i++) { + queue_added_removed_signal (self, + pi->signal_prefix, + g_ptr_array_index (removed, i), + FALSE); + } + + for (i = 0; i < added->len; i++) { + queue_added_removed_signal (self, + pi->signal_prefix, + g_ptr_array_index (added, i), + TRUE); + } + + different = removed->len || added->len; + g_ptr_array_unref (added); + g_ptr_array_unref (removed); + } else { + /* No added/removed signals to send, just replace the property with + * the new values. + */ + different = TRUE; } - different = removed->len || added->len; - g_ptr_array_unref (added); - g_ptr_array_unref (removed); - } else { - /* No added/removed signals to send, just replace the property with - * the new values. + /* Free old array last since it will release references, thus freeing + * any objects in the 'removed' array. */ - different = TRUE; - } - - /* Free old array last since it will release references, thus freeing - * any objects in the 'removed' array. - */ - if (pi_old) - g_ptr_array_unref (pi_old); - } else { - GObject **obj_p = pi->field; + if (old) + g_ptr_array_unref (old); + } else { + GObject **obj_p = pi->field; - different = (*obj_p != odata->objects[0]); - if (*obj_p) - g_object_unref (*obj_p); - *obj_p = odata->objects[0]; - } + different = (*obj_p != odata->objects[0]); + if (*obj_p) + g_object_unref (*obj_p); + *obj_p = odata->objects[0]; + } - if (different && odata->property_name) - _nm_object_queue_notify (self, odata->property_name); + if (different && odata->property_name) + _nm_object_queue_notify (self, odata->property_name); - if (--priv->reload_remaining == 0) - reload_complete (self, FALSE); + if (--priv->reload_remaining == 0) + reload_complete (self, TRUE); - odata_free (odata); + priv->pending = g_slist_remove (priv->pending, odata); + odata_free (odata); + } } static void @@ -831,8 +856,7 @@ object_created (GObject *obj, const char *path, gpointer user_data) } odata->objects[--odata->remaining] = obj; - if (!odata->remaining) - object_property_maybe_complete (odata); + object_property_maybe_complete (odata->self); } static gboolean @@ -849,9 +873,10 @@ handle_object_property (NMObject *self, const char *property_name, GVariant *val odata->pi = pi; odata->objects = g_new (GObject *, 1); odata->length = odata->remaining = 1; - odata->array = NULL; + odata->array = FALSE; odata->property_name = property_name; + priv->pending = g_slist_append (priv->pending, odata); priv->reload_remaining++; path = g_variant_get_string (value, NULL); @@ -888,7 +913,6 @@ handle_object_array_property (NMObject *self, const char *property_name, GVarian GPtrArray **array = pi->field; const char *path; ObjectCreatedData *odata; - guint i, len = *array ? (*array)->len : 0; npaths = g_variant_n_children (value); @@ -897,17 +921,14 @@ handle_object_array_property (NMObject *self, const char *property_name, GVarian odata->pi = pi; odata->objects = g_new0 (GObject *, npaths); odata->length = odata->remaining = npaths; + odata->array = TRUE; odata->property_name = property_name; - /* Objects known at this point. */ - odata->array = g_ptr_array_new_full (len, g_object_unref); - for (i = 0; i < len; i++) - g_ptr_array_add (odata->array, g_object_ref (g_ptr_array_index (*array, i))); - + priv->pending = g_slist_append (priv->pending, odata); priv->reload_remaining++; if (npaths == 0) { - object_property_maybe_complete (odata); + object_property_maybe_complete (self); return TRUE; } |