blob: 1844003b9d3dcbfd26a90eae350e7b4a5967cf7f [file] [log] [blame]
Zachary Turner3a57fbd2017-05-11 00:03:52 +00001//===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +00002//
Zachary Turner3a57fbd2017-05-11 00:03:52 +00003// The LLVM Compiler Infrastructure
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +00004//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turner3a57fbd2017-05-11 00:03:52 +000010#include "llvm/Support/Parallel.h"
Zachary Turner6083b2b2017-05-05 21:14:55 +000011#include "llvm/Config/llvm-config.h"
Nico Weber0f2a48c2018-05-11 15:25:38 +000012
13#if LLVM_ENABLE_THREADS
14
Rafael Espindola8c0ff952017-10-04 20:27:01 +000015#include "llvm/Support/Threading.h"
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000016
17#include <atomic>
18#include <stack>
Rui Ueyama552c2902017-05-05 21:27:30 +000019#include <thread>
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000020
Zachary Turner3a57fbd2017-05-11 00:03:52 +000021using namespace llvm;
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000022
23namespace {
24
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000025/// An abstract class that takes closures and runs them asynchronously.
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000026class Executor {
27public:
28 virtual ~Executor() = default;
29 virtual void add(std::function<void()> func) = 0;
30
31 static Executor *getDefaultExecutor();
32};
33
Nico Weber0f2a48c2018-05-11 15:25:38 +000034#if defined(_MSC_VER)
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000035/// An Executor that runs tasks via ConcRT.
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000036class ConcRTExecutor : public Executor {
37 struct Taskish {
38 Taskish(std::function<void()> Task) : Task(Task) {}
39
40 std::function<void()> Task;
41
42 static void run(void *P) {
43 Taskish *Self = static_cast<Taskish *>(P);
44 Self->Task();
45 concurrency::Free(Self);
46 }
47 };
48
49public:
50 virtual void add(std::function<void()> F) {
51 Concurrency::CurrentScheduler::ScheduleTask(
52 Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
53 }
54};
55
56Executor *Executor::getDefaultExecutor() {
57 static ConcRTExecutor exec;
58 return &exec;
59}
60
61#else
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000062/// An implementation of an Executor that runs closures on a thread pool
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000063/// in filo order.
64class ThreadPoolExecutor : public Executor {
65public:
Rafael Espindola8c0ff952017-10-04 20:27:01 +000066 explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency())
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000067 : Done(ThreadCount) {
68 // Spawn all but one of the threads in another thread as spawning threads
69 // can take a while.
70 std::thread([&, ThreadCount] {
71 for (size_t i = 1; i < ThreadCount; ++i) {
72 std::thread([=] { work(); }).detach();
73 }
74 work();
75 }).detach();
76 }
77
78 ~ThreadPoolExecutor() override {
79 std::unique_lock<std::mutex> Lock(Mutex);
80 Stop = true;
81 Lock.unlock();
82 Cond.notify_all();
83 // Wait for ~Latch.
84 }
85
86 void add(std::function<void()> F) override {
87 std::unique_lock<std::mutex> Lock(Mutex);
88 WorkStack.push(F);
89 Lock.unlock();
90 Cond.notify_one();
91 }
92
93private:
94 void work() {
95 while (true) {
96 std::unique_lock<std::mutex> Lock(Mutex);
97 Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
98 if (Stop)
99 break;
100 auto Task = WorkStack.top();
101 WorkStack.pop();
102 Lock.unlock();
103 Task();
104 }
105 Done.dec();
106 }
107
108 std::atomic<bool> Stop{false};
109 std::stack<std::function<void()>> WorkStack;
110 std::mutex Mutex;
111 std::condition_variable Cond;
Zachary Turner7a2d5682017-05-11 00:22:18 +0000112 parallel::detail::Latch Done;
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +0000113};
114
115Executor *Executor::getDefaultExecutor() {
116 static ThreadPoolExecutor exec;
117 return &exec;
118}
119#endif
120}
121
Zachary Turner20c8e912017-05-11 00:18:52 +0000122void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
Zachary Turner0a340ce2017-05-10 17:39:18 +0000123 L.inc();
124 Executor::getDefaultExecutor()->add([&, F] {
125 F();
126 L.dec();
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +0000127 });
128}
Nico Weber0f2a48c2018-05-11 15:25:38 +0000129#endif // LLVM_ENABLE_THREADS