15517e702SDimitry Andric //===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
25517e702SDimitry Andric //
35517e702SDimitry Andric //                     The LLVM Compiler Infrastructure
45517e702SDimitry Andric //
55517e702SDimitry Andric // This file is distributed under the University of Illinois Open Source
65517e702SDimitry Andric // License. See LICENSE.TXT for details.
75517e702SDimitry Andric //
85517e702SDimitry Andric //===----------------------------------------------------------------------===//
95517e702SDimitry Andric 
105517e702SDimitry Andric #include "llvm/Support/Parallel.h"
115517e702SDimitry Andric #include "llvm/Config/llvm-config.h"
12*4ba319b5SDimitry Andric 
13*4ba319b5SDimitry Andric #if LLVM_ENABLE_THREADS
14*4ba319b5SDimitry Andric 
152cab237bSDimitry Andric #include "llvm/Support/Threading.h"
165517e702SDimitry Andric 
175517e702SDimitry Andric #include <atomic>
185517e702SDimitry Andric #include <stack>
195517e702SDimitry Andric #include <thread>
205517e702SDimitry Andric 
215517e702SDimitry Andric using namespace llvm;
225517e702SDimitry Andric 
235517e702SDimitry Andric namespace {
245517e702SDimitry Andric 
25*4ba319b5SDimitry Andric /// An abstract class that takes closures and runs them asynchronously.
265517e702SDimitry Andric class Executor {
275517e702SDimitry Andric public:
285517e702SDimitry Andric   virtual ~Executor() = default;
295517e702SDimitry Andric   virtual void add(std::function<void()> func) = 0;
305517e702SDimitry Andric 
315517e702SDimitry Andric   static Executor *getDefaultExecutor();
325517e702SDimitry Andric };
335517e702SDimitry Andric 
34*4ba319b5SDimitry Andric #if defined(_MSC_VER)
35*4ba319b5SDimitry Andric /// An Executor that runs tasks via ConcRT.
365517e702SDimitry Andric class ConcRTExecutor : public Executor {
375517e702SDimitry Andric   struct Taskish {
Taskish__anon6be6bc8e0111::ConcRTExecutor::Taskish385517e702SDimitry Andric     Taskish(std::function<void()> Task) : Task(Task) {}
395517e702SDimitry Andric 
405517e702SDimitry Andric     std::function<void()> Task;
415517e702SDimitry Andric 
run__anon6be6bc8e0111::ConcRTExecutor::Taskish425517e702SDimitry Andric     static void run(void *P) {
435517e702SDimitry Andric       Taskish *Self = static_cast<Taskish *>(P);
445517e702SDimitry Andric       Self->Task();
455517e702SDimitry Andric       concurrency::Free(Self);
465517e702SDimitry Andric     }
475517e702SDimitry Andric   };
485517e702SDimitry Andric 
495517e702SDimitry Andric public:
add(std::function<void ()> F)505517e702SDimitry Andric   virtual void add(std::function<void()> F) {
515517e702SDimitry Andric     Concurrency::CurrentScheduler::ScheduleTask(
525517e702SDimitry Andric         Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
535517e702SDimitry Andric   }
545517e702SDimitry Andric };
555517e702SDimitry Andric 
getDefaultExecutor()565517e702SDimitry Andric Executor *Executor::getDefaultExecutor() {
575517e702SDimitry Andric   static ConcRTExecutor exec;
585517e702SDimitry Andric   return &exec;
595517e702SDimitry Andric }
605517e702SDimitry Andric 
615517e702SDimitry Andric #else
62*4ba319b5SDimitry Andric /// An implementation of an Executor that runs closures on a thread pool
635517e702SDimitry Andric ///   in filo order.
645517e702SDimitry Andric class ThreadPoolExecutor : public Executor {
655517e702SDimitry Andric public:
ThreadPoolExecutor(unsigned ThreadCount=hardware_concurrency ())662cab237bSDimitry Andric   explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency())
675517e702SDimitry Andric       : Done(ThreadCount) {
685517e702SDimitry Andric     // Spawn all but one of the threads in another thread as spawning threads
695517e702SDimitry Andric     // can take a while.
705517e702SDimitry Andric     std::thread([&, ThreadCount] {
715517e702SDimitry Andric       for (size_t i = 1; i < ThreadCount; ++i) {
725517e702SDimitry Andric         std::thread([=] { work(); }).detach();
735517e702SDimitry Andric       }
745517e702SDimitry Andric       work();
755517e702SDimitry Andric     }).detach();
765517e702SDimitry Andric   }
775517e702SDimitry Andric 
~ThreadPoolExecutor()785517e702SDimitry Andric   ~ThreadPoolExecutor() override {
795517e702SDimitry Andric     std::unique_lock<std::mutex> Lock(Mutex);
805517e702SDimitry Andric     Stop = true;
815517e702SDimitry Andric     Lock.unlock();
825517e702SDimitry Andric     Cond.notify_all();
835517e702SDimitry Andric     // Wait for ~Latch.
845517e702SDimitry Andric   }
855517e702SDimitry Andric 
add(std::function<void ()> F)865517e702SDimitry Andric   void add(std::function<void()> F) override {
875517e702SDimitry Andric     std::unique_lock<std::mutex> Lock(Mutex);
885517e702SDimitry Andric     WorkStack.push(F);
895517e702SDimitry Andric     Lock.unlock();
905517e702SDimitry Andric     Cond.notify_one();
915517e702SDimitry Andric   }
925517e702SDimitry Andric 
935517e702SDimitry Andric private:
work()945517e702SDimitry Andric   void work() {
955517e702SDimitry Andric     while (true) {
965517e702SDimitry Andric       std::unique_lock<std::mutex> Lock(Mutex);
975517e702SDimitry Andric       Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
985517e702SDimitry Andric       if (Stop)
995517e702SDimitry Andric         break;
1005517e702SDimitry Andric       auto Task = WorkStack.top();
1015517e702SDimitry Andric       WorkStack.pop();
1025517e702SDimitry Andric       Lock.unlock();
1035517e702SDimitry Andric       Task();
1045517e702SDimitry Andric     }
1055517e702SDimitry Andric     Done.dec();
1065517e702SDimitry Andric   }
1075517e702SDimitry Andric 
1085517e702SDimitry Andric   std::atomic<bool> Stop{false};
1095517e702SDimitry Andric   std::stack<std::function<void()>> WorkStack;
1105517e702SDimitry Andric   std::mutex Mutex;
1115517e702SDimitry Andric   std::condition_variable Cond;
1125517e702SDimitry Andric   parallel::detail::Latch Done;
1135517e702SDimitry Andric };
1145517e702SDimitry Andric 
getDefaultExecutor()1155517e702SDimitry Andric Executor *Executor::getDefaultExecutor() {
1165517e702SDimitry Andric   static ThreadPoolExecutor exec;
1175517e702SDimitry Andric   return &exec;
1185517e702SDimitry Andric }
1195517e702SDimitry Andric #endif
1205517e702SDimitry Andric }
1215517e702SDimitry Andric 
spawn(std::function<void ()> F)1225517e702SDimitry Andric void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
1235517e702SDimitry Andric   L.inc();
1245517e702SDimitry Andric   Executor::getDefaultExecutor()->add([&, F] {
1255517e702SDimitry Andric     F();
1265517e702SDimitry Andric     L.dec();
1275517e702SDimitry Andric   });
1285517e702SDimitry Andric }
129*4ba319b5SDimitry Andric #endif // LLVM_ENABLE_THREADS
130