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