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