diff --git a/glib/gmain.c b/glib/gmain.c index c651e9147..b9b25f1e6 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -574,6 +574,8 @@ retry_decrement: } g_source_iter_clear (&iter); + g_rw_lock_writer_unlock (&source_destroy_lock); + /* Next destroy all sources. As we still hold a reference to all of them, * this won't cause any of them to be freed yet and especially prevents any * source that unrefs another source from its finalize function to be freed. @@ -584,8 +586,6 @@ retry_decrement: g_source_destroy_internal (source, context, TRUE); } - g_rw_lock_writer_unlock (&source_destroy_lock); - /* the context is going to die now */ g_return_if_fail (old_ref > 0); diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c index 243becdee..b1a21293f 100644 --- a/glib/tests/mainloop.c +++ b/glib/tests/mainloop.c @@ -2384,6 +2384,38 @@ test_maincontext_source_finalization_from_dispatch (gconstpointer user_data) g_main_context_unref (c); } +static void +callback_source_unref (gpointer cb_data) +{ + GSource *s = (GSource *) cb_data; + + g_source_destroy (s); +}; + +static GSourceCallbackFuncs callback_funcs = { + NULL, + callback_source_unref, + NULL, +}; + +static void +test_context_ref_while_in_source_callbackfuncs_unref (void) +{ + GMainContext *c = g_main_context_new (); + GSource *s; + + g_test_summary ("Tests if calling GSource API in GSourceCallbackFuncs.unref " + "does not deadlock attempting to retrieve the relevant GMainContext."); + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/3725"); + + s = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource)); + g_source_set_callback_indirect (s, s, &callback_funcs); + g_source_attach (s, c); + g_source_unref (s); + + g_main_context_unref (c); +} + static void once_cb (gpointer user_data) { @@ -2671,6 +2703,7 @@ main (int argc, char *argv[]) } g_test_add_func ("/maincontext/idle-once", test_maincontext_idle_once); g_test_add_func ("/maincontext/timeout-once", test_maincontext_timeout_once); + g_test_add_func ("/maincontext/context-ref-in-source-callbackfuncs-unref", test_context_ref_while_in_source_callbackfuncs_unref); g_test_add_func ("/mainloop/basic", test_mainloop_basic); g_test_add_func ("/mainloop/timeouts", test_timeouts);