[gnome-builder] thread-pool: introduce IdeThreadPool helpers



commit 0e9dcc48bea16d7974e4156ed78b4642d15ba626
Author: Christian Hergert <christian hergert me>
Date:   Thu Apr 23 14:10:29 2015 -0700

    thread-pool: introduce IdeThreadPool helpers
    
    While working on workbench restoration, I got into a situation where
    all the files would try to immediately start compiling. While we should
    put throttles on this in other places as well, we can also help mitigate
    starvation of other important tasks by limiting the number of active
    compilation requests.
    
    This simple thread pool abstraction allows us to perform minimal changes
    to task execution (g_task_run_in_thread()) while giving us the ability
    to run the task in a special run queue.
    
    This uses the "compiler" run queue for makecache and clang work items.

 libide/Makefile.am                        |    3 +
 libide/autotools/ide-makecache.c          |   19 ++++-
 libide/clang/ide-clang-service.c          |    5 +-
 libide/clang/ide-clang-translation-unit.c |    6 +-
 libide/ide-enums.c.template               |    1 +
 libide/ide-internal.h                     |    1 +
 libide/ide-thread-pool.c                  |  117 +++++++++++++++++++++++++++++
 libide/ide-thread-pool.h                  |   38 +++++++++
 libide/ide.c                              |    3 +
 9 files changed, 187 insertions(+), 6 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 0eb113b..7920d6f 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -180,6 +180,8 @@ libide_1_0_la_public_sources = \
        libide/ide-test-case.h \
        libide/ide-test-suite.c \
        libide/ide-test-suite.h \
+        libide/ide-thread-pool.c \
+        libide/ide-thread-pool.h \
        libide/ide-types.h \
        libide/ide-unsaved-file.c \
        libide/ide-unsaved-file.h \
@@ -375,6 +377,7 @@ libide_1_0_la_type_headers = \
        libide/ide-diagnostic.h \
        libide/ide-highlighter.h \
        libide/ide-source-view.h \
+        libide/ide-thread-pool.h \
        $(NULL)
 
 libide_1_0_la_built_sources = \
diff --git a/libide/autotools/ide-makecache.c b/libide/autotools/ide-makecache.c
index f9681d6..f6296a3 100644
--- a/libide/autotools/ide-makecache.c
+++ b/libide/autotools/ide-makecache.c
@@ -37,6 +37,7 @@
 #include "ide-makecache.h"
 #include "ide-makecache-target.h"
 #include "ide-project.h"
+#include "ide-thread-pool.h"
 #include "ide-vcs.h"
 
 #define FAKE_CC  "__LIBIDE_FAKE_CC__"
@@ -234,7 +235,10 @@ ide_makecache_discover_llvm_flags_async (IdeMakecache        *self,
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   task = g_task_new (self, cancellable, callback, user_data);
-  g_task_run_in_thread (task, ide_makecache_discover_llvm_flags_worker);
+
+  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
+                             task,
+                             ide_makecache_discover_llvm_flags_worker);
 
   IDE_EXIT;
 }
@@ -1145,7 +1149,9 @@ ide_makecache__discover_llvm_flags_cb (GObject      *object,
 
   self->llvm_flags = flags;
 
-  g_task_run_in_thread (task, ide_makecache_new_worker);
+  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
+                             task,
+                             ide_makecache_new_worker);
 }
 
 void
@@ -1290,7 +1296,9 @@ ide_makecache_get_file_targets_async (IdeMakecache        *self,
       IDE_EXIT;
     }
 
-  g_task_run_in_thread (task, ide_makecache_get_file_targets_worker);
+  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
+                             task,
+                             ide_makecache_get_file_targets_worker);
 
   IDE_EXIT;
 }
