[glib/wip/otte/await] gtask: Add g_task_await()
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/otte/await] gtask: Add g_task_await()
- Date: Sun, 2 Feb 2020 05:45:50 +0000 (UTC)
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,
+ ¬ification_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]