diff options
author | Thomas Haller <thaller@redhat.com> | 2018-05-18 13:06:03 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-05-25 12:35:49 +0200 |
commit | f09e7797d448f7fe5d9cee8c4e351ad5b3837770 (patch) | |
tree | ac0eb783ceea4f39eb2fbb704db422e5ba8acbcc | |
parent | 3fd9bf9d7d9fc0290fd25f709b60a3a8f5c7e334 (diff) | |
download | NetworkManager-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.
-rw-r--r-- | src/NetworkManagerUtils.c | 89 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 12 |
2 files changed, 101 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); +} diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 13bdb67e85..b8d3a4f064 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -53,6 +53,18 @@ int nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, const GSList *specs, int no_match_value); + +/*****************************************************************************/ + +typedef struct _NMShutdownWaitObjHandle NMShutdownWaitObjHandle; + +NMShutdownWaitObjHandle *_nm_shutdown_wait_obj_register (GObject *watched_obj, + const char *msg_reason); + +#define nm_shutdown_wait_obj_register(watched_obj, msg_reason) _nm_shutdown_wait_obj_register((watched_obj), (""msg_reason"")) + +void nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle); + /*****************************************************************************/ #endif /* __NETWORKMANAGER_UTILS_H__ */ |