diff options
author | Thomas Haller <thaller@redhat.com> | 2018-03-29 15:33:19 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-03-29 16:42:09 +0200 |
commit | e1af22f79f76f0fd9a65449e3059a345d8885c21 (patch) | |
tree | fc92832a1d4d29e3ac91cb83f9b457ec6ba3c360 | |
parent | d169cde872c433c1985188f252e1945d4972e154 (diff) | |
download | NetworkManager-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.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, |