[glib] Fix a possible deadlock



commit b2715bbc5eaa1454df879964f58e36dbed65dc77
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Aug 3 10:41:21 2010 -0400

    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;
     }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]