xref: /aosp_15_r20/external/llvm-libc/src/__support/threads/thread.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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;
ThreadReturnValue()39   constexpr ThreadReturnValue() : posix_retval(nullptr) {}
ThreadReturnValue(int r)40   constexpr ThreadReturnValue(int r) : stdc_retval(r) {}
ThreadReturnValue(void * 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 
ThreadAttributesThreadAttributes113   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 
ThreadThread153   constexpr Thread() : attrib(nullptr) {}
ThreadThread154   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 
joinThread176   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 
joinThread186   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