@@ -1368,7 +1376,10 @@ ide_makecache__get_targets_cb (GObject      *object,
   lookup->relative_path = g_strdup (relative_path);
 
   g_task_set_task_data (task, lookup, file_flags_lookup_free);
-  g_task_run_in_thread (task, ide_makecache_get_file_flags_worker);
+
+  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
+                             task,
+                             ide_makecache_get_file_flags_worker);
 
   IDE_EXIT;
 }
diff --git a/libide/clang/ide-clang-service.c b/libide/clang/ide-clang-service.c
index 87ebbac..60ece86 100644
--- a/libide/clang/ide-clang-service.c
+++ b/libide/clang/ide-clang-service.c
@@ -29,6 +29,7 @@
 #include "ide-debug.h"
 #include "ide-file.h"
 #include "ide-highlight-index.h"
+#include "ide-thread-pool.h"
 #include "ide-unsaved-file.h"
 #include "ide-unsaved-files.h"
 
@@ -383,7 +384,9 @@ ide_clang_service__get_build_flags_cb (GObject      *object,
   }
 #endif
 
-  g_task_run_in_thread (task, ide_clang_service_parse_worker);
+  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
+                             task,
+                             ide_clang_service_parse_worker);
 }
 
 static gboolean
diff --git a/libide/clang/ide-clang-translation-unit.c b/libide/clang/ide-clang-translation-unit.c
index b65bc88..25b54e0 100644
--- a/libide/clang/ide-clang-translation-unit.c
+++ b/libide/clang/ide-clang-translation-unit.c
@@ -34,6 +34,7 @@
 #include "ide-ref-ptr.h"
 #include "ide-source-location.h"
 #include "ide-symbol.h"
+#include "ide-thread-pool.h"
 #include "ide-unsaved-file.h"
 #include "ide-unsaved-files.h"
 #include "ide-vcs.h"
@@ -711,7 +712,10 @@ ide_clang_translation_unit_code_complete_async (IdeClangTranslationUnit *self,
    */
 
   g_task_set_task_data (task, state, code_complete_state_free);
-  g_task_run_in_thread (task, ide_clang_translation_unit_code_complete_worker);
+
+  ide_thread_pool_push_task (IDE_THREAD_POOL_COMPILER,
+                             task,
+                             ide_clang_translation_unit_code_complete_worker);
 
   IDE_EXIT;
 }
diff --git a/libide/ide-enums.c.template b/libide/ide-enums.c.template
index b60ca20..04dce32 100644
--- a/libide/ide-enums.c.template
+++ b/libide/ide-enums.c.template
@@ -9,6 +9,7 @@
 #include "ide-diagnostic.h"
 #include "ide-highlighter.h"
 #include "ide-source-view.h"
+#include "ide-thread-pool.h"
 
 /*** END file-header ***/
 
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index dce6f68..0a27226 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -105,6 +105,7 @@ IdeSymbol          *_ide_symbol_new                    (const gchar           *n
                                                         IdeSourceLocation     *declaration_location,
                                                         IdeSourceLocation     *definition_location,
                                                         IdeSourceLocation     *canonical_location);
