Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===--- A platform independent indirection for a thread class --*- 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 | #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H |
10 | #define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H |
11 | |
12 | #include "src/__support/CPP/atomic.h" |
13 | #include "src/__support/CPP/optional.h" |
14 | #include "src/__support/CPP/string_view.h" |
15 | #include "src/__support/CPP/stringstream.h" |
16 | #include "src/__support/macros/attributes.h" |
17 | #include "src/__support/macros/config.h" |
18 | #include "src/__support/macros/properties/architectures.h" |
19 | |
20 | // TODO: fix this unguarded linux dep |
21 | #include <linux/param.h> // for exec_pagesize. |
22 | |
23 | #include <stddef.h> // For size_t |
24 | #include <stdint.h> |
25 | |
26 | namespace LIBC_NAMESPACE_DECL { |
27 | |
28 | using ThreadRunnerPosix = void *(void *); |
29 | using ThreadRunnerStdc = int(void *); |
30 | |
31 | union ThreadRunner { |
32 | ThreadRunnerPosix *posix_runner; |
33 | ThreadRunnerStdc *stdc_runner; |
34 | }; |
35 | |
36 | union ThreadReturnValue { |
37 | void *posix_retval; |
38 | int stdc_retval; |
39 | constexpr ThreadReturnValue() : posix_retval(nullptr) {} |
40 | constexpr ThreadReturnValue(int r) : stdc_retval(r) {} |
41 | constexpr ThreadReturnValue(void *r) : posix_retval(r) {} |
42 | }; |
43 | |
44 | #if (defined(LIBC_TARGET_ARCH_IS_AARCH64) || \ |
45 | defined(LIBC_TARGET_ARCH_IS_X86_64) || \ |
46 | defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)) |
47 | constexpr unsigned int STACK_ALIGNMENT = 16; |
48 | #elif defined(LIBC_TARGET_ARCH_IS_ARM) |
49 | // See Section 6.2.1.2 Stack constraints at a public interface of AAPCS32. |
50 | constexpr unsigned int STACK_ALIGNMENT = 8; |
51 | #endif |
52 | // TODO: Provide stack alignment requirements for other architectures. |
53 | |
54 | enum class DetachState : uint32_t { |
55 | JOINABLE = 0x11, |
56 | EXITING = 0x22, |
57 | DETACHED = 0x33 |
58 | }; |
59 | |
60 | enum class ThreadStyle : uint8_t { POSIX = 0x1, STDC = 0x2 }; |
61 | |
62 | // Detach type is useful in testing the detach operation. |
63 | enum class DetachType : int { |
64 | // Indicates that the detach operation just set the detach state to DETACHED |
65 | // and returned. |
66 | SIMPLE = 1, |
67 | |
68 | // Indicates that the detach operation performed thread cleanup. |
69 | CLEANUP = 2 |
70 | }; |
71 | |
72 | class ThreadAtExitCallbackMgr; |
73 | |
74 | // A data type to hold common thread attributes which have to be stored as |
75 | // thread state. Note that this is different from public attribute types like |
76 | // pthread_attr_t which might contain information which need not be saved as |
77 | // part of a thread's state. For example, the stack guard size. |
78 | // |
79 | // Thread attributes are typically stored on the stack. So, we align as required |
80 | // for the target architecture. |
81 | struct alignas(STACK_ALIGNMENT) ThreadAttributes { |
82 | // We want the "detach_state" attribute to be an atomic value as it could be |
83 | // updated by one thread while the self thread is reading it. It is a tristate |
84 | // variable with the following state transitions: |
85 | // 1. The a thread is created in a detached state, then user code should never |
86 | // call a detach or join function. Calling either of them can lead to |
87 | // undefined behavior. |
88 | // The value of |detach_state| is expected to be DetachState::DETACHED for |
89 | // its lifetime. |
90 | // 2. If a thread is created in a joinable state, |detach_state| will start |
91 | // with the value DetachState::JOINABLE. Another thread can detach this |
92 | // thread before it exits. The state transitions will as follows: |
93 | // (a) If the detach method sees the state as JOINABLE, then it will |
94 | // compare exchange to a state of DETACHED. The thread will clean |
95 | // itself up after it finishes. |
96 | // (b) If the detach method does not see JOINABLE in (a), then it will |
97 | // conclude that the thread is EXITING and will wait until the thread |
98 | // exits. It will clean up the thread resources once the thread |
99 | // exits. |
100 | cpp::Atomic<uint32_t> detach_state; |
101 | void *stack; // Pointer to the thread stack |
102 | size_t stacksize; // Size of the stack |
103 | size_t guardsize; // Guard size on stack |
104 | uintptr_t tls; // Address to the thread TLS memory |
105 | uintptr_t tls_size; // The size of area pointed to by |tls|. |
106 | unsigned char owned_stack; // Indicates if the thread owns this stack memory |
107 | int tid; |
108 | ThreadStyle style; |
109 | ThreadReturnValue retval; |
110 | ThreadAtExitCallbackMgr *atexit_callback_mgr; |
111 | void *platform_data; |
112 | |
113 | constexpr ThreadAttributes() |
114 | : detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr), |
115 | stacksize(0), guardsize(0), tls(0), tls_size(0), owned_stack(false), |
116 | tid(-1), style(ThreadStyle::POSIX), retval(), |
117 | atexit_callback_mgr(nullptr), platform_data(nullptr) {} |
118 | }; |
119 | |
120 | using TSSDtor = void(void *); |
121 | |
122 | // Create a new TSS key and associate the |dtor| as the corresponding |
123 | // destructor. Can be used to implement public functions like |
124 | // pthread_key_create. |
125 | cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor); |
126 | |
127 | // Delete the |key|. Can be used to implement public functions like |
128 | // pthread_key_delete. |
129 | // |
130 | // Return true on success, false on failure. |
131 | bool tss_key_delete(unsigned int key); |
132 | |
133 | // Set the value associated with |key| for the current thread. Can be used |
134 | // to implement public functions like pthread_setspecific. |
135 | // |
136 | // Return true on success, false on failure. |
137 | bool set_tss_value(unsigned int key, void *value); |
138 | |
139 | // Return the value associated with |key| for the current thread. Return |
140 | // nullptr if |key| is invalid. Can be used to implement public functions like |
141 | // pthread_getspecific. |
142 | void *get_tss_value(unsigned int key); |
143 | |
144 | struct Thread { |
145 | // NB: Default stacksize of 64kb is exceedingly small compared to the 2mb norm |
146 | // and will break many programs expecting the full 2mb. |
147 | static constexpr size_t DEFAULT_STACKSIZE = 1 << 16; |
148 | static constexpr size_t DEFAULT_GUARDSIZE = EXEC_PAGESIZE; |
149 | static constexpr bool DEFAULT_DETACHED = false; |
150 | |
151 | ThreadAttributes *attrib; |
152 | |
153 | constexpr Thread() : attrib(nullptr) {} |
154 | constexpr Thread(ThreadAttributes *attr) : attrib(attr) {} |
155 | |
156 | int run(ThreadRunnerPosix *func, void *arg, void *stack = nullptr, |
157 | size_t stacksize = DEFAULT_STACKSIZE, |
158 | size_t guardsize = DEFAULT_GUARDSIZE, |
159 | bool detached = DEFAULT_DETACHED) { |
160 | ThreadRunner runner; |
161 | runner.posix_runner = func; |
162 | return run(ThreadStyle::POSIX, runner, arg, stack, stacksize, guardsize, |
163 | detached); |
164 | } |
165 | |
166 | int run(ThreadRunnerStdc *func, void *arg, void *stack = nullptr, |
167 | size_t stacksize = DEFAULT_STACKSIZE, |
168 | size_t guardsize = DEFAULT_GUARDSIZE, |
169 | bool detached = DEFAULT_DETACHED) { |
170 | ThreadRunner runner; |
171 | runner.stdc_runner = func; |
172 | return run(ThreadStyle::STDC, runner, arg, stack, stacksize, guardsize, |
173 | detached); |
174 | } |
175 | |
176 | int join(int *val) { |
177 | ThreadReturnValue retval; |
178 | int status = join(retval); |
179 | if (status != 0) |
180 | return status; |
181 | if (val != nullptr) |
182 | *val = retval.stdc_retval; |
183 | return 0; |
184 | } |
185 | |
186 | int join(void **val) { |
187 | ThreadReturnValue retval; |
188 | int status = join(retval); |
189 | if (status != 0) |
190 | return status; |
191 | if (val != nullptr) |
192 | *val = retval.posix_retval; |
193 | return 0; |
194 | } |
195 | |
196 | // Platform should implement the functions below. |
197 | |
198 | // Return 0 on success or an error value on failure. |
199 | int run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, |
200 | size_t stacksize, size_t guardsize, bool detached); |
201 | |
202 | // Return 0 on success or an error value on failure. |
203 | int join(ThreadReturnValue &retval); |
204 | |
205 | // Detach a joinable thread. |
206 | // |
207 | // This method does not have error return value. However, the type of detach |
208 | // is returned to help with testing. |
209 | int detach(); |
210 | |
211 | // Wait for the thread to finish. This method can only be called |
212 | // if: |
213 | // 1. A detached thread is guaranteed to be running. |
214 | // 2. A joinable thread has not been detached or joined. As long as it has |
215 | // not been detached or joined, wait can be called multiple times. |
216 | // |
217 | // Also, only one thread can wait and expect to get woken up when the thread |
218 | // finishes. |
219 | // |
220 | // NOTE: This function is to be used for testing only. There is no standard |
221 | // which requires exposing it via a public API. |
222 | void wait(); |
223 | |
224 | // Return true if this thread is equal to the other thread. |
225 | bool operator==(const Thread &other) const; |
226 | |
227 | // Set the name of the thread. Return the error number on error. |
228 | int set_name(const cpp::string_view &name); |
229 | |
230 | // Return the name of the thread in |name|. Return the error number of error. |
231 | int get_name(cpp::StringStream &name) const; |
232 | }; |
233 | |
234 | LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self; |
235 | |
236 | // Platforms should implement this function. |
237 | [[noreturn]] void thread_exit(ThreadReturnValue retval, ThreadStyle style); |
238 | |
239 | namespace internal { |
240 | // Internal namespace containing utilities which are to be used by platform |
241 | // implementations of threads. |
242 | |
243 | // Return the current thread's atexit callback manager. After thread startup |
244 | // but before running the thread function, platform implementations should |
245 | // set the "atexit_callback_mgr" field of the thread's attributes to the value |
246 | // returned by this function. |
247 | ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr(); |
248 | |
249 | // Call the currently registered thread specific atexit callbacks. Useful for |
250 | // implementing the thread_exit function. |
251 | void call_atexit_callbacks(ThreadAttributes *attrib); |
252 | |
253 | } // namespace internal |
254 | |
255 | } // namespace LIBC_NAMESPACE_DECL |
256 | |
257 | #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H |
258 |
Warning: This file is not a C or C++ file. It does not have highlighting.