diff options
author | Dan Williams <dan@ioncontrol.co> | 2025-03-31 08:21:51 -0500 |
---|---|---|
committer | Dan Williams <dan@ioncontrol.co> | 2025-05-08 15:40:25 -0500 |
commit | 0f97d90490dbacad3a40a372b3c6ac626e7c6082 (patch) | |
tree | 7cff5a6003db2a21c4f1eedb748f63ef872ef976 | |
parent | 0cb1c1f157e2a4d2f75aeecc9874246359d0ca12 (diff) |
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 <dan@ioncontrol.co>
-rw-r--r-- | src/mm-base-modem.c | 21 |
1 files changed, 19 insertions, 2 deletions
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); |