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