1 //===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/Parallel.h" 11 #include "llvm/Config/llvm-config.h" 12 13 #include <atomic> 14 #include <stack> 15 #include <thread> 16 17 using namespace llvm; 18 19 namespace { 20 21 /// \brief An abstract class that takes closures and runs them asynchronously. 22 class Executor { 23 public: 24 virtual ~Executor() = default; 25 virtual void add(std::function<void()> func) = 0; 26 27 static Executor *getDefaultExecutor(); 28 }; 29 30 #if !LLVM_ENABLE_THREADS 31 class SyncExecutor : public Executor { 32 public: 33 virtual void add(std::function<void()> F) { F(); } 34 }; 35 36 Executor *Executor::getDefaultExecutor() { 37 static SyncExecutor Exec; 38 return &Exec; 39 } 40 41 #elif defined(_MSC_VER) 42 /// \brief An Executor that runs tasks via ConcRT. 43 class ConcRTExecutor : public Executor { 44 struct Taskish { 45 Taskish(std::function<void()> Task) : Task(Task) {} 46 47 std::function<void()> Task; 48 49 static void run(void *P) { 50 Taskish *Self = static_cast<Taskish *>(P); 51 Self->Task(); 52 concurrency::Free(Self); 53 } 54 }; 55 56 public: 57 virtual void add(std::function<void()> F) { 58 Concurrency::CurrentScheduler::ScheduleTask( 59 Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F)); 60 } 61 }; 62 63 Executor *Executor::getDefaultExecutor() { 64 static ConcRTExecutor exec; 65 return &exec; 66 } 67 68 #else 69 /// \brief An implementation of an Executor that runs closures on a thread pool 70 /// in filo order. 71 class ThreadPoolExecutor : public Executor { 72 public: 73 explicit ThreadPoolExecutor( 74 unsigned ThreadCount = std::thread::hardware_concurrency()) 75 : Done(ThreadCount) { 76 // Spawn all but one of the threads in another thread as spawning threads 77 // can take a while. 78 std::thread([&, ThreadCount] { 79 for (size_t i = 1; i < ThreadCount; ++i) { 80 std::thread([=] { work(); }).detach(); 81 } 82 work(); 83 }).detach(); 84 } 85 86 ~ThreadPoolExecutor() override { 87 std::unique_lock<std::mutex> Lock(Mutex); 88 Stop = true; 89 Lock.unlock(); 90 Cond.notify_all(); 91 // Wait for ~Latch. 92 } 93 94 void add(std::function<void()> F) override { 95 std::unique_lock<std::mutex> Lock(Mutex); 96 WorkStack.push(F); 97 Lock.unlock(); 98 Cond.notify_one(); 99 } 100 101 private: 102 void work() { 103 while (true) { 104 std::unique_lock<std::mutex> Lock(Mutex); 105 Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); }); 106 if (Stop) 107 break; 108 auto Task = WorkStack.top(); 109 WorkStack.pop(); 110 Lock.unlock(); 111 Task(); 112 } 113 Done.dec(); 114 } 115 116 std::atomic<bool> Stop{false}; 117 std::stack<std::function<void()>> WorkStack; 118 std::mutex Mutex; 119 std::condition_variable Cond; 120 Latch Done; 121 }; 122 123 Executor *Executor::getDefaultExecutor() { 124 static ThreadPoolExecutor exec; 125 return &exec; 126 } 127 #endif 128 } 129 130 void detail::TaskGroup::spawn(std::function<void()> F) { 131 L.inc(); 132 Executor::getDefaultExecutor()->add([&, F] { 133 F(); 134 L.dec(); 135 }); 136 } 137