summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-03-29 15:33:19 +0200
committerThomas Haller <thaller@redhat.com>2018-03-29 16:42:09 +0200
commite1af22f79f76f0fd9a65449e3059a345d8885c21 (patch)
treefc92832a1d4d29e3ac91cb83f9b457ec6ba3c360
parentd169cde872c433c1985188f252e1945d4972e154 (diff)
downloadNetworkManager-th/wip/dbus-object-export-ref.tar.gz
core: make exporting of NMDBusObject ref-countedth/wip/dbus-object-export-ref
Various parts might be interested in exporting an object (and more importantly, to ensure that it stays exported long enough). Add new API nm_dbus_object_export_ref() and nm_dbus_object_unexport_ref(). Like with ref/unref, export and unexport calls must add up. Hence, to do some more assertions, do not allow mixing exclusive export calls with the new calls. An object type must either be exclusively exported via nm_dbus_object_export(), or via nm_dbus_object_export_ref().
-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,