summaryrefslogtreecommitdiff
path: root/include/lldb/Host/TaskPool.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/lldb/Host/TaskPool.h')
-rw-r--r--include/lldb/Host/TaskPool.h98
1 files changed, 98 insertions, 0 deletions
diff --git a/include/lldb/Host/TaskPool.h b/include/lldb/Host/TaskPool.h
new file mode 100644
index 0000000000000..13076e7eb70bd
--- /dev/null
+++ b/include/lldb/Host/TaskPool.h
@@ -0,0 +1,98 @@
+//===--------------------- TaskPool.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_TaskPool_h_
+#define utility_TaskPool_h_
+
+#include "llvm/ADT/STLExtras.h"
+#include <functional> // for bind, function
+#include <future>
+#include <list>
+#include <memory> // for make_shared
+#include <mutex> // for mutex, unique_lock, condition_variable
+#include <type_traits> // for forward, result_of, move
+
+namespace lldb_private {
+
+// Global TaskPool class for running tasks in parallel on a set of worker thread
+// created the first
+// time the task pool is used. The TaskPool provide no guarantee about the order
+// the task will be run
+// and about what tasks will run in parallel. None of the task added to the task
+// pool should block
+// on something (mutex, future, condition variable) what will be set only by the
+// completion of an
+// other task on the task pool as they may run on the same thread sequentally.
+class TaskPool {
+public:
+ // Add a new task to the task pool and return a std::future belonging to the
+ // newly created task.
+ // The caller of this function has to wait on the future for this task to
+ // complete.
+ template <typename F, typename... Args>
+ static std::future<typename std::result_of<F(Args...)>::type>
+ AddTask(F &&f, Args &&... args);
+
+ // Run all of the specified tasks on the task pool and wait until all of them
+ // are finished
+ // before returning. This method is intended to be used for small number tasks
+ // where listing
+ // them as function arguments is acceptable. For running large number of tasks
+ // you should use
+ // AddTask for each task and then call wait() on each returned future.
+ template <typename... T> static void RunTasks(T &&... tasks);
+
+private:
+ TaskPool() = delete;
+
+ template <typename... T> struct RunTaskImpl;
+
+ static void AddTaskImpl(std::function<void()> &&task_fn);
+};
+
+template <typename F, typename... Args>
+std::future<typename std::result_of<F(Args...)>::type>
+TaskPool::AddTask(F &&f, Args &&... args) {
+ auto task_sp = std::make_shared<
+ std::packaged_task<typename std::result_of<F(Args...)>::type()>>(
+ std::bind(std::forward<F>(f), std::forward<Args>(args)...));
+
+ AddTaskImpl([task_sp]() { (*task_sp)(); });
+
+ return task_sp->get_future();
+}
+
+template <typename... T> void TaskPool::RunTasks(T &&... tasks) {
+ RunTaskImpl<T...>::Run(std::forward<T>(tasks)...);
+}
+
+template <typename Head, typename... Tail>
+struct TaskPool::RunTaskImpl<Head, Tail...> {
+ static void Run(Head &&h, Tail &&... t) {
+ auto f = AddTask(std::forward<Head>(h));
+ RunTaskImpl<Tail...>::Run(std::forward<Tail>(t)...);
+ f.wait();
+ }
+};
+
+template <> struct TaskPool::RunTaskImpl<> {
+ static void Run() {}
+};
+
+// Run 'func' on every value from begin .. end-1. Each worker will grab
+// 'batch_size' numbers at a time to work on, so for very fast functions, batch
+// should be large enough to avoid too much cache line contention.
+void TaskMapOverInt(size_t begin, size_t end,
+ const llvm::function_ref<void(size_t)> &func);
+
+unsigned GetHardwareConcurrencyHint();
+
+} // namespace lldb_private
+
+#endif // #ifndef utility_TaskPool_h_