thread.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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/ADT/Optional.h"
  23. #include "llvm/Config/llvm-config.h"
  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 FPtr, typename... Args, size_t... Indices>
  37. static void Apply(std::tuple<FPtr, Args...> &Callee,
  38. std::index_sequence<Indices...>) {
  39. std::move(std::get<0>(Callee))(std::move(std::get<Indices + 1>(Callee))...);
  40. }
  41. template <typename CalleeTuple> static void GenericThreadProxy(void *Ptr) {
  42. std::unique_ptr<CalleeTuple> Callee(static_cast<CalleeTuple *>(Ptr));
  43. // FIXME: use std::apply when C++17 is allowed.
  44. std::make_index_sequence<std::tuple_size<CalleeTuple>() - 1> Indices{};
  45. Apply(*Callee.get(), Indices);
  46. }
  47. public:
  48. #if LLVM_ON_UNIX
  49. using native_handle_type = pthread_t;
  50. using id = pthread_t;
  51. using start_routine_type = void *(*)(void *);
  52. template <typename CalleeTuple> static void *ThreadProxy(void *Ptr) {
  53. GenericThreadProxy<CalleeTuple>(Ptr);
  54. return nullptr;
  55. }
  56. #elif _WIN32
  57. using native_handle_type = HANDLE;
  58. using id = DWORD;
  59. using start_routine_type = unsigned(__stdcall *)(void *);
  60. template <typename CalleeTuple>
  61. static unsigned __stdcall ThreadProxy(void *Ptr) {
  62. GenericThreadProxy<CalleeTuple>(Ptr);
  63. return 0;
  64. }
  65. #endif
  66. static const llvm::Optional<unsigned> DefaultStackSize;
  67. thread() : Thread(native_handle_type()) {}
  68. thread(thread &&Other) noexcept
  69. : Thread(std::exchange(Other.Thread, native_handle_type())) {}
  70. template <class Function, class... Args>
  71. explicit thread(Function &&f, Args &&...args)
  72. : thread(DefaultStackSize, f, args...) {}
  73. template <class Function, class... Args>
  74. explicit thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
  75. Args &&...args);
  76. thread(const thread &) = delete;
  77. ~thread() {
  78. if (joinable())
  79. std::terminate();
  80. }
  81. thread &operator=(thread &&Other) noexcept {
  82. if (joinable())
  83. std::terminate();
  84. Thread = std::exchange(Other.Thread, native_handle_type());
  85. return *this;
  86. }
  87. bool joinable() const noexcept { return Thread != native_handle_type(); }
  88. inline id get_id() const noexcept;
  89. native_handle_type native_handle() const noexcept { return Thread; }
  90. static unsigned hardware_concurrency() {
  91. return std::thread::hardware_concurrency();
  92. };
  93. inline void join();
  94. inline void detach();
  95. void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
  96. private:
  97. native_handle_type Thread;
  98. };
  99. thread::native_handle_type
  100. llvm_execute_on_thread_impl(thread::start_routine_type ThreadFunc, void *Arg,
  101. llvm::Optional<unsigned> StackSizeInBytes);
  102. void llvm_thread_join_impl(thread::native_handle_type Thread);
  103. void llvm_thread_detach_impl(thread::native_handle_type Thread);
  104. thread::id llvm_thread_get_id_impl(thread::native_handle_type Thread);
  105. thread::id llvm_thread_get_current_id_impl();
  106. template <class Function, class... Args>
  107. thread::thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
  108. Args &&...args) {
  109. typedef std::tuple<typename std::decay<Function>::type,
  110. typename std::decay<Args>::type...>
  111. CalleeTuple;
  112. std::unique_ptr<CalleeTuple> Callee(
  113. new CalleeTuple(std::forward<Function>(f), std::forward<Args>(args)...));
  114. Thread = llvm_execute_on_thread_impl(ThreadProxy<CalleeTuple>, Callee.get(),
  115. StackSizeInBytes);
  116. if (Thread != native_handle_type())
  117. Callee.release();
  118. }
  119. thread::id thread::get_id() const noexcept {
  120. return llvm_thread_get_id_impl(Thread);
  121. }
  122. void thread::join() {
  123. llvm_thread_join_impl(Thread);
  124. Thread = native_handle_type();
  125. }
  126. void thread::detach() {
  127. llvm_thread_detach_impl(Thread);
  128. Thread = native_handle_type();
  129. }
  130. namespace this_thread {
  131. inline thread::id get_id() { return llvm_thread_get_current_id_impl(); }
  132. } // namespace this_thread
  133. #else // !LLVM_ON_UNIX && !_WIN32
  134. /// std::thread backed implementation of llvm::thread interface that ignores the
  135. /// stack size request.
  136. class thread {
  137. public:
  138. using native_handle_type = std::thread::native_handle_type;
  139. using id = std::thread::id;
  140. thread() : Thread(std::thread()) {}
  141. thread(thread &&Other) noexcept
  142. : Thread(std::exchange(Other.Thread, std::thread())) {}
  143. template <class Function, class... Args>
  144. explicit thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
  145. Args &&...args)
  146. : Thread(std::forward<Function>(f), std::forward<Args>(args)...) {}
  147. template <class Function, class... Args>
  148. explicit thread(Function &&f, Args &&...args) : Thread(f, args...) {}
  149. thread(const thread &) = delete;
  150. ~thread() {}
  151. thread &operator=(thread &&Other) noexcept {
  152. Thread = std::exchange(Other.Thread, std::thread());
  153. return *this;
  154. }
  155. bool joinable() const noexcept { return Thread.joinable(); }
  156. id get_id() const noexcept { return Thread.get_id(); }
  157. native_handle_type native_handle() noexcept { return Thread.native_handle(); }
  158. static unsigned hardware_concurrency() {
  159. return std::thread::hardware_concurrency();
  160. };
  161. inline void join() { Thread.join(); }
  162. inline void detach() { Thread.detach(); }
  163. void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
  164. private:
  165. std::thread Thread;
  166. };
  167. namespace this_thread {
  168. inline thread::id get_id() { return std::this_thread::get_id(); }
  169. }
  170. #endif // LLVM_ON_UNIX || _WIN32
  171. } // namespace llvm
  172. #else // !LLVM_ENABLE_THREADS
  173. #include <utility>
  174. namespace llvm {
  175. struct thread {
  176. thread() {}
  177. thread(thread &&other) {}
  178. template <class Function, class... Args>
  179. explicit thread(llvm::Optional<unsigned> StackSizeInBytes, Function &&f,
  180. Args &&...args) {
  181. f(std::forward<Args>(args)...);
  182. }
  183. template <class Function, class... Args>
  184. explicit thread(Function &&f, Args &&...args) {
  185. f(std::forward<Args>(args)...);
  186. }
  187. thread(const thread &) = delete;
  188. void detach() {
  189. report_fatal_error("Detaching from a thread does not make sense with no "
  190. "threading support");
  191. }
  192. void join() {}
  193. static unsigned hardware_concurrency() { return 1; };
  194. };
  195. } // namespace llvm
  196. #endif // LLVM_ENABLE_THREADS
  197. #endif // LLVM_SUPPORT_THREAD_H
  198. #ifdef __GNUC__
  199. #pragma GCC diagnostic pop
  200. #endif