diff options
-rw-r--r-- | src/nm-dbus-object.c | 111 | ||||
-rw-r--r-- | src/nm-dbus-object.h | 13 |
2 files changed, 93 insertions, 31 deletions
diff --git a/src/nm-dbus-object.c b/src/nm-dbus-object.c index cd3a23509e..efff436584 100644 --- a/src/nm-dbus-object.c +++ b/src/nm-dbus-object.c @@ -84,6 +84,69 @@ _create_export_path (NMDBusObjectClass *klass) return g_strdup (klass->export_path.path); } +static const char * +_export (NMDBusObject *self, gboolean allow_multiref) +{ + static guint64 id_counter = 0; + + g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); + +#define PATH_REF_NO_MULTI G_MAXUINT + + if (allow_multiref) { + if (self->internal.path_ref > 0) { + nm_assert (self->internal.path); + g_return_val_if_fail (self->internal.path_ref != PATH_REF_NO_MULTI, self->internal.path); + self->internal.path_ref++; + return self->internal.path; + } + nm_assert (!self->internal.path); + self->internal.path_ref = 1; + } else { + g_return_val_if_fail (self->internal.path_ref == 0, self->internal.path); + nm_assert (!self->internal.path); + self->internal.path_ref = PATH_REF_NO_MULTI; + } + + self->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self)); + + self->internal.export_version_id = ++id_counter; + + _LOGT ("export: \"%s\"", self->internal.path); + + _nm_dbus_manager_obj_export (self); + + _notify (self, PROP_PATH); + return self->internal.path; +} + +static void +_unexport (NMDBusObject *self, gboolean allow_multiref) +{ + g_return_if_fail (NM_IS_DBUS_OBJECT (self)); + + g_return_if_fail (self->internal.path_ref > 0); + nm_assert (self->internal.path); + + if (allow_multiref) { + g_return_if_fail (self->internal.path_ref != PATH_REF_NO_MULTI); + if (--self->internal.path_ref > 0) + return; + } else { + g_return_if_fail (self->internal.path_ref == PATH_REF_NO_MULTI); + self->internal.path_ref = 0; + } + + _LOGT ("unexport: \"%s\"", self->internal.path); + + _nm_dbus_manager_obj_unexport (self); + + g_clear_pointer (&self->internal.path, g_free); + self->internal.export_version_id = 0; + + _notify (self, PROP_PATH); +} + /** * nm_dbus_object_export: * @self: an #NMDBusObject @@ -101,22 +164,13 @@ _create_export_path (NMDBusObjectClass *klass) const char * nm_dbus_object_export (NMDBusObject *self) { - static guint64 id_counter = 0; - - g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); - - g_return_val_if_fail (!self->internal.path, self->internal.path); - - self->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self)); - - self->internal.export_version_id = ++id_counter; - - _LOGT ("export: \"%s\"", self->internal.path); - - _nm_dbus_manager_obj_export (self); + return _export (self, FALSE); +} - _notify (self, PROP_PATH); - return self->internal.path; +const char * +nm_dbus_object_export_ref (NMDBusObject *self) +{ + return _export (self, TRUE); } /** @@ -129,24 +183,19 @@ nm_dbus_object_export (NMDBusObject *self) void nm_dbus_object_unexport (NMDBusObject *self) { - g_return_if_fail (NM_IS_DBUS_OBJECT (self)); - - g_return_if_fail (self->internal.path); - - _LOGT ("unexport: \"%s\"", self->internal.path); - - _nm_dbus_manager_obj_unexport (self); - - g_clear_pointer (&self->internal.path, g_free); - self->internal.export_version_id = 0; + return _unexport (self, FALSE); +} - _notify (self, PROP_PATH); +void +nm_dbus_object_unexport_ref (NMDBusObject *self) +{ + return _unexport (self, TRUE); } /*****************************************************************************/ void -_nm_dbus_object_clear_and_unexport (NMDBusObject **location) +_nm_dbus_object_clear_and_unexport (NMDBusObject **location, gboolean allow_multiref) { NMDBusObject *self; @@ -159,7 +208,7 @@ _nm_dbus_object_clear_and_unexport (NMDBusObject **location) g_return_if_fail (NM_IS_DBUS_OBJECT (self)); if (self->internal.path) - nm_dbus_object_unexport (self); + _unexport (self, allow_multiref); g_object_unref (self); } @@ -282,7 +331,11 @@ dispose (GObject *object) if (!quitting) { if (self->internal.path) { g_warn_if_reached (); - nm_dbus_object_unexport (self); + /* Just hit a bug. You must unexport the objects before dispoing it. + * Hack around it, by setting the path_ref to one exclusive reference + * and forcefully unexport. */ + self->internal.path_ref = PATH_REF_NO_MULTI; + _unexport (self, FALSE); } } else if (nm_clear_g_free (&self->internal.path)) { /* FIXME: do a proper, coordinate shutdown, so that no objects stay diff --git a/src/nm-dbus-object.h b/src/nm-dbus-object.h index f6629289a5..05102aa167 100644 --- a/src/nm-dbus-object.h +++ b/src/nm-dbus-object.h @@ -99,6 +99,10 @@ struct _NMDBusObjectInternal { * unexported, or even re-exported afterwards. If that happens, we want * to fail the request. For that, we keep track of a version id. */ guint64 export_version_id; + + /** exporting an object is ref-counted. This is the reference count + * of how many callers exported this object. ref/unref must match. */ + guint path_ref; }; struct _NMDBusObject { @@ -172,8 +176,13 @@ nm_dbus_object_is_exported (NMDBusObject *self) const char *nm_dbus_object_export (NMDBusObject *self); void nm_dbus_object_unexport (NMDBusObject *self); -void _nm_dbus_object_clear_and_unexport (NMDBusObject **location); -#define nm_dbus_object_clear_and_unexport(location) _nm_dbus_object_clear_and_unexport ((NMDBusObject **) (location)) +const char *nm_dbus_object_export_ref (NMDBusObject *self); +void nm_dbus_object_unexport_ref (NMDBusObject *self); + +void _nm_dbus_object_clear_and_unexport (NMDBusObject **location, gboolean allow_multiref); + +#define nm_dbus_object_clear_and_unexport(location) _nm_dbus_object_clear_and_unexport ((NMDBusObject **) (location), FALSE) +#define nm_dbus_object_clear_and_unexport_ref(location) _nm_dbus_object_clear_and_unexport ((NMDBusObject **) (location), TRUE) void nm_dbus_object_emit_signal_variant (NMDBusObject *self, const NMDBusInterfaceInfoExtended *interface_info, |