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