TaskGroup.cpp 3.2 KB

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