summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nm-dbus-object.c111
-rw-r--r--src/nm-dbus-object.h13
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,