summaryrefslogtreecommitdiff
path: root/src/NetworkManagerUtils.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-05-18 13:06:03 +0200
committerThomas Haller <thaller@redhat.com>2018-05-25 12:35:49 +0200
commitf09e7797d448f7fe5d9cee8c4e351ad5b3837770 (patch)
treeac0eb783ceea4f39eb2fbb704db422e5ba8acbcc /src/NetworkManagerUtils.c
parent3fd9bf9d7d9fc0290fd25f709b60a3a8f5c7e334 (diff)
downloadNetworkManager-f09e7797d448f7fe5d9cee8c4e351ad5b3837770.tar.gz
core: add nm_shutdown_register_watchdog() for marking object to wait for shutdown
Eventually we should do a coordinated shutdown when NetworkManager exits. That is a large work, ensuring that all asynchronous actions are cancellable (in time), and that we wait for all pending operations to complete. Add a function nm_shutdown_register_watchdog(), so that objects can register themselves, to block shutdown until they are destroyed. It's not yet used, because actually iterating the mainloop during shutdown can only be done, once the code is prepared to be ready for that. But we already need the function, so that we can refactor individual parts of the code, in preparation of using it in the future.
Diffstat (limited to 'src/NetworkManagerUtils.c')
-rw-r--r--src/NetworkManagerUtils.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 78e1ac19c3..a3bd601359 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -23,6 +23,8 @@
#include "NetworkManagerUtils.h"
+#include "nm-utils/nm-c-list.h"
+
#include "nm-common-macros.h"
#include "nm-utils.h"
#include "nm-setting-connection.h"
@@ -907,3 +909,90 @@ nm_match_spec_device_by_pllink (const NMPlatformLink *pllink,
return no_match_value;
}
+/*****************************************************************************/
+
+struct _NMShutdownWaitObjHandle {
+ CList lst;
+ GObject *watched_obj;
+ const char *msg_reason;
+};
+
+static CList _shutdown_waitobj_lst_head;
+
+static void
+_shutdown_waitobj_unregister (NMShutdownWaitObjHandle *handle)
+{
+ c_list_unlink_stale (&handle->lst);
+ g_slice_free (NMShutdownWaitObjHandle, handle);
+
+ /* FIXME(shutdown): check whether the object list is empty, and
+ * signal shutdown-complete */
+}
+
+static void
+_shutdown_waitobj_cb (gpointer user_data,
+ GObject *where_the_object_was)
+{
+ NMShutdownWaitObjHandle *handle = user_data;
+
+ nm_assert (handle);
+ nm_assert (handle->watched_obj == where_the_object_was);
+ _shutdown_waitobj_unregister (handle);
+}
+
+/**
+ * _nm_shutdown_wait_obj_register:
+ * @watched_obj: the object to watch. Takes a weak reference on the object
+ * to be notified when it gets destroyed.
+ * @msg_reason: a reason message, for debugging and logging purposes. It
+ * must be a static string. Or at least, be alive at least as long as
+ * @watched_obj. So, theoretically, if you need a dynamic @msg_reason,
+ * you could attach it to @watched_obj's user-data.
+ *
+ * Keep track of @watched_obj until it gets destroyed. During shutdown,
+ * we wait until all watched objects are destroyed. This is useful, if
+ * this object still conducts some asynchronous action, which needs to
+ * complete before NetworkManager is allowed to terminate. We re-use
+ * the reference-counter of @watched_obj as signal, that the object
+ * is still used.
+ *
+ * FIXME(shutdown): proper shutdown is not yet implemented, and registering
+ * an object (currently) has no effect.
+ *
+ * Returns: a handle to unregister the object. The caller may choose to ignore
+ * the handle, in which case, the object will be automatically unregistered,
+ * once it gets destroyed.
+ */
+NMShutdownWaitObjHandle *
+_nm_shutdown_wait_obj_register (GObject *watched_obj,
+ const char *msg_reason)
+{
+ NMShutdownWaitObjHandle *handle;
+
+ g_return_val_if_fail (G_IS_OBJECT (watched_obj), NULL);
+
+ if (G_UNLIKELY (!_shutdown_waitobj_lst_head.next))
+ c_list_init (&_shutdown_waitobj_lst_head);
+
+ handle = g_slice_new (NMShutdownWaitObjHandle);
+ handle->watched_obj = watched_obj;
+ /* we don't clone the string. We require the caller to use pass a static message.
+ * If he really cannot do that, he should attach the string to the watched_obj
+ * as user-data. */
+ handle->msg_reason = msg_reason;
+ c_list_link_tail (&_shutdown_waitobj_lst_head, &handle->lst);
+ g_object_weak_ref (watched_obj, _shutdown_waitobj_cb, handle);
+ return handle;
+}
+
+void
+nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle)
+{
+ g_return_if_fail (handle);
+
+ nm_assert (G_IS_OBJECT (handle->watched_obj));
+ nm_assert (nm_c_list_contains_entry (&_shutdown_waitobj_lst_head, handle, lst));
+
+ g_object_weak_unref (handle->watched_obj, _shutdown_waitobj_cb, handle);
+ _shutdown_waitobj_unregister (handle);
+}