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>
This commit is contained in:
Philip Withnall 2021-06-21 14:16:36 +01:00
parent 323c5d7e21
commit 72f692eae4

View File

@ -90,6 +90,13 @@ client_ref (Client *client)
return 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 static void
client_unref (Client *client) client_unref (Client *client)
{ {
@ -105,9 +112,26 @@ client_unref (Client *client)
} }
g_free (client->name); g_free (client->name);
g_free (client->name_owner); g_free (client->name_owner);
g_main_context_unref (client->main_context);
if (client->user_data_free_func != NULL) 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); g_free (client);
} }
} }