1 //===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/Support/Parallel.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/Support/Threading.h"
22 /// \brief An abstract class that takes closures and runs them asynchronously.
25 virtual ~Executor() = default;
26 virtual void add(std::function<void()> func) = 0;
28 static Executor *getDefaultExecutor();
31 #if !LLVM_ENABLE_THREADS
32 class SyncExecutor : public Executor {
34 virtual void add(std::function<void()> F) { F(); }
37 Executor *Executor::getDefaultExecutor() {
38 static SyncExecutor Exec;
42 #elif defined(_MSC_VER)
43 /// \brief An Executor that runs tasks via ConcRT.
44 class ConcRTExecutor : public Executor {
46 Taskish(std::function<void()> Task) : Task(Task) {}
48 std::function<void()> Task;
50 static void run(void *P) {
51 Taskish *Self = static_cast<Taskish *>(P);
53 concurrency::Free(Self);
58 virtual void add(std::function<void()> F) {
59 Concurrency::CurrentScheduler::ScheduleTask(
60 Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
64 Executor *Executor::getDefaultExecutor() {
65 static ConcRTExecutor exec;
70 /// \brief An implementation of an Executor that runs closures on a thread pool
72 class ThreadPoolExecutor : public Executor {
74 explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency())
76 // Spawn all but one of the threads in another thread as spawning threads
78 std::thread([&, ThreadCount] {
79 for (size_t i = 1; i < ThreadCount; ++i) {
80 std::thread([=] { work(); }).detach();
86 ~ThreadPoolExecutor() override {
87 std::unique_lock<std::mutex> Lock(Mutex);
94 void add(std::function<void()> F) override {
95 std::unique_lock<std::mutex> Lock(Mutex);
104 std::unique_lock<std::mutex> Lock(Mutex);
105 Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
108 auto Task = WorkStack.top();
116 std::atomic<bool> Stop{false};
117 std::stack<std::function<void()>> WorkStack;
119 std::condition_variable Cond;
120 parallel::detail::Latch Done;
123 Executor *Executor::getDefaultExecutor() {
124 static ThreadPoolExecutor exec;
130 #if LLVM_ENABLE_THREADS
131 void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
133 Executor::getDefaultExecutor()->add([&, F] {