[gimp/gimp-2-10] app: add gimp_parallel_run_async_{full, independent}()



commit fac91ddad4f777740a6a4c1b63ee2ff7244bbd1e
Author: Ell <ell_se yahoo com>
Date:   Sun Jul 1 09:57:46 2018 -0400

    app: add gimp_parallel_run_async_{full,independent}()
    
    Remove the "independent" parameter of gimp_parallel_run_async(),
    and have the function always execute the passed callback in the
    shared async thread-pool.
    
    Add a new gimp_parallel_run_async_full() function, taking, in
    addition to a callback and a data pointer:
    
      - A priority value, controlling the priority of the callback in
        the async thread-pool queue.  0 is the default priority (used
        by gimp_parallel_run_async()), negative values have higher
        priority, and positive values have lower priority.
    
      - A destructor function for the data pointer.  This function is
        called to free the user data in case the async operation is
        canceled before execution of the callback function begins, and
        the operation is dropped from the queue and aborted without
        executing the callback.  Note that if the callback *is*
        executed, the destructor is *not* used -- it's the callback's
        responsibility to free/recycle the user data.
    
    Add a separate gimp_parallel_run_async_independent() function,
    taking the same parameters, and executing the passed callback in
    an independent thread, rather than the thread pool.  This function
    doesn't take a priority value or a destructor (and there's no
    corresponding "_full()" variant that does), since they're pointless
    for independent threads.
    
    Adapt the rest of the code to the changes.
    
    (cherry picked from commit b74e600c12ff00a304108320ad83feb1ee39040d)

 app/core/gimp-parallel.cc  | 166 +++++++++++++++++++++++++++++++--------------
 app/core/gimp-parallel.h   | 135 ++++++++++++++++++++++++++++--------
 app/core/gimphistogram.c   |   1 -
 app/gui/gui-vtable.c       |   3 +-
 app/text/gimpfontfactory.c |   6 +-
 5 files changed, 225 insertions(+), 86 deletions(-)
---
diff --git a/app/core/gimp-parallel.cc b/app/core/gimp-parallel.cc
index 12fb3765c2..d83fdf64cc 100644
--- a/app/core/gimp-parallel.cc
+++ b/app/core/gimp-parallel.cc
@@ -52,8 +52,10 @@ extern "C"
 typedef struct
 {
   GimpAsync                *async;
+  gint                      priority;
   GimpParallelRunAsyncFunc  func;
   gpointer                  user_data;
+  GDestroyNotify            user_data_destroy_func;
 } GimpParallelRunAsyncTask;
 
 typedef struct
@@ -161,9 +163,17 @@ gimp_parallel_exit (Gimp *gimp)
 }
 
 GimpAsync *
-gimp_parallel_run_async (gboolean                 independent,
-                         GimpParallelRunAsyncFunc func,
+gimp_parallel_run_async (GimpParallelRunAsyncFunc func,
                          gpointer                 user_data)
+{
+  return gimp_parallel_run_async_full (0, func, user_data, NULL);
+}
+
+GimpAsync *
+gimp_parallel_run_async_full (gint                     priority,
+                              GimpParallelRunAsyncFunc func,
+                              gpointer                 user_data,
+                              GDestroyNotify           user_data_destroy_func)
 {
   GimpAsync                *async;
   GimpParallelRunAsyncTask *task;
@@ -174,72 +184,120 @@ gimp_parallel_run_async (gboolean                 independent,
 
   task = g_slice_new (GimpParallelRunAsyncTask);
 
-  task->async     = GIMP_ASYNC (g_object_ref (async));
-  task->func      = func;
-  task->user_data = user_data;
+  task->async                  = GIMP_ASYNC (g_object_ref (async));
+  task->priority               = priority;
+  task->func                   = func;
+  task->user_data              = user_data;
+  task->user_data_destroy_func = user_data_destroy_func;
 
-  if (independent)
+  if (gimp_parallel_run_async_n_threads > 0)
     {
-      GThread *thread = g_thread_new (
-        "async-ind",
-        [] (gpointer data) -> gpointer
-        {
-          GimpParallelRunAsyncTask *task = (GimpParallelRunAsyncTask *) data;
+      GList *link;
+      GList *iter;
 
-          /* lower the thread's priority */
-#if defined (G_OS_WIN32)
-          SetThreadPriority (GetCurrentThread (), THREAD_MODE_BACKGROUND_BEGIN);
-#elif defined (HAVE_UNISTD_H) && defined (__gnu_linux__)
-          nice (+10) != -1;
-                  /* ^-- avoid "unused result" warning */
-#endif
+      link       = g_list_alloc ();
+      link->data = task;
 
-          gimp_parallel_run_async_execute_task (task);
+      g_object_set_data (G_OBJECT (async),
+                         "gimp-parallel-run-async-link", link);
 
-          return NULL;
-        },
-        task);
-
-      gimp_async_add_callback (async,
-                               [] (GimpAsync *async,
-                                   gpointer   thread)
-                               {
-                                 g_thread_join ((GThread *) thread);
-                               },
-                               thread);
-    }
-  else
-    {
-      if (gimp_parallel_run_async_n_threads > 0)
-        {
-          GList *link;
+      g_signal_connect_after (async, "cancel",
+                              G_CALLBACK (gimp_parallel_run_async_cancel),
+                              NULL);
+
+      g_mutex_lock (&gimp_parallel_run_async_mutex);
 
-          link       = g_list_alloc ();
-          link->data = task;
+      for (iter = g_queue_peek_tail_link (&gimp_parallel_run_async_queue);
+           iter;
+           iter = g_list_previous (iter))
+        {
+          GimpParallelRunAsyncTask *other_task =
+            (GimpParallelRunAsyncTask *) iter->data;
 
-          g_object_set_data (G_OBJECT (async),
-                             "gimp-parallel-run-async-link", link);
+          if (other_task->priority <= task->priority)
+            break;
+        }
 
-          g_signal_connect_after (async, "cancel",
-                                  G_CALLBACK (gimp_parallel_run_async_cancel),
-                                  NULL);
+      if (iter)
+        {
+          link->prev = iter;
+          link->next = iter->next;
 
-          g_mutex_lock (&gimp_parallel_run_async_mutex);
+          iter->next = link;
 
-          g_queue_push_tail_link (&gimp_parallel_run_async_queue, link);
-          g_cond_signal (&gimp_parallel_run_async_cond);
+          if (link->next)
+            link->next->prev = link;
+          else
+            gimp_parallel_run_async_queue.tail = link;
 
-          g_mutex_unlock (&gimp_parallel_run_async_mutex);
+          gimp_parallel_run_async_queue.length++;
         }
       else
         {
-          gimp_parallel_run_async_execute_task (task);
+          g_queue_push_head_link (&gimp_parallel_run_async_queue, link);
         }
+
+      g_cond_signal (&gimp_parallel_run_async_cond);
+
+      g_mutex_unlock (&gimp_parallel_run_async_mutex);
+    }
+  else
+    {
+      gimp_parallel_run_async_execute_task (task);
     }
 
   return async;
 }
 
+GimpAsync *
+gimp_parallel_run_async_independent (GimpParallelRunAsyncFunc func,
+                                     gpointer                 user_data)
+{
+  GimpAsync                *async;
+  GimpParallelRunAsyncTask *task;
+  GThread                  *thread;
+
+  g_return_val_if_fail (func != NULL, NULL);
+
+  async = gimp_async_new ();
+
+  task = g_slice_new0 (GimpParallelRunAsyncTask);
+
+  task->async     = GIMP_ASYNC (g_object_ref (async));
+  task->func      = func;
+  task->user_data = user_data;
+
+  thread = g_thread_new (
+    "async-ind",
+    [] (gpointer data) -> gpointer
+    {
+      GimpParallelRunAsyncTask *task = (GimpParallelRunAsyncTask *) data;
+
+      /* lower the thread's priority */
+#if defined (G_OS_WIN32)
+      SetThreadPriority (GetCurrentThread (), THREAD_MODE_BACKGROUND_BEGIN);
+#elif defined (HAVE_UNISTD_H) && defined (__gnu_linux__)
+      nice (+10) != -1;
+              /* ^-- avoid "unused result" warning */
+#endif
+
+      gimp_parallel_run_async_execute_task (task);
+
+      return NULL;
+    },
+    task);
+
+  gimp_async_add_callback (async,
+                           [] (GimpAsync *async,
+                               gpointer   thread)
+                           {
+                             g_thread_join ((GThread *) thread);
+                           },
+                           thread);
+
+  return async;
+}
+
 void
 gimp_parallel_distribute (gint                       max_n,
                           GimpParallelDistributeFunc func,
@@ -507,7 +565,8 @@ gimp_parallel_run_async_execute_task (GimpParallelRunAsyncTask *task)
 static void
 gimp_parallel_run_async_cancel (GimpAsync *async)
 {
-  GList *link;
+  GList                    *link;
+  GimpParallelRunAsyncTask *task = NULL;
 
   g_mutex_lock (&gimp_parallel_run_async_mutex);
 
@@ -519,15 +578,20 @@ gimp_parallel_run_async_cancel (GimpAsync *async)
       g_object_set_data (G_OBJECT (async),
                          "gimp-parallel-run-async-link", NULL);
 
-      g_slice_free (GimpParallelRunAsyncTask, link->data);
+      task = (GimpParallelRunAsyncTask *) link->data;
 
       g_queue_delete_link (&gimp_parallel_run_async_queue, link);
     }
 
   g_mutex_unlock (&gimp_parallel_run_async_mutex);
 
-  if (link)
+  if (task)
     {
+      if (task->user_data && task->user_data_destroy_func)
+        task->user_data_destroy_func (task->user_data);
+
+      g_slice_free (GimpParallelRunAsyncTask, task);
+
       gimp_async_abort (async);
 
       g_object_unref (async);
diff --git a/app/core/gimp-parallel.h b/app/core/gimp-parallel.h
index 4dc37c7f79..a796fb7783 100644
--- a/app/core/gimp-parallel.h
+++ b/app/core/gimp-parallel.h
@@ -35,24 +35,29 @@ typedef void (* GimpParallelDistributeAreaFunc)  (const GeglRectangle *area,
                                                   gpointer             user_data);
 
 
-void        gimp_parallel_init             (Gimp                            *gimp);
-void        gimp_parallel_exit             (Gimp                            *gimp);
-
-GimpAsync * gimp_parallel_run_async        (gboolean                         independent,
-                                            GimpParallelRunAsyncFunc         func,
-                                            gpointer                         user_data);
-
-void        gimp_parallel_distribute       (gint                             max_n,
-                                            GimpParallelDistributeFunc       func,
-                                            gpointer                         user_data);
-void        gimp_parallel_distribute_range (gsize                            size,
-                                            gsize                            min_sub_size,
-                                            GimpParallelDistributeRangeFunc  func,
-                                            gpointer                         user_data);
-void        gimp_parallel_distribute_area  (const GeglRectangle             *area,
-                                            gsize                            min_sub_area,
-                                            GimpParallelDistributeAreaFunc   func,
-                                            gpointer                         user_data);
+void        gimp_parallel_init                  (Gimp                            *gimp);
+void        gimp_parallel_exit                  (Gimp                            *gimp);
+
+GimpAsync * gimp_parallel_run_async             (GimpParallelRunAsyncFunc         func,
+                                                 gpointer                         user_data);
+GimpAsync * gimp_parallel_run_async_full        (gint                             priority,
+                                                 GimpParallelRunAsyncFunc         func,
+                                                 gpointer                         user_data,
+                                                 GDestroyNotify                   user_data_destroy_func);
+GimpAsync * gimp_parallel_run_async_independent (GimpParallelRunAsyncFunc         func,
+                                                 gpointer                         user_data);
+
+void        gimp_parallel_distribute            (gint                             max_n,
+                                                 GimpParallelDistributeFunc       func,
+                                                 gpointer                         user_data);
+void        gimp_parallel_distribute_range      (gsize                            size,
+                                                 gsize                            min_sub_size,
+                                                 GimpParallelDistributeRangeFunc  func,
+                                                 gpointer                         user_data);
+void        gimp_parallel_distribute_area       (const GeglRectangle             *area,
+                                                 gsize                            min_sub_area,
+                                                 GimpParallelDistributeAreaFunc   func,
+                                                 gpointer                         user_data);
 
 #ifdef __cplusplus
 
@@ -70,19 +75,91 @@ gimp_parallel_run_async (gboolean             independent,
 
   new (func_copy) ParallelRunAsyncFunc (func);
 
-  return gimp_parallel_run_async (independent,
-                                  [] (GimpAsync *async,
-                                      gpointer   user_data)
-                                  {
-                                    ParallelRunAsyncFunc *func_copy =
-                                      (ParallelRunAsyncFunc *) user_data;
+  return gimp_parallel_run_async_full (0,
+                                       [] (GimpAsync *async,
+                                           gpointer   user_data)
+                                       {
+                                         ParallelRunAsyncFunc *func_copy =
+                                           (ParallelRunAsyncFunc *) user_data;
+
+                                         (*func_copy) (async);
+
+                                         func_copy->~ParallelRunAsyncFunc ();
+                                         g_free (func_copy);
+                                       },
+                                       func_copy,
+                                       [] (gpointer user_data)
+                                       {
+                                         ParallelRunAsyncFunc *func_copy =
+                                           (ParallelRunAsyncFunc *) user_data;
+
+                                         func_copy->~ParallelRunAsyncFunc ();
+                                         g_free (func_copy);
+                                       });
+}
 
-                                    (*func_copy) (async);
+template <class ParallelRunAsyncFunc,
+          class DestroyFunc>
+inline GimpAsync *
+gimp_parallel_run_async_full (gint                 priority,
+                              ParallelRunAsyncFunc func,
+                              DestroyFunc          destroy_func)
+{
+  typedef struct
+  {
+    ParallelRunAsyncFunc func;
+    DestroyFunc          destroy_func;
+  } Funcs;
+
+  Funcs *funcs_copy = g_new (Funcs, 1);
+
+  new (funcs_copy) Funcs {func, destroy_func};
+
+  return gimp_parallel_run_async_full (priority,
+                                       [] (GimpAsync *async,
+                                           gpointer   user_data)
+                                       {
+                                         Funcs *funcs_copy =
+                                           (Funcs *) user_data;
+
+                                         funcs_copy->func (async);
+
+                                         funcs_copy->~Funcs ();
+                                         g_free (funcs_copy);
+                                       },
+                                       funcs_copy,
+                                       [] (gpointer user_data)
+                                       {
+                                         Funcs *funcs_copy =
+                                           (Funcs *) user_data;
+
+                                         funcs_copy->destroy_func ();
+
+                                         funcs_copy->~Funcs ();
+                                         g_free (funcs_copy);
+                                       });
+}
 
-                                    func_copy->~ParallelRunAsyncFunc ();
-                                    g_free (func_copy);
-                                  },
-                                  func_copy);
+template <class ParallelRunAsyncFunc>
+inline GimpAsync *
+gimp_parallel_run_async_independent (ParallelRunAsyncFunc func)
+{
+  ParallelRunAsyncFunc *func_copy = g_new (ParallelRunAsyncFunc, 1);
+
+  new (func_copy) ParallelRunAsyncFunc (func);
+
+  return gimp_parallel_run_async_independent ([] (GimpAsync *async,
+                                                  gpointer   user_data)
+                                              {
+                                                ParallelRunAsyncFunc *func_copy =
+                                                  (ParallelRunAsyncFunc *) user_data;
+
+                                                (*func_copy) (async);
+
+                                                func_copy->~ParallelRunAsyncFunc ();
+                                                g_free (func_copy);
+                                              },
+                                              func_copy);
 }
 
 template <class ParallelDistributeFunc>
diff --git a/app/core/gimphistogram.c b/app/core/gimphistogram.c
index 4b8e28fd46..5cfb88ab19 100644
--- a/app/core/gimphistogram.c
+++ b/app/core/gimphistogram.c
@@ -348,7 +348,6 @@ gimp_histogram_calculate_async (GimpHistogram       *histogram,
     }
 
   histogram->priv->calculate_async = gimp_parallel_run_async (
-    FALSE,
     (GimpParallelRunAsyncFunc) gimp_histogram_calculate_internal,
     context);
 
diff --git a/app/gui/gui-vtable.c b/app/gui/gui-vtable.c
index 70375743f2..b9e56a4b1e 100644
--- a/app/gui/gui-vtable.c
+++ b/app/gui/gui-vtable.c
@@ -537,8 +537,7 @@ gui_wait (Gimp         *gimp,
   if (GIMP_IS_CANCELABLE (waitable))
     {
       /* listens for a cancellation request */
-      input_async = gimp_parallel_run_async (
-        TRUE,
+      input_async = gimp_parallel_run_async_independent (
         (GimpParallelRunAsyncFunc) gui_wait_input_async,
         input_pipe);
 
diff --git a/app/text/gimpfontfactory.c b/app/text/gimpfontfactory.c
index 79c684dcaa..539f6090c1 100644
--- a/app/text/gimpfontfactory.c
+++ b/app/text/gimpfontfactory.c
@@ -340,9 +340,9 @@ gimp_font_factory_load (GimpFontFactory  *factory,
    * in the case a cache rebuild is to be done it will not block
    * the UI.
    */
-  async = gimp_parallel_run_async (TRUE,
-                                   (GimpParallelRunAsyncFunc) gimp_font_factory_load_async,
-                                   config);
+  async = gimp_parallel_run_async_independent (
+    (GimpParallelRunAsyncFunc) gimp_font_factory_load_async,
+    config);
 
   gimp_async_add_callback (async,
                            (GimpAsyncCallback) gimp_font_factory_load_async_callback,


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