[glib/wip/otte/await] gtask: Add g_task_await()



commit bf7785ba3fd391be4072fef0f2335cc51483c326
Author: Benjamin Otte <otte redhat com>
Date:   Sun Feb 2 06:23:48 2020 +0100

    gtask: Add g_task_await()

 docs/reference/gio/gio-sections-common.txt |  1 +
 gio/gtask.c                                | 52 ++++++++++++++++++++++++++++--
 gio/gtask.h                                |  2 ++
 gio/tests/task.c                           | 40 +++++++++++++++++++++++
 4 files changed, 92 insertions(+), 3 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt
index cd62b8a44..2b64ff1c1 100644
--- a/docs/reference/gio/gio-sections-common.txt
+++ b/docs/reference/gio/gio-sections-common.txt
@@ -4490,6 +4490,7 @@ g_task_get_completed
 <SUBSECTION>
 g_task_run_in_thread
 g_task_run_in_thread_sync
+g_task_await
 GTaskThreadFunc
 g_task_attach_source
 <SUBSECTION>
diff --git a/gio/gtask.c b/gio/gtask.c
index 2059e5147..a99a367c5 100644
--- a/gio/gtask.c
+++ b/gio/gtask.c
@@ -1204,6 +1204,9 @@ g_task_get_name (GTask *task)
 static void
 g_task_return_now (GTask *task)
 {
+  if (task->completed)
+    return;
+
   TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object, task->callback,
                                  task->callback_data));
 
@@ -1345,9 +1348,9 @@ g_task_thread_complete (GTask *task)
   if (task->cancellable)
     g_signal_handlers_disconnect_by_func (task->cancellable, task_thread_cancelled, task);
 
-  if (task->synchronous)
-    g_cond_signal (&task->cond);
-  else
+  g_cond_signal (&task->cond);
+
+  if (!task->synchronous)
     g_task_return (task, G_TASK_RETURN_FROM_THREAD);
 }
 
@@ -1590,6 +1593,49 @@ g_task_run_in_thread_sync (GTask           *task,
   g_object_unref (task);
 }
 
+/**
+ * g_task_await:
+ * @task: a #GTask that g_task_run_in_thread() has been called on
+ *     but that hasn't completed yet.
+ *
+ * Waits for @task to return a task run via g_task_run_in_thread() or be
+ * cancelled. You can use g_task_propagate_pointer(), etc, afterward
+ * to get the result of @task_func.
+ *
+ * The `callback` registered with @task will not be invoked when @task_func
+ * returns. #GTask:completed will be set to %TRUE just before this function
+ * returns.
+ **/
+void
+g_task_await (GTask *task)
+{
+  g_return_if_fail (G_IS_TASK (task));
+  g_return_if_fail (G_TASK_IS_THREADED (task));
+  /* FIXME: How to test? This one fails because of NULL != g_main_context_get_default()
+  g_return_if_fail (task->context == g_main_context_get_thread_default ());
+  */
+  g_return_if_fail (!task->completed);
+
+  g_object_ref (task);
+
+  g_mutex_lock (&task->lock);
+
+  while (!task->thread_complete)
+    g_cond_wait (&task->cond, &task->lock);
+
+  g_mutex_unlock (&task->lock);
+
+  TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object,
+                                 NULL  /* callback */,
+                                 NULL  /* callback data */));
+
+  /* Notify of completion in this thread. */
+  task->completed = TRUE;
+  g_object_notify (G_OBJECT (task), "completed");
+
+  g_object_unref (task);
+}
+
 /**
  * g_task_attach_source:
  * @task: a #GTask
diff --git a/gio/gtask.h b/gio/gtask.h
index 73a31e157..a269c9e57 100644
--- a/gio/gtask.h
+++ b/gio/gtask.h
@@ -110,6 +110,8 @@ void          g_task_run_in_thread        (GTask           *task,
 GLIB_AVAILABLE_IN_2_36
 void          g_task_run_in_thread_sync   (GTask           *task,
                                            GTaskThreadFunc  task_func);
+GLIB_AVAILABLE_IN_2_64
+void          g_task_await                (GTask           *task);
 GLIB_AVAILABLE_IN_2_36
 gboolean      g_task_set_return_on_cancel (GTask           *task,
                                            gboolean         return_on_cancel);
diff --git a/gio/tests/task.c b/gio/tests/task.c
index cca05ced1..9b113df79 100644
--- a/gio/tests/task.c
+++ b/gio/tests/task.c
@@ -1117,6 +1117,44 @@ test_run_in_thread_sync (void)
   g_object_unref (task);
 }
 
+/* test_run_in_thread_await */
+
+static void
+test_run_in_thread_await (gconstpointer data)
+{
+  GTask *task;
+  gboolean thread_ran = FALSE;
+  gssize ret;
+  gboolean notification_emitted = FALSE;
+  GError *error = NULL;
+  guint sleep_time = GPOINTER_TO_UINT (data);
+
+  task = g_task_new (NULL, NULL, run_in_thread_sync_callback, NULL);
+  g_signal_connect (task, "notify::completed",
+                    (GCallback) completed_cb,
+                    &notification_emitted);
+
+  g_task_set_task_data (task, &thread_ran, NULL);
+  g_task_run_in_thread (task, run_in_thread_sync_thread);
+  if (sleep_time)
+    g_usleep (sleep_time);
+  g_task_await (task);
+
+  g_assert (thread_ran == TRUE);
+  g_assert (task != NULL);
+  g_assert (!g_task_had_error (task));
+  g_assert_true (g_task_get_completed (task));
+  g_assert_true (notification_emitted);
+
+  ret = g_task_propagate_int (task, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (ret, ==, magic);
+
+  g_assert (!g_task_had_error (task));
+
+  g_object_unref (task);
+}
+
 /* test_run_in_thread_priority */
 
 static GMutex fake_task_mutex, last_fake_task_mutex;
@@ -2382,6 +2420,8 @@ main (int argc, char **argv)
   g_test_add_func ("/gtask/return-if-cancelled", test_return_if_cancelled);
   g_test_add_func ("/gtask/run-in-thread", test_run_in_thread);
   g_test_add_func ("/gtask/run-in-thread-sync", test_run_in_thread_sync);
+  g_test_add_data_func ("/gtask/run-in-thread-await", GUINT_TO_POINTER (0), test_run_in_thread_await);
+  g_test_add_data_func ("/gtask/run-in-thread-sleep-and-await", GUINT_TO_POINTER (50), 
test_run_in_thread_await);
   g_test_add_func ("/gtask/run-in-thread-priority", test_run_in_thread_priority);
   g_test_add_func ("/gtask/run-in-thread-nested", test_run_in_thread_nested);
   g_test_add_func ("/gtask/run-in-thread-overflow", test_run_in_thread_overflow);


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