diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 6ba453f28..5a17c102c 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -4396,6 +4396,7 @@ g_task_set_priority g_task_set_check_cancellable g_task_set_return_on_cancel g_task_set_source_tag +g_task_set_name g_task_report_error g_task_report_new_error @@ -4408,6 +4409,7 @@ g_task_get_return_on_cancel g_task_get_context g_task_get_source_object g_task_get_source_tag +g_task_get_name g_task_return_boolean g_task_return_int diff --git a/gio/gtask.c b/gio/gtask.c index a40bc01b4..a2f316d2e 100644 --- a/gio/gtask.c +++ b/gio/gtask.c @@ -543,6 +543,7 @@ struct _GTask { gpointer source_object; gpointer source_tag; + gchar *name; /* (owned); may only be modified before the #GTask is threaded */ gpointer task_data; GDestroyNotify task_data_destroy; @@ -637,6 +638,7 @@ g_task_finalize (GObject *object) g_clear_object (&task->source_object); g_clear_object (&task->cancellable); + g_free (task->name); if (task->context) g_main_context_unref (task->context); @@ -978,6 +980,36 @@ g_task_set_source_tag (GTask *task, TRACE (GIO_TASK_SET_SOURCE_TAG (task, source_tag)); } +/** + * g_task_set_name: + * @task: a #GTask + * @name: (nullable): a human readable name for the task, or %NULL to unset it + * + * Sets @task’s name, used in debugging and profiling. The name defaults to + * %NULL. + * + * The task name should describe in a human readable way what the task does. + * For example, ‘Open file’ or ‘Connect to network host’. It is used to set the + * name of the #GSource used for idle completion of the task. + * + * This function may only be called before the @task is first used in a thread + * other than the one it was constructed in. + * + * Since: 2.60 + */ +void +g_task_set_name (GTask *task, + const gchar *name) +{ + gchar *new_name; + + g_return_if_fail (G_IS_TASK (task)); + + new_name = g_strdup (name); + g_free (task->name); + task->name = g_steal_pointer (&new_name); +} + /** * g_task_get_source_object: * @task: a #GTask @@ -1138,6 +1170,22 @@ g_task_get_source_tag (GTask *task) return task->source_tag; } +/** + * g_task_get_name: + * @task: a #GTask + * + * Gets @task’s name. See g_task_set_name(). + * + * Returns: (nullable) (transfer none): @task’s name, or %NULL + * Since: 2.60 + */ +const gchar * +g_task_get_name (GTask *task) +{ + g_return_val_if_fail (G_IS_TASK (task), NULL); + + return task->name; +} static void g_task_return_now (GTask *task) @@ -1527,6 +1575,9 @@ g_task_run_in_thread_sync (GTask *task, * #GMainContext with @task's [priority][io-priority], and sets @source's * callback to @callback, with @task as the callback's `user_data`. * + * It will set the @source’s name to the task’s name (as set with + * g_task_set_name()), if one has been set. + * * This takes a reference on @task until @source is destroyed. * * Since: 2.36 @@ -1541,6 +1592,9 @@ g_task_attach_source (GTask *task, g_source_set_callback (source, callback, g_object_ref (task), g_object_unref); g_source_set_priority (source, task->priority); + if (task->name != NULL) + g_source_set_name (source, task->name); + g_source_attach (source, task->context); } diff --git a/gio/gtask.h b/gio/gtask.h index 92cd2b144..4fc1c859e 100644 --- a/gio/gtask.h +++ b/gio/gtask.h @@ -74,6 +74,9 @@ void g_task_set_check_cancellable (GTask *task, GLIB_AVAILABLE_IN_2_36 void g_task_set_source_tag (GTask *task, gpointer source_tag); +GLIB_AVAILABLE_IN_2_60 +void g_task_set_name (GTask *task, + const gchar *name); GLIB_AVAILABLE_IN_2_36 gpointer g_task_get_source_object (GTask *task); @@ -89,6 +92,8 @@ GLIB_AVAILABLE_IN_2_36 gboolean g_task_get_check_cancellable (GTask *task); GLIB_AVAILABLE_IN_2_36 gpointer g_task_get_source_tag (GTask *task); +GLIB_AVAILABLE_IN_2_60 +const gchar *g_task_get_name (GTask *task); GLIB_AVAILABLE_IN_2_36 gboolean g_task_is_valid (gpointer result, diff --git a/gio/tests/task.c b/gio/tests/task.c index 7f698306b..db1b2d4fe 100644 --- a/gio/tests/task.c +++ b/gio/tests/task.c @@ -614,6 +614,46 @@ test_priority (void) g_assert_cmpint (ret3, ==, 3); } +/* Test that getting and setting the task name works. */ +static void name_callback (GObject *object, + GAsyncResult *result, + gpointer user_data); + +static void +test_name (void) +{ + GTask *t1 = NULL; + gchar *name1 = NULL; + + t1 = g_task_new (NULL, NULL, name_callback, &name1); + g_task_set_name (t1, "some task"); + g_task_return_boolean (t1, TRUE); + g_object_unref (t1); + + g_main_loop_run (loop); + + g_assert_cmpstr (name1, ==, "some task"); + + g_free (name1); +} + +static void +name_callback (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + gchar **name_out = user_data; + GError *local_error = NULL; + + g_assert_null (*name_out); + *name_out = g_strdup (g_task_get_name (G_TASK (result))); + + g_task_propagate_boolean (G_TASK (result), &local_error); + g_assert_no_error (local_error); + + g_main_loop_quit (loop); +} + /* test_check_cancellable: cancellation overrides return value */ enum { @@ -793,6 +833,7 @@ run_in_thread_callback (GObject *object, g_assert (g_async_result_get_user_data (result) == user_data); g_assert (!g_task_had_error (G_TASK (result))); g_assert_false (g_task_get_completed (G_TASK (result))); + g_assert_cmpstr (g_task_get_name (G_TASK (result)), ==, "test_run_in_thread name"); ret = g_task_propagate_int (G_TASK (result), &error); g_assert_no_error (error); @@ -816,6 +857,7 @@ run_in_thread_thread (GTask *task, g_assert (task_data == g_task_get_task_data (task)); g_assert (cancellable == g_task_get_cancellable (task)); g_assert_false (g_task_get_completed (task)); + g_assert_cmpstr (g_task_get_name (task), ==, "test_run_in_thread name"); g_assert (g_thread_self () != main_thread); @@ -837,13 +879,13 @@ test_run_in_thread (void) gboolean done = FALSE; task = g_task_new (NULL, NULL, run_in_thread_callback, &done); + g_task_set_name (task, "test_run_in_thread name"); g_object_weak_ref (G_OBJECT (task), task_weak_notify, (gpointer)&weak_notify_ran); g_signal_connect (task, "notify::completed", (GCallback) completed_cb, ¬ification_emitted); g_task_set_task_data (task, (gpointer)&thread_ran, NULL); g_task_run_in_thread (task, run_in_thread_thread); - g_object_unref (task); g_mutex_lock (&run_in_thread_mutex); while (!thread_ran) @@ -858,6 +900,10 @@ test_run_in_thread (void) g_assert (done == TRUE); g_assert_true (notification_emitted); + g_assert_cmpstr (g_task_get_name (task), ==, "test_run_in_thread name"); + + g_object_unref (task); + g_mutex_lock (&run_in_thread_mutex); while (!weak_notify_ran) g_cond_wait (&run_in_thread_cond, &run_in_thread_mutex); @@ -2139,6 +2185,7 @@ main (int argc, char **argv) g_test_add_func ("/gtask/no-callback", test_no_callback); g_test_add_func ("/gtask/report-error", test_report_error); g_test_add_func ("/gtask/priority", test_priority); + g_test_add_func ("/gtask/name", test_name); g_test_add_func ("/gtask/check-cancellable", test_check_cancellable); g_test_add_func ("/gtask/return-if-cancelled", test_return_if_cancelled); g_test_add_func ("/gtask/run-in-thread", test_run_in_thread);