summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-08-23 07:45:41 +0200
committerThomas Haller <thaller@redhat.com>2019-09-22 16:05:50 +0200
commiteae69e33dd1865f24544c135b366eb343c5a46e6 (patch)
tree8c6cbf9aa248fc92b7b4427307e4e4128d7b7a6d
parent5131cc42455f0de7bb7538ecd2b9d811fb246d2c (diff)
downloadNetworkManager-eae69e33dd1865f24544c135b366eb343c5a46e6.tar.gz
core: extend nm_shutdown_wait_obj_*() to support notification via a GCancellable
Now nm_shutdown_wait_obj_*() supports two styles: - NM_SHUTDOWN_WAIT_TYPE_OBJECT: this just registers a weak pointer on a source GObject. As long as the object is not destroyed (and the object is not unregistered), the shutdown gets blocked. - now new is NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE: this source object is a GCancellable, and during shutdown, the system will cancel the instances to notify about the shutdown. That aside, the GCancellable is tracked exactly like a regular NM_SHUTDOWN_WAIT_TYPE_OBJECT (meaning: a weak pointer is registered and shutdown gets delayed as long as the instance lives). As the rest of the shutdown, it's not yet implemented on the shutdown-side. What is now possible is to register such cancellables, so that users can make use of this API before we fix shutdown. We cannot fix it all at the same time, so first users must be ready for this approach.
-rw-r--r--src/NetworkManagerUtils.c32
-rw-r--r--src/NetworkManagerUtils.h34
-rw-r--r--src/ppp/nm-ppp-manager.c4
-rw-r--r--src/settings/nm-secret-agent.c2
-rw-r--r--src/settings/nm-settings.c6
5 files changed, 66 insertions, 12 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index b928b8b3b4..19e51cf198 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -946,9 +946,10 @@ nm_ip_routing_rule_to_platform (const NMIPRoutingRule *rule,
struct _NMShutdownWaitObjHandle {
CList lst;
- GObject *watched_obj;
+ gpointer watched_obj;
char *msg_reason;
bool free_msg_reason:1;
+ bool is_cancellable:1;
};
static CList _shutdown_waitobj_lst_head;
@@ -967,7 +968,7 @@ _shutdown_waitobj_unregister (NMShutdownWaitObjHandle *handle)
static void
_shutdown_waitobj_cb (gpointer user_data,
- GObject *where_the_object_was)
+ GObject *where_the_object_was)
{
NMShutdownWaitObjHandle *handle = user_data;
@@ -980,6 +981,8 @@ _shutdown_waitobj_cb (gpointer user_data,
* nm_shutdown_wait_obj_register_full:
* @watched_obj: the object to watch. Takes a weak reference on the object
* to be notified when it gets destroyed.
+ * @wait_type: whether @watched_obj is just a plain GObject or a GCancellable
+ * that should be cancelled.
* @msg_reason: a reason message, for debugging and logging purposes.
* @free_msg_reason: if %TRUE, then ownership of @msg_reason will be taken
* and the string will be freed with g_free() afterwards. If %FALSE,
@@ -993,21 +996,41 @@ _shutdown_waitobj_cb (gpointer user_data,
* the reference-counter of @watched_obj as signal, that the object
* is still used.
*
+ * If @wait_type is %NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE, then during shutdown
+ * (after %NM_SHUTDOWN_TIMEOUT_MS), the cancellable will be cancelled to notify
+ * the source of the shutdown. Note that otherwise, in this mode also @watched_obj
+ * is only tracked with a weak-pointer. Especially, it does not register to the
+ * "cancelled" signal to automatically unregister (otherwise, you would never
+ * know whether the returned NMShutdownWaitObjHandle is still valid.
+ *
* FIXME(shutdown): proper shutdown is not yet implemented, and registering
* an object (currently) has no effect.
*
+ * FIXME(shutdown): during shutdown, after %NM_SHUTDOWN_TIMEOUT_MS timeout, cancel
+ * all remaining %NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE instances. Also, when somebody
+ * enqueues a cancellable after that point, cancel it right away on an idle handler.
+ *
* 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.
+ * Note that the handle is only valid as long as @watched_obj exists. If
+ * you plan to use it, ensure that you take care of not using it after
+ * destroying @watched_obj.
*/
NMShutdownWaitObjHandle *
-nm_shutdown_wait_obj_register_full (GObject *watched_obj,
+nm_shutdown_wait_obj_register_full (gpointer watched_obj,
+ NMShutdownWaitType wait_type,
char *msg_reason,
gboolean free_msg_reason)
{
NMShutdownWaitObjHandle *handle;
- g_return_val_if_fail (G_IS_OBJECT (watched_obj), NULL);
+ if (wait_type == NM_SHUTDOWN_WAIT_TYPE_OBJECT)
+ g_return_val_if_fail (G_IS_OBJECT (watched_obj), NULL);
+ else if (wait_type == NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE)
+ g_return_val_if_fail (G_IS_CANCELLABLE (watched_obj), NULL);
+ else
+ g_return_val_if_reached (NULL);
if (G_UNLIKELY (!_shutdown_waitobj_lst_head.next))
c_list_init (&_shutdown_waitobj_lst_head);
@@ -1020,6 +1043,7 @@ nm_shutdown_wait_obj_register_full (GObject *watched_obj,
.watched_obj = watched_obj,
.msg_reason = msg_reason,
.free_msg_reason = free_msg_reason,
+ .is_cancellable = (wait_type == NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE),
};
c_list_link_tail (&_shutdown_waitobj_lst_head, &handle->lst);
g_object_weak_ref (watched_obj, _shutdown_waitobj_cb, handle);
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index e957b95e29..72be1c4cf6 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -74,13 +74,43 @@ NMPlatformRoutingRule *nm_ip_routing_rule_to_platform (const NMIPRoutingRule *ru
#define NM_SHUTDOWN_TIMEOUT_MS 1500
#define NM_SHUTDOWN_TIMEOUT_MS_WATCHDOG 500
+typedef enum {
+ /* The watched_obj argument is a GObject, and shutdown is delayed until the object
+ * gets destroyed (or unregistered). */
+ NM_SHUTDOWN_WAIT_TYPE_OBJECT,
+
+ /* The watched_obj argument is a GCancellable, and shutdown is delayed until the object
+ * gets destroyed (or unregistered). Note that after NM_SHUTDOWN_TIMEOUT_MS, the
+ * cancellable will be cancelled to notify listeners about the shutdown. */
+ NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE,
+} NMShutdownWaitType;
+
typedef struct _NMShutdownWaitObjHandle NMShutdownWaitObjHandle;
-NMShutdownWaitObjHandle *nm_shutdown_wait_obj_register_full (GObject *watched_obj,
+NMShutdownWaitObjHandle *nm_shutdown_wait_obj_register_full (gpointer watched_obj,
+ NMShutdownWaitType wait_type,
char *msg_reason,
gboolean free_msg_reason);
-#define nm_shutdown_wait_obj_register(watched_obj, msg_reason) nm_shutdown_wait_obj_register_full((watched_obj), (""msg_reason""), FALSE)
+static inline NMShutdownWaitObjHandle *
+nm_shutdown_wait_obj_register_object_full (gpointer watched_obj,
+ char *msg_reason,
+ gboolean free_msg_reason)
+{
+ return nm_shutdown_wait_obj_register_full (watched_obj, NM_SHUTDOWN_WAIT_TYPE_OBJECT, msg_reason, free_msg_reason);
+}
+
+#define nm_shutdown_wait_obj_register_object(watched_obj, msg_reason) nm_shutdown_wait_obj_register_object_full((watched_obj), (""msg_reason""), FALSE)
+
+static inline NMShutdownWaitObjHandle *
+nm_shutdown_wait_obj_register_cancellable_full (GCancellable *watched_obj,
+ char *msg_reason,
+ gboolean free_msg_reason)
+{
+ return nm_shutdown_wait_obj_register_full (watched_obj, NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE, msg_reason, free_msg_reason);
+}
+
+#define nm_shutdown_wait_obj_register_cancellable(watched_obj, msg_reason) nm_shutdown_wait_obj_register_cancellable_full((watched_obj), (""msg_reason""), FALSE)
void nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle);
diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c
index ff22dbbed2..c294942286 100644
--- a/src/ppp/nm-ppp-manager.c
+++ b/src/ppp/nm-ppp-manager.c
@@ -1213,7 +1213,7 @@ _ppp_manager_stop (NMPPPManager *self,
/* No PID. There is nothing to kill, however, invoke the callback in
* an idle handler.
*
- * Note that we don't register nm_shutdown_wait_obj_register().
+ * Note that we don't register nm_shutdown_wait_obj_register_object().
* In order for shutdown to work properly, the caller must always
* explicitly cancel the action to go down. With the idle-handler,
* cancelling the handle completes the request. */
@@ -1225,7 +1225,7 @@ _ppp_manager_stop (NMPPPManager *self,
* until the process terminated. We do that, by registering an object
* that delays shutdown. */
handle->shutdown_waitobj = g_object_new (G_TYPE_OBJECT, NULL);
- nm_shutdown_wait_obj_register (handle->shutdown_waitobj, "ppp-manager-wait-kill-pppd");
+ nm_shutdown_wait_obj_register_object (handle->shutdown_waitobj, "ppp-manager-wait-kill-pppd");
nm_utils_kill_child_async (nm_steal_int (&priv->pid),
SIGTERM, LOGD_PPP, "pppd",
NM_SHUTDOWN_TIMEOUT_MS,
diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c
index 1831d89bbb..88e6a77b6e 100644
--- a/src/settings/nm-secret-agent.c
+++ b/src/settings/nm-secret-agent.c
@@ -160,7 +160,7 @@ _call_id_new (NMSecretAgent *self,
/* self has async requests (that keep self alive). As long as
* we have pending requests, shutdown is blocked. */
priv->shutdown_wait_obj_registered = TRUE;
- nm_shutdown_wait_obj_register (G_OBJECT (self), "secret-agent");
+ nm_shutdown_wait_obj_register_object (G_OBJECT (self), "secret-agent");
}
return call_id;
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index adb6636a43..f474324c20 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -3116,9 +3116,9 @@ add_plugin (NMSettings *self,
priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
- nm_shutdown_wait_obj_register_full (G_OBJECT (plugin),
- g_strdup_printf ("%s-settings-plugin", pname),
- TRUE);
+ nm_shutdown_wait_obj_register_object_full (plugin,
+ g_strdup_printf ("%s-settings-plugin", pname),
+ TRUE);
_LOGI ("Loaded settings plugin: %s (%s%s%s)",
pname,