This revision was automatically updated to reflect the committed changes.
Closed by commit rL313637: Use ThreadLauncher to launch TaskPool threads
(authored by fjricci).
Changed prior to commit:
https://reviews.llvm.org/D37930?vs=115691&id=115844#toc
Repository:
rL LLVM
https://reviews.llvm.org/D37930
Files:
lldb/trunk/include/lldb/Host/TaskPool.h
lldb/trunk/include/lldb/Utility/TaskPool.h
lldb/trunk/lldb.xcodeproj/project.pbxproj
lldb/trunk/source/Host/CMakeLists.txt
lldb/trunk/source/Host/common/TaskPool.cpp
lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
lldb/trunk/source/Utility/CMakeLists.txt
lldb/trunk/source/Utility/TaskPool.cpp
lldb/trunk/unittests/Host/CMakeLists.txt
lldb/trunk/unittests/Host/TaskPoolTest.cpp
lldb/trunk/unittests/Utility/CMakeLists.txt
lldb/trunk/unittests/Utility/TaskPoolTest.cpp
Index: lldb/trunk/unittests/Host/TaskPoolTest.cpp
===================================================================
--- lldb/trunk/unittests/Host/TaskPoolTest.cpp
+++ lldb/trunk/unittests/Host/TaskPoolTest.cpp
@@ -0,0 +1,43 @@
+#include "gtest/gtest.h"
+
+#include "lldb/Host/TaskPool.h"
+
+TEST(TaskPoolTest, AddTask) {
+ auto fn = [](int x) { return x * x + 1; };
+
+ auto f1 = TaskPool::AddTask(fn, 1);
+ auto f2 = TaskPool::AddTask(fn, 2);
+ auto f3 = TaskPool::AddTask(fn, 3);
+ auto f4 = TaskPool::AddTask(fn, 4);
+
+ ASSERT_EQ(10, f3.get());
+ ASSERT_EQ(2, f1.get());
+ ASSERT_EQ(17, f4.get());
+ ASSERT_EQ(5, f2.get());
+}
+
+TEST(TaskPoolTest, RunTasks) {
+ std::vector<int> r(4);
+
+ auto fn = [](int x, int &y) { y = x * x + 1; };
+
+ TaskPool::RunTasks([fn, &r]() { fn(1, r[0]); }, [fn, &r]() { fn(2, r[1]); },
+ [fn, &r]() { fn(3, r[2]); }, [fn, &r]() { fn(4, r[3]); });
+
+ ASSERT_EQ(2, r[0]);
+ ASSERT_EQ(5, r[1]);
+ ASSERT_EQ(10, r[2]);
+ ASSERT_EQ(17, r[3]);
+}
+
+TEST(TaskPoolTest, TaskMap) {
+ int data[4];
+ auto fn = [&data](int x) { data[x] = x * x; };
+
+ TaskMapOverInt(0, 4, fn);
+
+ ASSERT_EQ(data[0], 0);
+ ASSERT_EQ(data[1], 1);
+ ASSERT_EQ(data[2], 4);
+ ASSERT_EQ(data[3], 9);
+}
Index: lldb/trunk/unittests/Host/CMakeLists.txt
===================================================================
--- lldb/trunk/unittests/Host/CMakeLists.txt
+++ lldb/trunk/unittests/Host/CMakeLists.txt
@@ -6,6 +6,7 @@
SocketAddressTest.cpp
SocketTest.cpp
SymbolsTest.cpp
+ TaskPoolTest.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
Index: lldb/trunk/unittests/Utility/CMakeLists.txt
===================================================================
--- lldb/trunk/unittests/Utility/CMakeLists.txt
+++ lldb/trunk/unittests/Utility/CMakeLists.txt
@@ -8,7 +8,6 @@
StatusTest.cpp
StringExtractorTest.cpp
StructuredDataTest.cpp
- TaskPoolTest.cpp
TildeExpressionResolverTest.cpp
TimeoutTest.cpp
TimerTest.cpp
Index: lldb/trunk/source/Utility/CMakeLists.txt
===================================================================
--- lldb/trunk/source/Utility/CMakeLists.txt
+++ lldb/trunk/source/Utility/CMakeLists.txt
@@ -29,7 +29,6 @@
StringLexer.cpp
StringList.cpp
StructuredData.cpp
- TaskPool.cpp
TildeExpressionResolver.cpp
Timer.cpp
UserID.cpp
Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -53,7 +53,7 @@
#include "lldb/Target/Language.h"
-#include "lldb/Utility/TaskPool.h"
+#include "lldb/Host/TaskPool.h"
#include "DWARFASTParser.h"
#include "DWARFASTParserClang.h"
Index: lldb/trunk/source/Host/CMakeLists.txt
===================================================================
--- lldb/trunk/source/Host/CMakeLists.txt
+++ lldb/trunk/source/Host/CMakeLists.txt
@@ -31,6 +31,7 @@
common/SoftwareBreakpoint.cpp
common/StringConvert.cpp
common/Symbols.cpp
+ common/TaskPool.cpp
common/TCPSocket.cpp
common/Terminal.cpp
common/ThreadLauncher.cpp
Index: lldb/trunk/source/Host/common/TaskPool.cpp
===================================================================
--- lldb/trunk/source/Host/common/TaskPool.cpp
+++ lldb/trunk/source/Host/common/TaskPool.cpp
@@ -0,0 +1,109 @@
+//===--------------------- TaskPool.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/TaskPool.h"
+#include "lldb/Host/ThreadLauncher.h"
+
+#include <cstdint> // for uint32_t
+#include <queue> // for queue
+#include <thread> // for thread
+
+namespace {
+class TaskPoolImpl {
+public:
+ static TaskPoolImpl &GetInstance();
+
+ void AddTask(std::function<void()> &&task_fn);
+
+private:
+ TaskPoolImpl();
+
+ static lldb::thread_result_t WorkerPtr(void *pool);
+
+ static void Worker(TaskPoolImpl *pool);
+
+ std::queue<std::function<void()>> m_tasks;
+ std::mutex m_tasks_mutex;
+ uint32_t m_thread_count;
+};
+
+} // end of anonymous namespace
+
+TaskPoolImpl &TaskPoolImpl::GetInstance() {
+ static TaskPoolImpl g_task_pool_impl;
+ return g_task_pool_impl;
+}
+
+void TaskPool::AddTaskImpl(std::function<void()> &&task_fn) {
+ TaskPoolImpl::GetInstance().AddTask(std::move(task_fn));
+}
+
+TaskPoolImpl::TaskPoolImpl() : m_thread_count(0) {}
+
+void TaskPoolImpl::AddTask(std::function<void()> &&task_fn) {
+ static const uint32_t max_threads = std::thread::hardware_concurrency();
+ const size_t min_stack_size = 8 * 1024 * 1024;
+
+ std::unique_lock<std::mutex> lock(m_tasks_mutex);
+ m_tasks.emplace(std::move(task_fn));
+ if (m_thread_count < max_threads) {
+ m_thread_count++;
+ // Note that this detach call needs to happen with the m_tasks_mutex held.
+ // This prevents the thread
+ // from exiting prematurely and triggering a linux libc bug
+ // (https://sourceware.org/bugzilla/show_bug.cgi?id=19951).
+ lldb_private::ThreadLauncher::LaunchThread("task-pool.worker", WorkerPtr,
+ this, nullptr, min_stack_size)
+ .Release();
+ }
+}
+
+lldb::thread_result_t TaskPoolImpl::WorkerPtr(void *pool) {
+ Worker((TaskPoolImpl *)pool);
+ return 0;
+}
+
+void TaskPoolImpl::Worker(TaskPoolImpl *pool) {
+ while (true) {
+ std::unique_lock<std::mutex> lock(pool->m_tasks_mutex);
+ if (pool->m_tasks.empty()) {
+ pool->m_thread_count--;
+ break;
+ }
+
+ std::function<void()> f = pool->m_tasks.front();
+ pool->m_tasks.pop();
+ lock.unlock();
+
+ f();
+ }
+}
+
+void TaskMapOverInt(size_t begin, size_t end,
+ const llvm::function_ref<void(size_t)> &func) {
+ std::atomic<size_t> idx{begin};
+ size_t num_workers =
+ std::min<size_t>(end, std::thread::hardware_concurrency());
+
+ auto wrapper = [&idx, end, &func]() {
+ while (true) {
+ size_t i = idx.fetch_add(1);
+ if (i >= end)
+ break;
+ func(i);
+ }
+ };
+
+ std::vector<std::future<void>> futures;
+ futures.reserve(num_workers);
+ for (size_t i = 0; i < num_workers; i++)
+ futures.push_back(TaskPool::AddTask(wrapper));
+ for (size_t i = 0; i < num_workers; i++)
+ futures[i].wait();
+}
Index: lldb/trunk/include/lldb/Host/TaskPool.h
===================================================================
--- lldb/trunk/include/lldb/Host/TaskPool.h
+++ lldb/trunk/include/lldb/Host/TaskPool.h
@@ -0,0 +1,92 @@
+//===--------------------- 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
+
+// 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);
+
+#endif // #ifndef utility_TaskPool_h_
Index: lldb/trunk/lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj
@@ -2664,8 +2664,8 @@
6D99A3621BBC2F3200979793 /* ArmUnwindInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ArmUnwindInfo.cpp; path = source/Symbol/ArmUnwindInfo.cpp; sourceTree = "<group>"; };
6D9AB3DC1BB2B74E003F2289 /* TypeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeMap.cpp; path = source/Symbol/TypeMap.cpp; sourceTree = "<group>"; };
6D9AB3DE1BB2B76B003F2289 /* TypeMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeMap.h; path = include/lldb/Symbol/TypeMap.h; sourceTree = "<group>"; };
- 6DEC6F381BD66D750091ABA6 /* TaskPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TaskPool.cpp; path = source/Utility/TaskPool.cpp; sourceTree = "<group>"; };
- 6DEC6F3A1BD66D950091ABA6 /* TaskPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaskPool.h; path = include/lldb/Utility/TaskPool.h; sourceTree = "<group>"; };
+ 6DEC6F381BD66D750091ABA6 /* TaskPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TaskPool.cpp; path = source/Host/common/TaskPool.cpp; sourceTree = "<group>"; };
+ 6DEC6F3A1BD66D950091ABA6 /* TaskPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaskPool.h; path = include/lldb/Host/TaskPool.h; sourceTree = "<group>"; };
8C26C4241C3EA4340031DF7C /* TSanRuntime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TSanRuntime.cpp; path = TSan/TSanRuntime.cpp; sourceTree = "<group>"; };
8C26C4251C3EA4340031DF7C /* TSanRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TSanRuntime.h; path = TSan/TSanRuntime.h; sourceTree = "<group>"; };
8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MemoryHistory.cpp; path = source/Target/MemoryHistory.cpp; sourceTree = "<group>"; };
@@ -4413,8 +4413,6 @@
AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */,
94BA8B6E176F8CA0005A91B5 /* Range.h */,
94BA8B6C176F8C9B005A91B5 /* Range.cpp */,
- 6DEC6F3A1BD66D950091ABA6 /* TaskPool.h */,
- 6DEC6F381BD66D750091ABA6 /* TaskPool.cpp */,
AFF8FF0B1E779D4B003830EF /* TildeExpressionResolver.cpp */,
AFF8FF0D1E779D51003830EF /* TildeExpressionResolver.h */,
26BC7D7E10F1B77400F91463 /* Timer.h */,
@@ -5248,6 +5246,8 @@
267A47F21B14115A0021A5BC /* SoftwareBreakpoint.h */,
232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */,
2689B0A4113EE3CD00A4AEDB /* Symbols.h */,
+ 6DEC6F3A1BD66D950091ABA6 /* TaskPool.h */,
+ 6DEC6F381BD66D750091ABA6 /* TaskPool.cpp */,
268DA871130095D000C9483A /* Terminal.h */,
3FDFED2319BA6D55009756A7 /* ThreadLauncher.h */,
267A48031B1416080021A5BC /* XML.h */,
Index: lldb/trunk/unittests/Utility/TaskPoolTest.cpp
===================================================================
--- lldb/trunk/unittests/Utility/TaskPoolTest.cpp
+++ lldb/trunk/unittests/Utility/TaskPoolTest.cpp
@@ -1,43 +0,0 @@
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/TaskPool.h"
-
-TEST(TaskPoolTest, AddTask) {
- auto fn = [](int x) { return x * x + 1; };
-
- auto f1 = TaskPool::AddTask(fn, 1);
- auto f2 = TaskPool::AddTask(fn, 2);
- auto f3 = TaskPool::AddTask(fn, 3);
- auto f4 = TaskPool::AddTask(fn, 4);
-
- ASSERT_EQ(10, f3.get());
- ASSERT_EQ(2, f1.get());
- ASSERT_EQ(17, f4.get());
- ASSERT_EQ(5, f2.get());
-}
-
-TEST(TaskPoolTest, RunTasks) {
- std::vector<int> r(4);
-
- auto fn = [](int x, int &y) { y = x * x + 1; };
-
- TaskPool::RunTasks([fn, &r]() { fn(1, r[0]); }, [fn, &r]() { fn(2, r[1]); },
- [fn, &r]() { fn(3, r[2]); }, [fn, &r]() { fn(4, r[3]); });
-
- ASSERT_EQ(2, r[0]);
- ASSERT_EQ(5, r[1]);
- ASSERT_EQ(10, r[2]);
- ASSERT_EQ(17, r[3]);
-}
-
-TEST(TaskPoolTest, TaskMap) {
- int data[4];
- auto fn = [&data](int x) { data[x] = x * x; };
-
- TaskMapOverInt(0, 4, fn);
-
- ASSERT_EQ(data[0], 0);
- ASSERT_EQ(data[1], 1);
- ASSERT_EQ(data[2], 4);
- ASSERT_EQ(data[3], 9);
-}
Index: lldb/trunk/source/Utility/TaskPool.cpp
===================================================================
--- lldb/trunk/source/Utility/TaskPool.cpp
+++ lldb/trunk/source/Utility/TaskPool.cpp
@@ -1,98 +0,0 @@
-//===--------------------- TaskPool.cpp -------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/TaskPool.h"
-
-#include <cstdint> // for uint32_t
-#include <queue> // for queue
-#include <thread> // for thread
-
-namespace {
-class TaskPoolImpl {
-public:
- static TaskPoolImpl &GetInstance();
-
- void AddTask(std::function<void()> &&task_fn);
-
-private:
- TaskPoolImpl();
-
- static void Worker(TaskPoolImpl *pool);
-
- std::queue<std::function<void()>> m_tasks;
- std::mutex m_tasks_mutex;
- uint32_t m_thread_count;
-};
-
-} // end of anonymous namespace
-
-TaskPoolImpl &TaskPoolImpl::GetInstance() {
- static TaskPoolImpl g_task_pool_impl;
- return g_task_pool_impl;
-}
-
-void TaskPool::AddTaskImpl(std::function<void()> &&task_fn) {
- TaskPoolImpl::GetInstance().AddTask(std::move(task_fn));
-}
-
-TaskPoolImpl::TaskPoolImpl() : m_thread_count(0) {}
-
-void TaskPoolImpl::AddTask(std::function<void()> &&task_fn) {
- static const uint32_t max_threads = std::thread::hardware_concurrency();
-
- std::unique_lock<std::mutex> lock(m_tasks_mutex);
- m_tasks.emplace(std::move(task_fn));
- if (m_thread_count < max_threads) {
- m_thread_count++;
- // Note that this detach call needs to happen with the m_tasks_mutex held.
- // This prevents the thread
- // from exiting prematurely and triggering a linux libc bug
- // (https://sourceware.org/bugzilla/show_bug.cgi?id=19951).
- std::thread(Worker, this).detach();
- }
-}
-
-void TaskPoolImpl::Worker(TaskPoolImpl *pool) {
- while (true) {
- std::unique_lock<std::mutex> lock(pool->m_tasks_mutex);
- if (pool->m_tasks.empty()) {
- pool->m_thread_count--;
- break;
- }
-
- std::function<void()> f = pool->m_tasks.front();
- pool->m_tasks.pop();
- lock.unlock();
-
- f();
- }
-}
-
-void TaskMapOverInt(size_t begin, size_t end,
- const llvm::function_ref<void(size_t)> &func) {
- std::atomic<size_t> idx{begin};
- size_t num_workers =
- std::min<size_t>(end, std::thread::hardware_concurrency());
-
- auto wrapper = [&idx, end, &func]() {
- while (true) {
- size_t i = idx.fetch_add(1);
- if (i >= end)
- break;
- func(i);
- }
- };
-
- std::vector<std::future<void>> futures;
- futures.reserve(num_workers);
- for (size_t i = 0; i < num_workers; i++)
- futures.push_back(TaskPool::AddTask(wrapper));
- for (size_t i = 0; i < num_workers; i++)
- futures[i].wait();
-}
Index: lldb/trunk/include/lldb/Utility/TaskPool.h
===================================================================
--- lldb/trunk/include/lldb/Utility/TaskPool.h
+++ lldb/trunk/include/lldb/Utility/TaskPool.h
@@ -1,92 +0,0 @@
-//===--------------------- 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
-
-// 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);
-
-#endif // #ifndef utility_TaskPool_h_
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits