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"
21 /// \brief An abstract class that takes closures and runs them asynchronously.
24 virtual ~Executor() = default;
25 virtual void add(std::function<void()> func) = 0;
27 static Executor *getDefaultExecutor();
30 #if !LLVM_ENABLE_THREADS
31 class SyncExecutor : public Executor {
33 virtual void add(std::function<void()> F) { F(); }
36 Executor *Executor::getDefaultExecutor() {
37 static SyncExecutor Exec;
41 #elif defined(_MSC_VER)
42 /// \brief An Executor that runs tasks via ConcRT.
43 class ConcRTExecutor : public Executor {
45 Taskish(std::function<void()> Task) : Task(Task) {}
47 std::function<void()> Task;
49 static void run(void *P) {
50 Taskish *Self = static_cast<Taskish *>(P);
52 concurrency::Free(Self);
57 virtual void add(std::function<void()> F) {
58 Concurrency::CurrentScheduler::ScheduleTask(
59 Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
63 Executor *Executor::getDefaultExecutor() {
64 static ConcRTExecutor exec;
69 /// \brief An implementation of an Executor that runs closures on a thread pool
71 class ThreadPoolExecutor : public Executor {
73 explicit ThreadPoolExecutor(
74 unsigned ThreadCount = std::thread::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] {