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