[glib: 1/2] gtask: Add a g_task_set_name() method



commit e89128a9354280cdb5e973ce534c3512c7e66ab9
Author: Philip Withnall <withnall endlessm com>
Date:   Sun Oct 7 17:37:58 2018 +0100

    gtask: Add a g_task_set_name() method
    
    Similarly to g_source_set_name(), this sets a name on a GTask for
    debugging and profiling. Importantly, this name is propagated to the
    GSource for idle callbacks for the GTask, ending the glorious reign of
    `[gio] complete_in_idle_cb`.
    
    The name can be queried using g_task_get_name(). Locking is avoided by
    only allowing the name to be set before the GTask is used from another
    thread.
    
    Includes tests.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 docs/reference/gio/gio-sections.txt |  2 ++
 gio/gtask.c                         | 54 +++++++++++++++++++++++++++++++++++++
 gio/gtask.h                         |  5 ++++
 gio/tests/task.c                    | 49 ++++++++++++++++++++++++++++++++-
 4 files changed, 109 insertions(+), 1 deletion(-)
---
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
 <SUBSECTION>
 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
 <SUBSECTION>
 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, &notification_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);


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