+void                _ide_thread_pool_init              (void);
 IdeUnsavedFile     *_ide_unsaved_file_new              (GFile                 *file,
                                                         GBytes                *content,
                                                         const gchar           *temp_path,
diff --git a/libide/ide-thread-pool.c b/libide/ide-thread-pool.c
new file mode 100644
index 0000000..07910c1
--- /dev/null
+++ b/libide/ide-thread-pool.c
@@ -0,0 +1,117 @@
+/* ide-thread-pool.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-thread-pool"
+
+#include "ide-debug.h"
+#include "ide-thread-pool.h"
+
+#define COMPILER_MAX_THREADS 4
+
+typedef struct
+{
+  GTask           *task;
+  GTaskThreadFunc  func;
+} WorkItem;
+
+static GThreadPool *gThreadPools [IDE_THREAD_POOL_LAST];
+
+static inline GThreadPool *
+ide_thread_pool_get_pool (IdeThreadPoolKind kind)
+{
+  return gThreadPools [kind];
+}
+
+/**
+ * ide_thread_pool_push_task:
+ * @kind: The task kind.
+ * @task: A #GTask to execute.
+ * @func: (scope async): The thread worker to execute for @task.
+ *
+ * This pushes a task to be executed on a worker thread based on the task kind as denoted by
+ * @kind. Some tasks will be placed on special work queues or throttled based on proirity.
+ */
+void
+ide_thread_pool_push_task (IdeThreadPoolKind  kind,
+                           GTask             *task,
+                           GTaskThreadFunc    func)
+{
+  GThreadPool *pool;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (kind >= 0);
+  g_return_if_fail (kind < IDE_THREAD_POOL_LAST);
+  g_return_if_fail (G_IS_TASK (task));
+  g_return_if_fail (func != NULL);
+
+  pool = ide_thread_pool_get_pool (kind);
+
+  if (pool != NULL)
+    {
+      WorkItem *work_item;
+
+      work_item = g_slice_new0 (WorkItem);
+      work_item->task = g_object_ref (task);
+      work_item->func = func;
+
+      g_thread_pool_push (pool, work_item, NULL);
+    }
+  else
+    {
+      g_task_run_in_thread (task, func);
+    }
+
+  IDE_EXIT;
+}
+
+static void
+ide_thread_pool_worker (gpointer data,
+                        gpointer user_data)
+{
+  WorkItem *work_item = data;
+  gpointer source_object;
+  gpointer task_data;
+  GCancellable *cancellable;
+
+  g_assert (work_item != NULL);
+
+  source_object = g_task_get_source_object (work_item->task);
+  task_data = g_task_get_task_data (work_item->task);
+  cancellable = g_task_get_cancellable (work_item->task);
+
+  work_item->func (work_item->task, source_object, task_data, cancellable);
+
+  g_object_unref (work_item->task);
+  g_slice_free (WorkItem, work_item);
+}
+
+void
+_ide_thread_pool_init (void)
+{
+  /*
+   * Create our thread pool exclusive to compiler tasks (such as those from Clang).
+   * We don't want to consume threads fro other GTask's such as those regarding IO so we manage
+   * these work items exclusively.
+   */
+  gThreadPools [IDE_THREAD_POOL_COMPILER] = g_thread_pool_new (ide_thread_pool_worker,
+                                                               NULL,
+                                                               COMPILER_MAX_THREADS,
+                                                               TRUE,
+                                                               NULL);
+}
diff --git a/libide/ide-thread-pool.h b/libide/ide-thread-pool.h
new file mode 100644
index 0000000..9056ab7
--- /dev/null
+++ b/libide/ide-thread-pool.h
@@ -0,0 +1,38 @@
+/* ide-thread-pool.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_THREAD_POOL_H
+#define IDE_THREAD_POOL_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  IDE_THREAD_POOL_COMPILER,
+  IDE_THREAD_POOL_LAST
+} IdeThreadPoolKind;
+
+void ide_thread_pool_push_task (IdeThreadPoolKind  kind,
+                                GTask             *task,
+                                GTaskThreadFunc    func);
+
+G_END_DECLS
+
+#endif /* IDE_THREAD_POOL_H */
diff --git a/libide/ide.c b/libide/ide.c
index 5f51c16..ee23227 100644
--- a/libide/ide.c
+++ b/libide/ide.c
@@ -38,6 +38,7 @@
 #include "ide-gjs-script.h"
 #include "ide-gsettings-file-settings.h"
 #include "ide-html-language.h"
+#include "ide-internal.h"
 #include "ide-project-miner.h"
 #include "ide-pygobject-script.h"
 #include "ide-python-language.h"
@@ -195,4 +196,6 @@ ide_init_ctor (void)
       g_error (_("Builder requires libgit2-glib with SSH support."));
       exit (EXIT_FAILURE);
     }
+
+  _ide_thread_pool_init ();
 }


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