[gnome-builder] task: be safer when destroying secondary task data



commit b3509627ad08792ea893e7f0edc033ff7293371c
Author: Christian Hergert <chergert redhat com>
Date:   Wed Aug 8 19:07:55 2018 -0700

    task: be safer when destroying secondary task data
    
    If we get a second return value for the task, proxy the free request back
    to the main context so that we don't hit assertions later on.

 src/libide/threading/ide-task.c | 41 ++++++++++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 13 deletions(-)
---
diff --git a/src/libide/threading/ide-task.c b/src/libide/threading/ide-task.c
index df60a73fa..1d8a7ef31 100644
--- a/src/libide/threading/ide-task.c
+++ b/src/libide/threading/ide-task.c
@@ -1046,6 +1046,12 @@ ide_task_return_cb (gpointer user_data)
   return G_SOURCE_REMOVE;
 }
 
+static gboolean
+ide_task_return_dummy_cb (gpointer data)
+{
+  return G_SOURCE_REMOVE;
+}
+
 static void
 ide_task_return (IdeTask       *self,
                  IdeTaskResult *result)
@@ -1067,6 +1073,8 @@ ide_task_return (IdeTask       *self,
 
   if (priv->return_called)
     {
+      GSource *source;
+
       if (result->type == IDE_TASK_RESULT_CANCELLED)
         {
           /* We already had a result, and now raced to be notified of
@@ -1077,21 +1085,28 @@ ide_task_return (IdeTask       *self,
           return;
         }
 
-      /*
-       * We already failed this task, but we need to ensure that the data
-       * is released from the main context rather than potentially on a
-       * thread (as we could be now).
-       *
-       * Since this can only happen when return_on_cancel is set, we can
-       * be assured the main context is alive because that is our contract
-       * with the API consumer.
+      /* If we haven't been cancelled, then we reached this path multiple
+       * times by programmer error.
        */
       if (!priv->got_cancel)
-        {
-          /* leak result to ensure we don't free anything in the wrong context */
-          g_critical ("Attempted to set task result multiple times, leaking result");
-          return;
-        }
+        g_critical ("Attempted to set result on task [%s] multiple times", priv->name);
+
+      /*
+       * This task has already returned, but we need to ensure that we pass
+       * the data back to the main context so that it is freed appropriately.
+       */
+
+      source = g_idle_source_new ();
+      g_source_set_name (source, "[ide-task] finalize task result");
+      g_source_set_ready_time (source, -1);
+      g_source_set_callback (source,
+                             ide_task_return_dummy_cb,
+                             result,
+                             (GDestroyNotify)ide_task_result_free);
+      g_source_attach (source, priv->main_context);
+      g_source_unref (source);
+
+      return;
     }
 
   priv->return_called = TRUE;


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