From 08fb4ee4f601af457e11319a0c39f7b5dabd826d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 14 Jan 2020 13:58:20 +0100 Subject: [PATCH] libnm: keep context-busy-watcher of NMClient alive for one more idle round The context-busy-watch has two purposes: 1) it allows the user to watch whether the NMClient still has pending GSource'es attached to the GMainContext. 2) thereby, it also keeps the inner GMainContext integrated into the caller's (in case of synchronous initialization of NMClient). Especially for 2), we must not get this wrong. Otherwise, we might un-integrate the inner GMainContext too early and it will be leaked indefinitely (because the user has no means to access or iterate it). To be extra careful, extend the lifetime of the context-busy-watcher for one more idle invocation. Theoretically, this should not be necessary, but it's not clear whether something else is still pending. The downside of that extra safety is that it is probably unnecessary in practice. And in case where it is necessary, it hides an actual issue, making it harder to notice and fix it. (cherry picked from commit b572c0542a0ab5f39df44fdbaa93bc7d6b7a3c9e) --- libnm/nm-client.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 8e395cc436..a63dd14ccb 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -7481,6 +7481,32 @@ dispose (GObject *object) nm_clear_pointer (&priv->udev, udev_unref); + if ( priv->context_busy_watcher + && priv->dbus_context) { + GSource *cleanup_source; + + /* Technically, we cancelled all pending actions (and these actions keep + * the context_busy_watcher object alive). Also, we passed + * no destroy notify to g_dbus_connection_signal_subscribe(). + * That means, there should be no other unaccounted GSource'es left. + * + * However, we really need to be sure that the context_busy_watcher's + * lifetime matches the time that the context is busy. That is especially + * important with synchronous initialization, where the context-busy-watcher + * keeps the inner GMainContext integrated in the caller's. + * We must not g_source_destroy() that integration too early. + * + * So to be really sure all this is given, always schedule one last + * cleanup idle action with low priority. This should be the last + * thing related to this instance that keeps the context busy. */ + cleanup_source = nm_g_idle_source_new (G_PRIORITY_LOW + 10, + nm_source_func_unref_gobject, + g_steal_pointer (&priv->context_busy_watcher), + NULL); + g_source_attach (cleanup_source, priv->dbus_context); + g_source_unref (cleanup_source); + } + nm_clear_pointer (&priv->dbus_context, g_main_context_unref); nm_clear_pointer (&priv->main_context, g_main_context_unref);