From b2715bbc5eaa1454df879964f58e36dbed65dc77 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 3 Aug 2010 10:41:21 -0400 Subject: [PATCH] Fix a possible deadlock the FdSource was calling g_cancellable_disconnect while holding the main context lock, which is bad news if the ::cancelled handler is trying to get that lock to wake up the mainloop... Bug 586432 --- gio/gasynchelper.c | 8 ++++++-- gio/tests/unix-streams.c | 22 +--------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c index b439703..8e2e8e6 100644 --- a/gio/gasynchelper.c +++ b/gio/gasynchelper.c @@ -86,9 +86,13 @@ fd_source_finalize (GSource *source) { FDSource *fd_source = (FDSource *)source; + /* we don't use g_cancellable_disconnect() here, since we are holding + * the main context lock here, and the ::disconnect signal handler + * will try to grab that, and deadlock looms. + */ if (fd_source->cancelled_tag) - g_cancellable_disconnect (fd_source->cancellable, - fd_source->cancelled_tag); + g_signal_handler_disconnect (fd_source->cancellable, + fd_source->cancelled_tag); if (fd_source->cancellable) g_object_unref (fd_source->cancellable); diff --git a/gio/tests/unix-streams.c b/gio/tests/unix-streams.c index ea34017..2d06b8e 100644 --- a/gio/tests/unix-streams.c +++ b/gio/tests/unix-streams.c @@ -33,16 +33,6 @@ int writer_pipe[2], reader_pipe[2]; GCancellable *writer_cancel, *reader_cancel, *main_cancel; GMainLoop *loop; -static gboolean -cancel_main (gpointer data) -{ - GCancellable *main_cancel = data; - - g_cancellable_cancel (main_cancel); - - return FALSE; -} - static gpointer writer_thread (gpointer user_data) @@ -74,17 +64,7 @@ writer_thread (gpointer user_data) if (g_cancellable_is_cancelled (writer_cancel)) { - /* FIXME: directly calling g_cancellable_cancel (main_cancel) here - * leads to sporadic deadlock, because it will try to wake up the - * main context, for which it needs to acquire the main context lock. - * This lock may be held by the main loop running in the main thread, - * and it may be held while the main thread is blocking in - * fd_source_finalize -> g_cancellable_disconnect - * until the ::cancelled callbacks have run. - * - * Work around by deferring the cancellation to a timeout. - */ - g_timeout_add (0, cancel_main, main_cancel); + g_cancellable_cancel (main_cancel); g_object_unref (out); return NULL; } -- 2.7.4