[glib/wip/pwithnall/gdbus-names-livelock] gdbusnamewatching: Ensure GDestroyNotify is called in correct context
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/pwithnall/gdbus-names-livelock] gdbusnamewatching: Ensure GDestroyNotify is called in correct context
- Date: Mon, 21 Jun 2021 13:18:02 +0000 (UTC)
commit 72f692eae4954da8e0ad0651bb87984f2ed82cb1
Author: Philip Withnall <pwithnall endlessos org>
Date: Mon Jun 21 14:16:36 2021 +0100
gdbusnamewatching: Ensure GDestroyNotify is called in correct context
The documentation for `g_bus_watch_name()` implies that the
`GDestroyNotify` for the user data will be called in the current thread
default `GMainContext`. Currently, it could be called in any thread, as
`client_unref()` can be called in any thread.
Fix that by deferring it to an idle source if `client_unref()` finalises
the `Client` object in a different thread.
Signed-off-by: Philip Withnall <pwithnall endlessos org>
gio/gdbusnamewatching.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
---
diff --git a/gio/gdbusnamewatching.c b/gio/gdbusnamewatching.c
index 40aee5a3c..3688eb066 100644
--- a/gio/gdbusnamewatching.c
+++ b/gio/gdbusnamewatching.c
@@ -90,6 +90,13 @@ client_ref (Client *client)
return client;
}
+static gboolean
+free_user_data_cb (gpointer user_data)
+{
+ /* The user data is actually freed by the GDestroyNotify for the idle source */
+ return G_SOURCE_REMOVE;
+}
+
static void
client_unref (Client *client)
{
@@ -105,9 +112,26 @@ client_unref (Client *client)
}
g_free (client->name);
g_free (client->name_owner);
- g_main_context_unref (client->main_context);
+
if (client->user_data_free_func != NULL)
- client->user_data_free_func (client->user_data);
+ {
+ /* Ensure client->user_data_free_func() is called from the right thread */
+ if (client->main_context != g_main_context_get_thread_default ())
+ {
+ GSource *idle_source = g_idle_source_new ();
+ g_source_set_callback (idle_source, free_user_data_cb,
+ client->user_data,
+ client->user_data_free_func);
+ g_source_set_name (idle_source, "[gio, gdbusnamewatching.c] free_user_data_cb");
+ g_source_attach (idle_source, client->main_context);
+ g_source_unref (idle_source);
+ }
+ else
+ client->user_data_free_func (client->user_data);
+ }
+
+ g_main_context_unref (client->main_context);
+
g_free (client);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]