diff options
author | Thomas Haller <thaller@redhat.com> | 2015-09-17 17:13:30 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-09-18 18:01:55 +0200 |
commit | 45f682e22225ccff745d2688d4475b7a0f23a210 (patch) | |
tree | 932ad7d42ec1a6e88b0af63c1b508b16955d1f06 | |
parent | 24dc78957f082b12637b22bd1e5f803c7657af44 (diff) | |
download | NetworkManager-45f682e22225ccff745d2688d4475b7a0f23a210.tar.gz |
exported-object: explicitly disconnect bindings and signal handlers to GDBusInterfaceSkeleton interfaces
While an NMExportedObject is exported (i.e. registered at NMBusManager),
it has a list of GDBusInterfaceSkeleton interfaces. The properties of
the nm-object are bound to the interfaces and the signals connected.
Previously, when unexporting the NMExportedObject, we would only unref
the interfaces, but not explicitly disconnect. As there is no guarantee
that the lifetime of the interfaces is shorter then the lifetime of the
nm-object, hence, explicitly disconnect.
-rw-r--r-- | src/nm-exported-object.c | 70 |
1 files changed, 59 insertions, 11 deletions
diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c index aec73e3ade..bdf409ad17 100644 --- a/src/nm-exported-object.c +++ b/src/nm-exported-object.c @@ -353,6 +353,14 @@ nm_exported_object_meta_marshal (GClosure *closure, GValue *return_value, g_free (local_param_values); } +GQuark _skeleton_data_quark (void); +G_DEFINE_QUARK (skeleton-data, _skeleton_data); + +typedef struct { + GBinding **prop_bindings; + gulong *method_signals; +} SkeletonData; + static void nm_exported_object_create_skeletons (NMExportedObject *self, GType object_type) @@ -372,16 +380,22 @@ nm_exported_object_create_skeletons (NMExportedObject *self, for (iter = classinfo->skeleton_types; iter; iter = iter->next) { GType dbus_skeleton_type = GPOINTER_TO_SIZE (iter->data); gs_free GParamSpec **properties = NULL; + SkeletonData *skeleton_data; + guint j; interface = G_DBUS_INTERFACE_SKELETON (g_object_new (dbus_skeleton_type, NULL)); priv->interfaces = g_slist_prepend (priv->interfaces, interface); + skeleton_data = g_slice_new (SkeletonData); + /* Bind properties */ properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (interface), &n_properties); - for (i = 0; i < n_properties; i++) { + skeleton_data->prop_bindings = g_new (GBinding *, n_properties + 1); + for (i = 0, j = 0; i < n_properties; i++) { GParamSpec *nm_property; GBindingFlags flags; + GBinding *prop_binding; nm_property = g_object_class_find_property (object_class, properties[i]->name); if (!nm_property) @@ -391,23 +405,61 @@ nm_exported_object_create_skeletons (NMExportedObject *self, if ( (nm_property->flags & G_PARAM_WRITABLE) && !(nm_property->flags & G_PARAM_CONSTRUCT_ONLY)) flags |= G_BINDING_BIDIRECTIONAL; - g_object_bind_property (self, properties[i]->name, - interface, properties[i]->name, - flags); + prop_binding = g_object_bind_property (self, properties[i]->name, + interface, properties[i]->name, + flags); + if (prop_binding) + skeleton_data->prop_bindings[j++] = prop_binding; } + skeleton_data->prop_bindings[j++] = NULL; /* Bind methods */ - for (i = 0; i < classinfo->methods->len; i++) { + skeleton_data->method_signals = g_new (gulong, classinfo->methods->len + 1); + for (i = 0, j = 0; i < classinfo->methods->len; i++) { NMExportedObjectDBusMethodImpl *method = &g_array_index (classinfo->methods, NMExportedObjectDBusMethodImpl, i); GClosure *closure; + gulong method_signal; if (method->dbus_skeleton_type != dbus_skeleton_type) continue; closure = g_cclosure_new_swap (method->impl, self, NULL); g_closure_set_meta_marshal (closure, NULL, nm_exported_object_meta_marshal); - g_signal_connect_closure (interface, method->method_name, closure, FALSE); + method_signal = g_signal_connect_closure (interface, method->method_name, closure, FALSE); + + if (method_signal != 0) + skeleton_data->method_signals[j++] = method_signal; } + skeleton_data->method_signals[j++] = 0; + + g_object_set_qdata ((GObject *) interface, _skeleton_data_quark (), skeleton_data); + } +} + +static void +nm_exported_object_destroy_skeletons (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_if_fail (priv->interfaces); + + while (priv->interfaces) { + gs_unref_object GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (priv->interfaces->data); + SkeletonData *skeleton_data; + guint j; + + priv->interfaces = g_slist_remove (priv->interfaces, interface); + + skeleton_data = g_object_steal_qdata ((GObject *) interface, _skeleton_data_quark ()); + + for (j = 0; skeleton_data->prop_bindings[j]; j++) + g_object_unref (skeleton_data->prop_bindings[j]); + for (j = 0; skeleton_data->method_signals[j]; j++) + g_signal_handler_disconnect (interface, skeleton_data->method_signals[j]); + + g_free (skeleton_data->prop_bindings); + g_free (skeleton_data->method_signals); + g_slice_free (SkeletonData, skeleton_data); } } @@ -527,8 +579,7 @@ nm_exported_object_unexport (NMExportedObject *self) nm_bus_manager_unregister_object (priv->bus_mgr, self); - g_slist_free_full (priv->interfaces, g_object_unref); - priv->interfaces = NULL; + nm_exported_object_destroy_skeletons (self); g_clear_pointer (&priv->path, g_free); g_clear_object (&priv->bus_mgr); @@ -691,9 +742,6 @@ nm_exported_object_dispose (GObject *object) g_variant_builder_clear (&priv->pending_notifies); nm_clear_g_source (&priv->notify_idle_id); - g_slist_free_full (priv->interfaces, g_object_unref); - priv->interfaces = NULL; - G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object); } |