diff options
author | Siva Chandra Reddy <sivachandra@google.com> | 2022-06-23 18:18:50 +0000 |
---|---|---|
committer | Siva Chandra Reddy <sivachandra@google.com> | 2022-06-24 08:22:53 +0000 |
commit | f4580c6d5a44379f3b1be033f39ec7af78dbbbfa (patch) | |
tree | f752af3d381abea1fd73fe38a903c54e4d93ff2d | |
parent | 2b3de2971790964691b351cc068f936eeeea32a4 (diff) | |
download | llvm-f4580c6d5a44379f3b1be033f39ec7af78dbbbfa.zip llvm-f4580c6d5a44379f3b1be033f39ec7af78dbbbfa.tar.gz llvm-f4580c6d5a44379f3b1be033f39ec7af78dbbbfa.tar.bz2 |
[libc][NFC] Remove the templatization from the linux implementation of thread.
This enables setting up a single "self" thread object to be returned by
API like thrd_self and pthread_self.
-rw-r--r-- | libc/src/__support/threads/linux/thread.h | 119 | ||||
-rw-r--r-- | libc/src/__support/threads/thread.h | 22 | ||||
-rw-r--r-- | libc/src/__support/threads/thread_attrib.h | 8 | ||||
-rw-r--r-- | libc/src/pthread/pthread_create.cpp | 6 | ||||
-rw-r--r-- | libc/src/pthread/pthread_detach.cpp | 6 | ||||
-rw-r--r-- | libc/src/pthread/pthread_join.cpp | 6 | ||||
-rw-r--r-- | libc/src/threads/thrd_create.cpp | 6 | ||||
-rw-r--r-- | libc/src/threads/thrd_detach.cpp | 6 | ||||
-rw-r--r-- | libc/src/threads/thrd_join.cpp | 6 |
9 files changed, 120 insertions, 65 deletions
diff --git a/libc/src/__support/threads/linux/thread.h b/libc/src/__support/threads/linux/thread.h index a947613..365f0fc 100644 --- a/libc/src/__support/threads/linux/thread.h +++ b/libc/src/__support/threads/linux/thread.h @@ -27,8 +27,6 @@ namespace __llvm_libc { -template <typename ReturnType> struct Thread; - #ifdef SYS_mmap2 static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2; #elif SYS_mmap @@ -72,16 +70,16 @@ static inline void free_stack(void *stack, size_t size) { __llvm_libc::syscall(SYS_munmap, stack, size); } -template <typename ReturnType> using ThreadRunner = ReturnType(void *); +struct Thread; // We align the start args to 16-byte boundary as we adjust the allocated // stack memory with its size. We want the adjusted address to be at a // 16-byte boundary to satisfy the x86_64 and aarch64 ABI requirements. // If different architecture in future requires higher alignment, then we // can add a platform specific alignment spec. -template <typename ReturnType> struct alignas(STACK_ALIGNMENT) StartArgs { - Thread<ReturnType> *thread; - ThreadRunner<ReturnType> *func; +struct alignas(STACK_ALIGNMENT) StartArgs { + Thread *thread; + ThreadRunner runner; void *arg; }; @@ -104,19 +102,57 @@ __attribute__((always_inline)) inline uintptr_t get_start_args_addr() { #endif } -template <typename ReturnType> struct Thread { +struct Thread { private: - ThreadAttributes<ReturnType> *attrib; + ThreadAttributes *attrib; cpp::Atomic<FutexWordType> *clear_tid; public: Thread() = default; - static void start_thread() __attribute__((noinline)); + static void start_thread() __attribute__((noinline)) { + auto *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr()); + auto *thread = start_args->thread; + auto *attrib = thread->attrib; + long retval; + if (attrib->style == ThreadStyle::POSIX) { + attrib->retval.posix_retval = + start_args->runner.posix_runner(start_args->arg); + retval = long(attrib->retval.posix_retval); + } else { + attrib->retval.stdc_retval = + start_args->runner.stdc_runner(start_args->arg); + retval = long(attrib->retval.stdc_retval); + } - // Return 0 on success or an error value on failure. - int run(ThreadRunner<ReturnType> *f, void *arg, void *stack, size_t size, + uint32_t joinable_state = uint32_t(DetachState::JOINABLE); + if (!thread->attrib->detach_state.compare_exchange_strong( + joinable_state, uint32_t(DetachState::EXITING))) { + // Thread is detached so cleanup the resources. + if (thread->attrib->owned_stack) + free_stack(thread->attrib->stack, thread->attrib->stack_size); + } + + __llvm_libc::syscall(SYS_exit, retval); + } + + int run(ThreadRunnerPosix *func, void *arg, void *stack, size_t size, + bool detached = false) { + ThreadRunner runner; + runner.posix_runner = func; + return run(ThreadStyle::POSIX, runner, arg, stack, size, detached); + } + + int run(ThreadRunnerStdc *func, void *arg, void *stack, size_t size, bool detached = false) { + ThreadRunner runner; + runner.stdc_runner = func; + return run(ThreadStyle::STDC, runner, arg, stack, size, detached); + } + + // Return 0 on success or an error value on failure. + int run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, + size_t size, bool detached) { bool owned_stack = false; if (stack == nullptr) { if (size == 0) @@ -139,19 +175,18 @@ public: // Likewise, the actual thread state information is also stored on the // stack memory. uintptr_t adjusted_stack = reinterpret_cast<uintptr_t>(stack) + size - - sizeof(StartArgs<ReturnType>) - - sizeof(ThreadAttributes<ReturnType>) - + sizeof(StartArgs) - sizeof(ThreadAttributes) - sizeof(cpp::Atomic<FutexWordType>); adjusted_stack &= ~(uintptr_t(STACK_ALIGNMENT) - 1); - auto *start_args = - reinterpret_cast<StartArgs<ReturnType> *>(adjusted_stack); + auto *start_args = reinterpret_cast<StartArgs *>(adjusted_stack); start_args->thread = this; - start_args->func = f; + start_args->runner = runner; start_args->arg = arg; - attrib = reinterpret_cast<ThreadAttributes<ReturnType> *>( - adjusted_stack + sizeof(StartArgs<ReturnType>)); + attrib = reinterpret_cast<ThreadAttributes *>(adjusted_stack + + sizeof(StartArgs)); + attrib->style = style; attrib->detach_state = uint32_t(detached ? DetachState::DETACHED : DetachState::JOINABLE); attrib->stack = stack; @@ -159,8 +194,7 @@ public: attrib->owned_stack = owned_stack; clear_tid = reinterpret_cast<cpp::Atomic<FutexWordType> *>( - adjusted_stack + sizeof(StartArgs<ReturnType>) + - sizeof(ThreadAttributes<ReturnType>)); + adjusted_stack + sizeof(StartArgs) + sizeof(ThreadAttributes)); clear_tid->val = CLEAR_TID_VALUE; // The clone syscall takes arguments in an architecture specific order. @@ -203,10 +237,32 @@ public: return 0; } - int join(ReturnType *retval) { + int join(int *val) { + ThreadReturnValue retval; + int status = join(retval); + if (status != 0) + return status; + *val = retval.stdc_retval; + return 0; + } + + int join(void **val) { + ThreadReturnValue retval; + int status = join(retval); + if (status != 0) + return status; + *val = retval.posix_retval; + return 0; + } + + int join(ThreadReturnValue &retval) { wait(); - *retval = attrib->retval; + if (attrib->style == ThreadStyle::POSIX) + retval.posix_retval = attrib->retval.posix_retval; + else + retval.stdc_retval = attrib->retval.stdc_retval; + if (attrib->owned_stack) free_stack(attrib->stack, attrib->stack_size); @@ -258,25 +314,6 @@ public: } }; -template <typename ReturnType> -__attribute__((noinline)) void Thread<ReturnType>::start_thread() { - auto *start_args = - reinterpret_cast<StartArgs<ReturnType> *>(get_start_args_addr()); - auto *thread = start_args->thread; - ReturnType retval = thread->attrib->retval = - start_args->func(start_args->arg); - - uint32_t joinable_state = uint32_t(DetachState::JOINABLE); - if (!thread->attrib->detach_state.compare_exchange_strong( - joinable_state, uint32_t(DetachState::EXITING))) { - // Thread is detached so cleanup the resources. - if (thread->attrib->owned_stack) - free_stack(thread->attrib->stack, thread->attrib->stack_size); - } - - __llvm_libc::syscall(SYS_exit, retval); -} - } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_SUPPORT_THREADS_LINUX_THREAD_H diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h index 2d38c37..368df2b 100644 --- a/libc/src/__support/threads/thread.h +++ b/libc/src/__support/threads/thread.h @@ -11,6 +11,19 @@ #include <stddef.h> +using ThreadRunnerPosix = void *(void *); +using ThreadRunnerStdc = int(void *); + +union ThreadRunner { + ThreadRunnerPosix *posix_runner; + ThreadRunnerStdc *stdc_runner; +}; + +union ThreadReturnValue { + void *posix_retval; + int stdc_retval; +}; + // The platform specific implemnetations are pulled via the following include. // The idea is for the platform implementation to implement a class named Thread // in the namespace __llvm_libc with the following properties: @@ -19,22 +32,25 @@ // // 2. Has a "run" method with the following signature: // -// int run(ThreadRunner *f, void *arg, void *stack, size_t size); +// int run(ThreadRunner runner, void *arg, void *stack, size_t size, +// bool detached); // // Returns: // 0 on success and an error value on failure. // Args: +// runner - The function to execute in the new thread. // arg - The argument to be passed to the thread runner after the thread // is created. // stack - The stack to use for the thread. // size - The stack size. +// detached - The detached state of the thread at startup. // -// If callers pass a non-null |stack| value, then it will assumed that +// If callers pass a non-null |stack| value, then it will be assumed that // 1. The clean up the stack memory is their responsibility // 2. The guard area is setup appropriately by the caller. // // 3. Has a "join" method with the following signature: -// ErrorOr<ReturnType> join(); +// int join(ThreadReturnValue &retval); // The "join" method should return 0 on success and set retcode to the // threads return value. On failure, an appropriate errno value should be // returned. diff --git a/libc/src/__support/threads/thread_attrib.h b/libc/src/__support/threads/thread_attrib.h index 31d97ac..c4deabd 100644 --- a/libc/src/__support/threads/thread_attrib.h +++ b/libc/src/__support/threads/thread_attrib.h @@ -27,6 +27,8 @@ enum class DetachState : uint32_t { DETACHED = 0x33 }; +enum class ThreadStyle : uint8_t { POSIX = 0x1, STDC = 0x2 }; + // Detach type is useful in testing the detach operation. enum class DetachType : int { // Indicates that the detach operation just set the detach state to DETACHED @@ -44,7 +46,6 @@ enum class DetachType : int { // // Thread attributes are typically stored on the stack. So, we align as required // for the target architecture. -template <typename ReturnType> struct alignas(STACK_ALIGNMENT) ThreadAttributes { // We want the "detach_state" attribute to be an atomic value as it could be // updated by one thread while the self thread is reading it. It is a tristate @@ -66,12 +67,13 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes { // exits. cpp::Atomic<uint32_t> detach_state; void *stack; // Pointer to the thread stack + void *tls; unsigned long long stack_size; // Size of the stack unsigned char owned_stack; // Indicates if the thread owns this stack memory - ReturnType retval; // The return value of thread runner is saved here int tid; + ThreadStyle style; + ThreadReturnValue retval; }; - } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_SUPPORT_THREADS_THREAD_ATTRIB_H diff --git a/libc/src/pthread/pthread_create.cpp b/libc/src/pthread/pthread_create.cpp index bc945a9..ec1e0e3 100644 --- a/libc/src/pthread/pthread_create.cpp +++ b/libc/src/pthread/pthread_create.cpp @@ -16,14 +16,14 @@ namespace __llvm_libc { -static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread<int>), - "Mismatch between pthread_t and internal Thread<int>."); +static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread), + "Mismatch between pthread_t and internal Thread."); LLVM_LIBC_FUNCTION(int, pthread_create, (pthread_t *__restrict th, const pthread_attr_t *__restrict attr, __pthread_start_t func, void *arg)) { - auto *thread = reinterpret_cast<__llvm_libc::Thread<void *> *>(th); + auto *thread = reinterpret_cast<__llvm_libc::Thread *>(th); int result = thread->run(func, arg, nullptr, 0); if (result != 0 && result != EPERM) return EAGAIN; diff --git a/libc/src/pthread/pthread_detach.cpp b/libc/src/pthread/pthread_detach.cpp index c71b12f..009438e 100644 --- a/libc/src/pthread/pthread_detach.cpp +++ b/libc/src/pthread/pthread_detach.cpp @@ -15,11 +15,11 @@ namespace __llvm_libc { -static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread<void *>), - "Mismatch between pthread_t and internal Thread<void *>."); +static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread), + "Mismatch between pthread_t and internal Thread."); LLVM_LIBC_FUNCTION(int, pthread_detach, (pthread_t th)) { - auto *thread = reinterpret_cast<Thread<void *> *>(&th); + auto *thread = reinterpret_cast<Thread *>(&th); thread->detach(); return 0; } diff --git a/libc/src/pthread/pthread_join.cpp b/libc/src/pthread/pthread_join.cpp index c3bf4ad..0774d02 100644 --- a/libc/src/pthread/pthread_join.cpp +++ b/libc/src/pthread/pthread_join.cpp @@ -15,11 +15,11 @@ namespace __llvm_libc { -static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread<int>), - "Mismatch between pthread_t and internal Thread<int>."); +static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread), + "Mismatch between pthread_t and internal Thread."); LLVM_LIBC_FUNCTION(int, pthread_join, (pthread_t th, void **retval)) { - auto *thread = reinterpret_cast<Thread<void *> *>(&th); + auto *thread = reinterpret_cast<Thread *>(&th); int result = thread->join(retval); return result; } diff --git a/libc/src/threads/thrd_create.cpp b/libc/src/threads/thrd_create.cpp index 91b36a7..9e81f0f 100644 --- a/libc/src/threads/thrd_create.cpp +++ b/libc/src/threads/thrd_create.cpp @@ -15,12 +15,12 @@ namespace __llvm_libc { -static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread<int>), - "Mismatch between thrd_t and internal Thread<int>."); +static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread), + "Mismatch between thrd_t and internal Thread."); LLVM_LIBC_FUNCTION(int, thrd_create, (thrd_t * th, thrd_start_t func, void *arg)) { - auto *thread = reinterpret_cast<__llvm_libc::Thread<int> *>(th); + auto *thread = reinterpret_cast<__llvm_libc::Thread *>(th); int result = thread->run(func, arg, nullptr, 0); if (result == 0) return thrd_success; diff --git a/libc/src/threads/thrd_detach.cpp b/libc/src/threads/thrd_detach.cpp index e3c4301..20c6540 100644 --- a/libc/src/threads/thrd_detach.cpp +++ b/libc/src/threads/thrd_detach.cpp @@ -14,11 +14,11 @@ namespace __llvm_libc { -static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread<int>), - "Mismatch between thrd_t and internal Thread<int>."); +static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread), + "Mismatch between thrd_t and internal Thread."); LLVM_LIBC_FUNCTION(int, thrd_detach, (thrd_t th)) { - auto *thread = reinterpret_cast<Thread<int> *>(&th); + auto *thread = reinterpret_cast<Thread *>(&th); thread->detach(); return 0; } diff --git a/libc/src/threads/thrd_join.cpp b/libc/src/threads/thrd_join.cpp index fbdfa78..4c3ecac 100644 --- a/libc/src/threads/thrd_join.cpp +++ b/libc/src/threads/thrd_join.cpp @@ -14,11 +14,11 @@ namespace __llvm_libc { -static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread<int>), - "Mismatch between thrd_t and internal Thread<int>."); +static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread), + "Mismatch between thrd_t and internal Thread."); LLVM_LIBC_FUNCTION(int, thrd_join, (thrd_t * th, int *retval)) { - auto *thread = reinterpret_cast<Thread<int> *>(th); + auto *thread = reinterpret_cast<Thread *>(th); int result = thread->join(retval); return result == 0 ? thrd_success : thrd_error; } |