thread.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- llvm/Support/thread.h - Wrapper for <thread> ------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This header is a wrapper for <thread> that works around problems with the
  15. // MSVC headers when exceptions are disabled. It also provides llvm::thread,
  16. // which is either a typedef of std::thread or a replacement that calls the
  17. // function synchronously depending on the value of LLVM_ENABLE_THREADS.
  18. //
  19. //===----------------------------------------------------------------------===//
  20. #ifndef LLVM_SUPPORT_THREAD_H
  21. #define LLVM_SUPPORT_THREAD_H
  22. #include "llvm/Config/llvm-config.h"
  23. #include <optional>
  24. #ifdef _WIN32
  25. typedef unsigned long DWORD;
  26. typedef void *PVOID;
  27. typedef PVOID HANDLE;
  28. #endif
  29. #if LLVM_ENABLE_THREADS
  30. #include <thread>
  31. namespace llvm {
  32. #if LLVM_ON_UNIX || _WIN32
  33. /// LLVM thread following std::thread interface with added constructor to
  34. /// specify stack size.
  35. class thread {
  36. template <typename CalleeTuple> static void GenericThreadProxy(void *Ptr) {
  37. std::unique_ptr<CalleeTuple> Callee(static_cast<CalleeTuple *>(Ptr));
  38. std::apply(
  39. [](auto &&F, auto &&...Args) {
  40. std::forward<decltype(F)>(F)(std::forward<decltype(Args)>(Args)...);
  41. },
  42. *Callee);
  43. }
  44. public:
  45. #if LLVM_ON_UNIX
  46. using native_handle_type = pthread_t;
  47. using id = pthread_t;
  48. using start_routine_type = void *(*)(void *);
  49. template <typename CalleeTuple> static void *ThreadProxy(void *Ptr) {
  50. GenericThreadProxy<CalleeTuple>(Ptr);
  51. return nullptr;
  52. }
  53. #elif _WIN32
  54. using native_handle_type = HANDLE;
  55. using id = DWORD;
  56. using start_routine_type = unsigned(__stdcall *)(void *);
  57. template <typename CalleeTuple>
  58. static unsigned __stdcall ThreadProxy(void *Ptr) {
  59. GenericThreadProxy<CalleeTuple>(Ptr);
  60. return 0;
  61. }
  62. #endif
  63. static const std::optional<unsigned> DefaultStackSize;
  64. thread() : Thread(native_handle_type()) {}
  65. thread(thread &&Other) noexcept
  66. : Thread(std::exchange(Other.Thread, native_handle_type())) {}
  67. template <class Function, class... Args>
  68. explicit thread(Function &&f, Args &&...args)
  69. : thread(DefaultStackSize, f, args...) {}
  70. template <class Function, class... Args>
  71. explicit thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
  72. Args &&...args);
  73. thread(const thread &) = delete;
  74. ~thread() {
  75. if (joinable())
  76. std::terminate();
  77. }
  78. thread &operator=(thread &&Other) noexcept {
  79. if (joinable())
  80. std::terminate();
  81. Thread = std::exchange(Other.Thread, native_handle_type());
  82. return *this;
  83. }
  84. bool joinable() const noexcept { return Thread != native_handle_type(); }
  85. inline id get_id() const noexcept;
  86. native_handle_type native_handle() const noexcept { return Thread; }
  87. static unsigned hardware_concurrency() {
  88. return std::thread::hardware_concurrency();
  89. };
  90. inline void join();
  91. inline void detach();
  92. void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
  93. private:
  94. native_handle_type Thread;
  95. };
  96. thread::native_handle_type
  97. llvm_execute_on_thread_impl(thread::start_routine_type ThreadFunc, void *Arg,
  98. std::optional<unsigned> StackSizeInBytes);
  99. void llvm_thread_join_impl(thread::native_handle_type Thread);
  100. void llvm_thread_detach_impl(thread::native_handle_type Thread);
  101. thread::id llvm_thread_get_id_impl(thread::native_handle_type Thread);
  102. thread::id llvm_thread_get_current_id_impl();
  103. template <class Function, class... Args>
  104. thread::thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
  105. Args &&...args) {
  106. typedef std::tuple<std::decay_t<Function>, std::decay_t<Args>...> CalleeTuple;
  107. std::unique_ptr<CalleeTuple> Callee(
  108. new CalleeTuple(std::forward<Function>(f), std::forward<Args>(args)...));
  109. Thread = llvm_execute_on_thread_impl(ThreadProxy<CalleeTuple>, Callee.get(),
  110. StackSizeInBytes);
  111. if (Thread != native_handle_type())
  112. Callee.release();
  113. }
  114. thread::id thread::get_id() const noexcept {
  115. return llvm_thread_get_id_impl(Thread);
  116. }
  117. void thread::join() {
  118. llvm_thread_join_impl(Thread);
  119. Thread = native_handle_type();
  120. }
  121. void thread::detach() {
  122. llvm_thread_detach_impl(Thread);
  123. Thread = native_handle_type();
  124. }
  125. namespace this_thread {
  126. inline thread::id get_id() { return llvm_thread_get_current_id_impl(); }
  127. } // namespace this_thread
  128. #else // !LLVM_ON_UNIX && !_WIN32
  129. /// std::thread backed implementation of llvm::thread interface that ignores the
  130. /// stack size request.
  131. class thread {
  132. public:
  133. using native_handle_type = std::thread::native_handle_type;
  134. using id = std::thread::id;
  135. thread() : Thread(std::thread()) {}
  136. thread(thread &&Other) noexcept
  137. : Thread(std::exchange(Other.Thread, std::thread())) {}
  138. template <class Function, class... Args>
  139. explicit thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
  140. Args &&...args)
  141. : Thread(std::forward<Function>(f), std::forward<Args>(args)...) {}
  142. template <class Function, class... Args>
  143. explicit thread(Function &&f, Args &&...args) : Thread(f, args...) {}
  144. thread(const thread &) = delete;
  145. ~thread() {}
  146. thread &operator=(thread &&Other) noexcept {
  147. Thread = std::exchange(Other.Thread, std::thread());
  148. return *this;
  149. }
  150. bool joinable() const noexcept { return Thread.joinable(); }
  151. id get_id() const noexcept { return Thread.get_id(); }
  152. native_handle_type native_handle() noexcept { return Thread.native_handle(); }
  153. static unsigned hardware_concurrency() {
  154. return std::thread::hardware_concurrency();
  155. };
  156. inline void join() { Thread.join(); }
  157. inline void detach() { Thread.detach(); }
  158. void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
  159. private:
  160. std::thread Thread;
  161. };
  162. namespace this_thread {
  163. inline thread::id get_id() { return std::this_thread::get_id(); }
  164. }
  165. #endif // LLVM_ON_UNIX || _WIN32
  166. } // namespace llvm
  167. #else // !LLVM_ENABLE_THREADS
  168. #include <utility>
  169. namespace llvm {
  170. struct thread {
  171. thread() {}
  172. thread(thread &&other) {}
  173. template <class Function, class... Args>
  174. explicit thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
  175. Args &&...args) {
  176. f(std::forward<Args>(args)...);
  177. }
  178. template <class Function, class... Args>
  179. explicit thread(Function &&f, Args &&...args) {
  180. f(std::forward<Args>(args)...);
  181. }
  182. thread(const thread &) = delete;
  183. void detach() {
  184. report_fatal_error("Detaching from a thread does not make sense with no "
  185. "threading support");
  186. }
  187. void join() {}
  188. static unsigned hardware_concurrency() { return 1; };
  189. };
  190. } // namespace llvm
  191. #endif // LLVM_ENABLE_THREADS
  192. #endif // LLVM_SUPPORT_THREAD_H
  193. #ifdef __GNUC__
  194. #pragma GCC diagnostic pop
  195. #endif