[gnome-builder] egg-task-cache: handle the cancellation in an idle callback



commit 32b5234dc22e159f22047391bc7822c0203efb06
Author: Debarshi Ray <debarshir gnome org>
Date:   Tue Mar 7 10:55:54 2017 +0100

    egg-task-cache: handle the cancellation in an idle callback
    
    The caller's GTask was created in an earlier iteration of the
    GMainLoop. Hence, the g_task_return_error_if_cancelled will complete
    immediately, and there is a possibility that the GTask might be
    destroyed before returning to the GMainLoop. If that happens, it will
    deadlock because it would be disconnecting from the GCancellable
    from the GCancellable::cancelled handler.
    
    It is also not safe to avoid disconnecting from the GCancellable, in
    case it was cancelled, because, if reset, it can emit the signal a
    second time and we will be accessing invalid memory.
    
    Hence the safest option is to handle the cancellation in an idle
    callback and immediately returning to the GMainLoop in the "cancelled"
    handler.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=779660

 contrib/egg/egg-task-cache.c |   54 +++++++++++++++++++++++++++++++-----------
 1 files changed, 40 insertions(+), 14 deletions(-)
---
diff --git a/contrib/egg/egg-task-cache.c b/contrib/egg/egg-task-cache.c
index 48e7c45..0e38ba7 100644
--- a/contrib/egg/egg-task-cache.c
+++ b/contrib/egg/egg-task-cache.c
@@ -235,13 +235,9 @@ cancelled_data_free (gpointer data)
 
   g_clear_pointer (&cancelled->key, cancelled->self->key_destroy_func);
 
-  if (cancelled->cancelled_id != 0)
-    {
-      g_cancellable_disconnect (cancelled->cancellable, cancelled->cancelled_id);
-      cancelled->cancelled_id = 0;
-
-      g_clear_object (&cancelled->cancellable);
-    }
+  g_cancellable_disconnect (cancelled->cancellable, cancelled->cancelled_id);
+  cancelled->cancelled_id = 0;
+  g_clear_object (&cancelled->cancellable);
 
   cancelled->self = NULL;
 
@@ -468,29 +464,28 @@ egg_task_cache_propagate_pointer (EggTaskCache  *self,
     }
 }
 
-static void
-egg_task_cache_cancelled_cb (GCancellable *cancellable,
-                             gpointer      user_data)
+static gboolean
+egg_task_cache_cancel_in_idle (gpointer user_data)
 {
   EggTaskCache *self;
   CancelledData *data;
+  GCancellable *cancellable;
   GPtrArray *queued;
   GTask *task = user_data;
   gboolean cancelled = FALSE;
 
-  g_assert (G_IS_CANCELLABLE (cancellable));
   g_assert (G_IS_TASK (task));
 
   self = g_task_get_source_object (task);
+  cancellable = g_task_get_cancellable (task);
   data = g_task_get_task_data (task);
 
   g_assert (EGG_IS_TASK_CACHE (self));
+  g_assert (G_IS_CANCELLABLE (cancellable));
   g_assert (data != NULL);
   g_assert (data->self == self);
   g_assert (data->cancellable == cancellable);
 
-  data->cancelled_id = 0;
-
   if ((queued = g_hash_table_lookup (self->queued, data->key)))
     {
       for (guint i = 0; i < queued->len; i++)
@@ -525,7 +520,38 @@ egg_task_cache_cancelled_cb (GCancellable *cancellable,
         }
     }
 
-  g_return_if_fail (cancelled);
+  g_return_val_if_fail (cancelled, G_SOURCE_REMOVE);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+egg_task_cache_cancelled_cb (GCancellable *cancellable,
+                             gpointer      user_data)
+{
+  EggTaskCache *self;
+  CancelledData *data;
+  GMainContext *context;
+  g_autoptr(GSource) source = NULL;
+  GTask *task = user_data;
+
+  g_assert (G_IS_CANCELLABLE (cancellable));
+  g_assert (G_IS_TASK (task));
+
+  self = g_task_get_source_object (task);
+  data = g_task_get_task_data (task);
+
+  g_assert (EGG_IS_TASK_CACHE (self));
+  g_assert (data != NULL);
+  g_assert (data->self == self);
+  g_assert (data->cancellable == cancellable);
+
+  source = g_idle_source_new ();
+  g_source_set_callback (source, egg_task_cache_cancel_in_idle, g_object_ref (task), g_object_unref);
+  g_source_set_name (source, "[egg] egg_task_cache_cancel_in_idle");
+
+  context = g_main_context_get_thread_default ();
+  g_source_attach (source, context);
 }
 
 static void


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