From 0f97d90490dbacad3a40a372b3c6ac626e7c6082 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 31 Mar 2025 08:21:51 -0500 Subject: broadband-modem: remove invalid idle handler during dispose base_modem_invalid_idle() needs to keep a reference to the MMBaseModem until its done. But if the modem is cancelled during removal right before we're trying to forget about it, keeping that reference can prevent everything getting cleaned up by MMBaseModem's dispose() until after the mainloop has run again and all our removal operations are supposedly complete. MMDevice uses an explicit dispose() trigger that mitigates most of this (and requires it for other reasons, like breaking reference cycles between the modem and it's various child classes) but it's somewhat error-prone to keep the modem around if we don't really need to. Signed-off-by: Dan Williams --- src/mm-base-modem.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/mm-base-modem.c') diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c index 16f3e07b..7e142327 100644 --- a/src/mm-base-modem.c +++ b/src/mm-base-modem.c @@ -87,6 +87,7 @@ struct _MMBaseModemPrivate { * should be done by the modem. */ GCancellable *cancellable; gulong invalid_if_cancelled; + guint invalid_from_idle; gchar *device; gchar *physdev; @@ -2162,13 +2163,22 @@ mm_base_modem_get_subsystem_device_id (MMBaseModem *self) /*****************************************************************************/ +static void +clear_invalid_from_idle (MMBaseModem *self) +{ + if (self->priv->invalid_from_idle) + g_source_remove (self->priv->invalid_from_idle); + self->priv->invalid_from_idle = 0; +} + static gboolean base_modem_invalid_idle (MMBaseModem *self) { + clear_invalid_from_idle (self); + /* Ensure the modem is set invalid if we get the modem-wide cancellable * cancelled */ mm_base_modem_set_valid (self, FALSE); - g_object_unref (self); return G_SOURCE_REMOVE; } @@ -2176,9 +2186,14 @@ static void base_modem_cancelled (GCancellable *cancellable, MMBaseModem *self) { + clear_invalid_from_idle (self); + /* NOTE: Don't call set_valid() directly here, do it in an idle, and ensure * that we pass a valid reference of the modem object as context. */ - g_idle_add ((GSourceFunc)base_modem_invalid_idle, g_object_ref (self)); + self->priv->invalid_from_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc)base_modem_invalid_idle, + g_object_ref (self), + (GDestroyNotify) g_object_unref); } /*****************************************************************************/ @@ -2584,6 +2599,8 @@ dispose (GObject *object) g_cancellable_cancel (self->priv->cancellable); g_clear_object (&self->priv->cancellable); + clear_invalid_from_idle (self); + g_clear_object (&self->priv->primary); g_clear_object (&self->priv->secondary); g_list_free_full (g_steal_pointer (&self->priv->data), g_object_unref); -- cgit v1.2.3-70-g09d2