mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-09 12:25:48 +01:00
GMainContext: unref pending sources on destroy
It is possible (but unlikely) that there will be a non-empty list of pending dispatches when we remove the last ref from a GMainContext. Make sure we drop the refs on the sources appropriately. Add a (now-working) testcase that demonstrates how to trigger the issue. https://bugzilla.gnome.org/show_bug.cgi?id=139699
This commit is contained in:
parent
2a3ee7ceaf
commit
8f6be404cb
@ -507,6 +507,7 @@ g_main_context_unref (GMainContext *context)
|
|||||||
GSource *source;
|
GSource *source;
|
||||||
GList *sl_iter;
|
GList *sl_iter;
|
||||||
GSourceList *list;
|
GSourceList *list;
|
||||||
|
gint i;
|
||||||
|
|
||||||
g_return_if_fail (context != NULL);
|
g_return_if_fail (context != NULL);
|
||||||
g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0);
|
g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0);
|
||||||
@ -518,6 +519,10 @@ g_main_context_unref (GMainContext *context)
|
|||||||
main_context_list = g_slist_remove (main_context_list, context);
|
main_context_list = g_slist_remove (main_context_list, context);
|
||||||
G_UNLOCK (main_context_list);
|
G_UNLOCK (main_context_list);
|
||||||
|
|
||||||
|
/* Free pending dispatches */
|
||||||
|
for (i = 0; i < context->pending_dispatches->len; i++)
|
||||||
|
g_source_unref_internal (context->pending_dispatches->pdata[i], context, FALSE);
|
||||||
|
|
||||||
/* g_source_iter_next() assumes the context is locked. */
|
/* g_source_iter_next() assumes the context is locked. */
|
||||||
LOCK_CONTEXT (context);
|
LOCK_CONTEXT (context);
|
||||||
g_source_iter_init (&iter, context, TRUE);
|
g_source_iter_init (&iter, context, TRUE);
|
||||||
|
@ -1050,6 +1050,47 @@ test_remove_invalid (void)
|
|||||||
g_test_assert_expected_messages ();
|
g_test_assert_expected_messages ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
trivial_prepare (GSource *source,
|
||||||
|
gint *timeout)
|
||||||
|
{
|
||||||
|
*timeout = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint n_finalized;
|
||||||
|
|
||||||
|
static void
|
||||||
|
trivial_finalize (GSource *source)
|
||||||
|
{
|
||||||
|
n_finalized++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_unref_while_pending (void)
|
||||||
|
{
|
||||||
|
static GSourceFuncs funcs = { trivial_prepare, NULL, NULL, trivial_finalize };
|
||||||
|
GMainContext *context;
|
||||||
|
GSource *source;
|
||||||
|
|
||||||
|
context = g_main_context_new ();
|
||||||
|
|
||||||
|
source = g_source_new (&funcs, sizeof (GSource));
|
||||||
|
g_source_attach (source, context);
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
/* Do incomplete main iteration -- get a pending source but don't dispatch it. */
|
||||||
|
g_main_context_prepare (context, NULL);
|
||||||
|
g_main_context_query (context, 0, NULL, NULL, 0);
|
||||||
|
g_main_context_check (context, 1000, NULL, 0);
|
||||||
|
|
||||||
|
/* Destroy the context */
|
||||||
|
g_main_context_unref (context);
|
||||||
|
|
||||||
|
/* Make sure we didn't leak the source */
|
||||||
|
g_assert_cmpint (n_finalized, ==, 1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef G_OS_UNIX
|
#ifdef G_OS_UNIX
|
||||||
|
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
@ -1495,6 +1536,7 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/mainloop/ready-time", test_ready_time);
|
g_test_add_func ("/mainloop/ready-time", test_ready_time);
|
||||||
g_test_add_func ("/mainloop/wakeup", test_wakeup);
|
g_test_add_func ("/mainloop/wakeup", test_wakeup);
|
||||||
g_test_add_func ("/mainloop/remove-invalid", test_remove_invalid);
|
g_test_add_func ("/mainloop/remove-invalid", test_remove_invalid);
|
||||||
|
g_test_add_func ("/mainloop/unref-while-pending", test_unref_while_pending);
|
||||||
#ifdef G_OS_UNIX
|
#ifdef G_OS_UNIX
|
||||||
g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
|
g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
|
||||||
g_test_add_func ("/mainloop/unix-fd-source", test_unix_fd_source);
|
g_test_add_func ("/mainloop/unix-fd-source", test_unix_fd_source);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user