brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · 6806098 Raw
258 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H10#define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H11 12#include "hdr/stdint_proxy.h"13#include "src/__support/CPP/atomic.h"14#include "src/__support/CPP/optional.h"15#include "src/__support/CPP/string_view.h"16#include "src/__support/CPP/stringstream.h"17#include "src/__support/macros/attributes.h"18#include "src/__support/macros/config.h"19#include "src/__support/macros/properties/architectures.h"20 21// TODO: fix this unguarded linux dep22#include <linux/param.h> // for exec_pagesize.23 24#include <stddef.h> // For size_t25 26namespace LIBC_NAMESPACE_DECL {27 28using ThreadRunnerPosix = void *(void *);29using ThreadRunnerStdc = int(void *);30 31union ThreadRunner {32  ThreadRunnerPosix *posix_runner;33  ThreadRunnerStdc *stdc_runner;34};35 36union 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))47constexpr 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.50constexpr unsigned int STACK_ALIGNMENT = 8;51#endif52// TODO: Provide stack alignment requirements for other architectures.53 54enum class DetachState : uint32_t {55  JOINABLE = 0x11,56  EXITING = 0x22,57  DETACHED = 0x3358};59 60enum class ThreadStyle : uint8_t { POSIX = 0x1, STDC = 0x2 };61 62// Detach type is useful in testing the detach operation.63enum class DetachType : int {64  // Indicates that the detach operation just set the detach state to DETACHED65  // and returned.66  SIMPLE = 1,67 68  // Indicates that the detach operation performed thread cleanup.69  CLEANUP = 270};71 72class ThreadAtExitCallbackMgr;73 74// A data type to hold common thread attributes which have to be stored as75// thread state. Note that this is different from public attribute types like76// pthread_attr_t which might contain information which need not be saved as77// 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 required80// for the target architecture.81struct alignas(STACK_ALIGNMENT) ThreadAttributes {82  // We want the "detach_state" attribute to be an atomic value as it could be83  // updated by one thread while the self thread is reading it. It is a tristate84  // variable with the following state transitions:85  // 1. The a thread is created in a detached state, then user code should never86  //    call a detach or join function. Calling either of them can lead to87  //    undefined behavior.88  //    The value of |detach_state| is expected to be DetachState::DETACHED for89  //    its lifetime.90  // 2. If a thread is created in a joinable state, |detach_state| will start91  //    with the value DetachState::JOINABLE. Another thread can detach this92  //    thread before it exits. The state transitions will as follows:93  //      (a) If the detach method sees the state as JOINABLE, then it will94  //          compare exchange to a state of DETACHED. The thread will clean95  //          itself up after it finishes.96  //      (b) If the detach method does not see JOINABLE in (a), then it will97  //          conclude that the thread is EXITING and will wait until the thread98  //          exits. It will clean up the thread resources once the thread99  //          exits.100  cpp::Atomic<uint32_t> detach_state;101  void *stack;               // Pointer to the thread stack102  size_t stacksize;          // Size of the stack103  size_t guardsize;          // Guard size on stack104  uintptr_t tls;             // Address to the thread TLS memory105  uintptr_t tls_size;        // The size of area pointed to by |tls|.106  unsigned char owned_stack; // Indicates if the thread owns this stack memory107  int tid;108  ThreadStyle style;109  ThreadReturnValue retval;110  ThreadAtExitCallbackMgr *atexit_callback_mgr;111  void *platform_data;112 113  LIBC_INLINE 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 120using TSSDtor = void(void *);121 122// Create a new TSS key and associate the |dtor| as the corresponding123// destructor. Can be used to implement public functions like124// pthread_key_create.125cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor);126 127// Delete the |key|. Can be used to implement public functions like128// pthread_key_delete.129//130// Return true on success, false on failure.131bool tss_key_delete(unsigned int key);132 133// Set the value associated with |key| for the current thread. Can be used134// to implement public functions like pthread_setspecific.135//136// Return true on success, false on failure.137bool set_tss_value(unsigned int key, void *value);138 139// Return the value associated with |key| for the current thread. Return140// nullptr if |key| is invalid. Can be used to implement public functions like141// pthread_getspecific.142void *get_tss_value(unsigned int key);143 144struct Thread {145  // NB: Default stacksize of 64kb is exceedingly small compared to the 2mb norm146  // 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 detach208  // is returned to help with testing.209  int detach();210 211  // Wait for the thread to finish. This method can only be called212  // 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 has215  //    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 thread218  // finishes.219  //220  // NOTE: This function is to be used for testing only. There is no standard221  // 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 234LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self;235 236// Platforms should implement this function.237[[noreturn]] void thread_exit(ThreadReturnValue retval, ThreadStyle style);238 239namespace internal {240// Internal namespace containing utilities which are to be used by platform241// implementations of threads.242 243// Return the current thread's atexit callback manager. After thread startup244// but before running the thread function, platform implementations should245// set the "atexit_callback_mgr" field of the thread's attributes to the value246// returned by this function.247ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr();248 249// Call the currently registered thread specific atexit callbacks. Useful for250// implementing the thread_exit function.251void call_atexit_callbacks(ThreadAttributes *attrib);252 253} // namespace internal254 255} // namespace LIBC_NAMESPACE_DECL256 257#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H258