1fe801747SSiva Chandra Reddy //===--- Implementation of a Linux thread class -----------------*- C++ -*-===// 2fe801747SSiva Chandra Reddy // 3fe801747SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe801747SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 5fe801747SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe801747SSiva Chandra Reddy // 7fe801747SSiva Chandra Reddy //===----------------------------------------------------------------------===// 8fe801747SSiva Chandra Reddy 9fe801747SSiva Chandra Reddy #include "src/__support/threads/thread.h" 101a92cc5aSJoseph Huber #include "config/app.h" 11fe801747SSiva Chandra Reddy #include "src/__support/CPP/atomic.h" 129beb8d11SMichael Jones #include "src/__support/CPP/string_view.h" 13658c84e4SSiva Chandra Reddy #include "src/__support/CPP/stringstream.h" 14fe801747SSiva Chandra Reddy #include "src/__support/OSUtil/syscall.h" // For syscall functions. 1559c809cdSSiva Chandra Reddy #include "src/__support/common.h" 169beb8d11SMichael Jones #include "src/__support/error_or.h" 175ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 18ab3a9e72SSchrodinger ZHU Yifan #include "src/__support/threads/linux/futex_utils.h" // For FutexWordType 1904a9c625SMichael Jones #include "src/errno/libc_errno.h" // For error macros 20fe801747SSiva Chandra Reddy 21a2569a76SGuillaume Chatelet #ifdef LIBC_TARGET_ARCH_IS_AARCH64 22fe801747SSiva Chandra Reddy #include <arm_acle.h> 23fe801747SSiva Chandra Reddy #endif 24fe801747SSiva Chandra Reddy 25*abc49cc1SJob Henandez Lara #include "hdr/fcntl_macros.h" 266a185718SNoah Goldstein #include <linux/param.h> // For EXEC_PAGESIZE. 27658c84e4SSiva Chandra Reddy #include <linux/prctl.h> // For PR_SET_NAME 28fe801747SSiva Chandra Reddy #include <linux/sched.h> // For CLONE_* flags. 29fe801747SSiva Chandra Reddy #include <stdint.h> 30fe801747SSiva Chandra Reddy #include <sys/mman.h> // For PROT_* and MAP_* definitions. 31fe801747SSiva Chandra Reddy #include <sys/syscall.h> // For syscall numbers. 32fe801747SSiva Chandra Reddy 335ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 34fe801747SSiva Chandra Reddy 35fe801747SSiva Chandra Reddy #ifdef SYS_mmap2 36fe801747SSiva Chandra Reddy static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2; 375b22df99SMikhail R. Gadelha #elif defined(SYS_mmap) 38fe801747SSiva Chandra Reddy static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap; 39fe801747SSiva Chandra Reddy #else 405b22df99SMikhail R. Gadelha #error "mmap or mmap2 syscalls not available." 41fe801747SSiva Chandra Reddy #endif 42fe801747SSiva Chandra Reddy 43658c84e4SSiva Chandra Reddy static constexpr size_t NAME_SIZE_MAX = 16; // Includes the null terminator 44fe801747SSiva Chandra Reddy static constexpr uint32_t CLEAR_TID_VALUE = 0xABCD1234; 45fe801747SSiva Chandra Reddy static constexpr unsigned CLONE_SYSCALL_FLAGS = 46fe801747SSiva Chandra Reddy CLONE_VM // Share the memory space with the parent. 47fe801747SSiva Chandra Reddy | CLONE_FS // Share the file system with the parent. 48fe801747SSiva Chandra Reddy | CLONE_FILES // Share the files with the parent. 49fe801747SSiva Chandra Reddy | CLONE_SIGHAND // Share the signal handlers with the parent. 50fe801747SSiva Chandra Reddy | CLONE_THREAD // Same thread group as the parent. 51fe801747SSiva Chandra Reddy | CLONE_SYSVSEM // Share a single list of System V semaphore adjustment 52fe801747SSiva Chandra Reddy // values 53fe801747SSiva Chandra Reddy | CLONE_PARENT_SETTID // Set child thread ID in |ptid| of the parent. 54859c1897SSiva Chandra Reddy | CLONE_CHILD_CLEARTID // Let the kernel clear the tid address 55fe801747SSiva Chandra Reddy // wake the joining thread. 56859c1897SSiva Chandra Reddy | CLONE_SETTLS; // Setup the thread pointer of the new thread. 57fe801747SSiva Chandra Reddy 58cf90633cSSiva Chandra #ifdef LIBC_TARGET_ARCH_IS_AARCH64 59cf90633cSSiva Chandra #define CLONE_RESULT_REGISTER "x0" 60e3087c4bSMikhail R. Gadelha #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) 61cf90633cSSiva Chandra #define CLONE_RESULT_REGISTER "t0" 62cf90633cSSiva Chandra #elif defined(LIBC_TARGET_ARCH_IS_X86_64) 63cf90633cSSiva Chandra #define CLONE_RESULT_REGISTER "rax" 64cf90633cSSiva Chandra #else 65cf90633cSSiva Chandra #error "CLONE_RESULT_REGISTER not defined for your target architecture" 66cf90633cSSiva Chandra #endif 67cf90633cSSiva Chandra 686a185718SNoah Goldstein static constexpr ErrorOr<size_t> add_no_overflow(size_t lhs, size_t rhs) { 696a185718SNoah Goldstein if (lhs > SIZE_MAX - rhs) 706a185718SNoah Goldstein return Error{EINVAL}; 716a185718SNoah Goldstein if (rhs > SIZE_MAX - lhs) 726a185718SNoah Goldstein return Error{EINVAL}; 736a185718SNoah Goldstein return lhs + rhs; 746a185718SNoah Goldstein } 756a185718SNoah Goldstein 766a185718SNoah Goldstein static constexpr ErrorOr<size_t> round_to_page(size_t v) { 776a185718SNoah Goldstein auto vp_or_err = add_no_overflow(v, EXEC_PAGESIZE - 1); 786a185718SNoah Goldstein if (!vp_or_err) 796a185718SNoah Goldstein return vp_or_err; 806a185718SNoah Goldstein 816a185718SNoah Goldstein return vp_or_err.value() & -EXEC_PAGESIZE; 826a185718SNoah Goldstein } 836a185718SNoah Goldstein 846a185718SNoah Goldstein LIBC_INLINE ErrorOr<void *> alloc_stack(size_t stacksize, size_t guardsize) { 856a185718SNoah Goldstein 866a185718SNoah Goldstein // Guard needs to be mapped with PROT_NONE 876a185718SNoah Goldstein int prot = guardsize ? PROT_NONE : PROT_READ | PROT_WRITE; 886a185718SNoah Goldstein auto size_or_err = add_no_overflow(stacksize, guardsize); 896a185718SNoah Goldstein if (!size_or_err) 906a185718SNoah Goldstein return Error{int(size_or_err.error())}; 916a185718SNoah Goldstein size_t size = size_or_err.value(); 926a185718SNoah Goldstein 936a185718SNoah Goldstein // TODO: Maybe add MAP_STACK? Currently unimplemented on linux but helps 946a185718SNoah Goldstein // future-proof. 95b6bc9d72SGuillaume Chatelet long mmap_result = LIBC_NAMESPACE::syscall_impl<long>( 96f0a3954eSMichael Jones MMAP_SYSCALL_NUMBER, 97fe801747SSiva Chandra Reddy 0, // No special address 986a185718SNoah Goldstein size, prot, 996a185718SNoah Goldstein MAP_ANONYMOUS | MAP_PRIVATE, // Process private. 100fe801747SSiva Chandra Reddy -1, // Not backed by any file 101fe801747SSiva Chandra Reddy 0 // No offset 102fe801747SSiva Chandra Reddy ); 103fe801747SSiva Chandra Reddy if (mmap_result < 0 && (uintptr_t(mmap_result) >= UINTPTR_MAX - size)) 1049beb8d11SMichael Jones return Error{int(-mmap_result)}; 1056a185718SNoah Goldstein 1066a185718SNoah Goldstein if (guardsize) { 1076a185718SNoah Goldstein // Give read/write permissions to actual stack. 1086a185718SNoah Goldstein // TODO: We are assuming stack growsdown here. 109b6bc9d72SGuillaume Chatelet long result = LIBC_NAMESPACE::syscall_impl<long>( 110b6bc9d72SGuillaume Chatelet SYS_mprotect, mmap_result + guardsize, stacksize, 111b6bc9d72SGuillaume Chatelet PROT_READ | PROT_WRITE); 1126a185718SNoah Goldstein 1136a185718SNoah Goldstein if (result != 0) 1146a185718SNoah Goldstein return Error{int(-result)}; 1156a185718SNoah Goldstein } 1166a185718SNoah Goldstein mmap_result += guardsize; 117fe801747SSiva Chandra Reddy return reinterpret_cast<void *>(mmap_result); 118fe801747SSiva Chandra Reddy } 119fe801747SSiva Chandra Reddy 120916e9be4SNoah Goldstein // This must always be inlined as we may be freeing the calling threads stack in 121916e9be4SNoah Goldstein // which case a normal return from the top the stack would cause an invalid 122916e9be4SNoah Goldstein // memory read. 1235bf8efd2SRoland McGrath [[gnu::always_inline]] LIBC_INLINE void 124916e9be4SNoah Goldstein free_stack(void *stack, size_t stacksize, size_t guardsize) { 1256a185718SNoah Goldstein uintptr_t stackaddr = reinterpret_cast<uintptr_t>(stack); 1266a185718SNoah Goldstein stackaddr -= guardsize; 1276a185718SNoah Goldstein stack = reinterpret_cast<void *>(stackaddr); 128b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_munmap, stack, stacksize + guardsize); 129fe801747SSiva Chandra Reddy } 130fe801747SSiva Chandra Reddy 131fe801747SSiva Chandra Reddy struct Thread; 132fe801747SSiva Chandra Reddy 133fe801747SSiva Chandra Reddy // We align the start args to 16-byte boundary as we adjust the allocated 134fe801747SSiva Chandra Reddy // stack memory with its size. We want the adjusted address to be at a 135fe801747SSiva Chandra Reddy // 16-byte boundary to satisfy the x86_64 and aarch64 ABI requirements. 136fe801747SSiva Chandra Reddy // If different architecture in future requires higher alignment, then we 137fe801747SSiva Chandra Reddy // can add a platform specific alignment spec. 138fe801747SSiva Chandra Reddy struct alignas(STACK_ALIGNMENT) StartArgs { 139379428c2SSiva Chandra Reddy ThreadAttributes *thread_attrib; 140fe801747SSiva Chandra Reddy ThreadRunner runner; 141fe801747SSiva Chandra Reddy void *arg; 142fe801747SSiva Chandra Reddy }; 143fe801747SSiva Chandra Reddy 144916e9be4SNoah Goldstein // This must always be inlined as we may be freeing the calling threads stack in 145916e9be4SNoah Goldstein // which case a normal return from the top the stack would cause an invalid 146916e9be4SNoah Goldstein // memory read. 1475bf8efd2SRoland McGrath [[gnu::always_inline]] LIBC_INLINE void 148916e9be4SNoah Goldstein cleanup_thread_resources(ThreadAttributes *attrib) { 149859c1897SSiva Chandra Reddy // Cleanup the TLS before the stack as the TLS information is stored on 150859c1897SSiva Chandra Reddy // the stack. 151859c1897SSiva Chandra Reddy cleanup_tls(attrib->tls, attrib->tls_size); 152859c1897SSiva Chandra Reddy if (attrib->owned_stack) 1536a185718SNoah Goldstein free_stack(attrib->stack, attrib->stacksize, attrib->guardsize); 154859c1897SSiva Chandra Reddy } 155859c1897SSiva Chandra Reddy 1565bf8efd2SRoland McGrath [[gnu::always_inline]] LIBC_INLINE uintptr_t get_start_args_addr() { 157fe801747SSiva Chandra Reddy // NOTE: For __builtin_frame_address to work reliably across compilers, 158fe801747SSiva Chandra Reddy // architectures and various optimization levels, the TU including this file 159fe801747SSiva Chandra Reddy // should be compiled with -fno-omit-frame-pointer. 160a2569a76SGuillaume Chatelet #ifdef LIBC_TARGET_ARCH_IS_X86_64 161fe801747SSiva Chandra Reddy return reinterpret_cast<uintptr_t>(__builtin_frame_address(0)) 162fe801747SSiva Chandra Reddy // The x86_64 call instruction pushes resume address on to the stack. 163fe801747SSiva Chandra Reddy // Next, The x86_64 SysV ABI requires that the frame pointer be pushed 164fe801747SSiva Chandra Reddy // on to the stack. So, we have to step past two 64-bit values to get 165fe801747SSiva Chandra Reddy // to the start args. 166fe801747SSiva Chandra Reddy + sizeof(uintptr_t) * 2; 167c1bb7108SSiva Chandra #elif defined(LIBC_TARGET_ARCH_IS_AARCH64) 168fe801747SSiva Chandra Reddy // The frame pointer after cloning the new thread in the Thread::run method 169fe801747SSiva Chandra Reddy // is set to the stack pointer where start args are stored. So, we fetch 170fe801747SSiva Chandra Reddy // from there. 171fe801747SSiva Chandra Reddy return reinterpret_cast<uintptr_t>(__builtin_frame_address(1)); 172e3087c4bSMikhail R. Gadelha #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) 173c1bb7108SSiva Chandra // The current frame pointer is the previous stack pointer where the start 174c1bb7108SSiva Chandra // args are stored. 175c1bb7108SSiva Chandra return reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); 176fe801747SSiva Chandra Reddy #endif 177fe801747SSiva Chandra Reddy } 178fe801747SSiva Chandra Reddy 1799c2e5449SNick Desaulniers [[gnu::noinline]] void start_thread() { 180fe801747SSiva Chandra Reddy auto *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr()); 181379428c2SSiva Chandra Reddy auto *attrib = start_args->thread_attrib; 1828dc42802SSiva Chandra Reddy self.attrib = attrib; 1830071a795SSiva Chandra Reddy self.attrib->atexit_callback_mgr = internal::get_thread_atexit_callback_mgr(); 1848dc42802SSiva Chandra Reddy 185fe801747SSiva Chandra Reddy if (attrib->style == ThreadStyle::POSIX) { 186fe801747SSiva Chandra Reddy attrib->retval.posix_retval = 187fe801747SSiva Chandra Reddy start_args->runner.posix_runner(start_args->arg); 1880071a795SSiva Chandra Reddy thread_exit(ThreadReturnValue(attrib->retval.posix_retval), 1890071a795SSiva Chandra Reddy ThreadStyle::POSIX); 190fe801747SSiva Chandra Reddy } else { 191fe801747SSiva Chandra Reddy attrib->retval.stdc_retval = 192fe801747SSiva Chandra Reddy start_args->runner.stdc_runner(start_args->arg); 1930071a795SSiva Chandra Reddy thread_exit(ThreadReturnValue(attrib->retval.stdc_retval), 1940071a795SSiva Chandra Reddy ThreadStyle::STDC); 195fe801747SSiva Chandra Reddy } 196fe801747SSiva Chandra Reddy } 197fe801747SSiva Chandra Reddy 198fe801747SSiva Chandra Reddy int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, 1996a185718SNoah Goldstein size_t stacksize, size_t guardsize, bool detached) { 200fe801747SSiva Chandra Reddy bool owned_stack = false; 201fe801747SSiva Chandra Reddy if (stack == nullptr) { 2026a185718SNoah Goldstein // TODO: Should we return EINVAL here? Should we have a generic concept of a 2036a185718SNoah Goldstein // minimum stacksize (like 16384 for pthread). 2046a185718SNoah Goldstein if (stacksize == 0) 2056a185718SNoah Goldstein stacksize = DEFAULT_STACKSIZE; 2066a185718SNoah Goldstein // Roundup stacksize/guardsize to page size. 2076a185718SNoah Goldstein // TODO: Should be also add sizeof(ThreadAttribute) and other internal 2086a185718SNoah Goldstein // meta data? 2096a185718SNoah Goldstein auto round_or_err = round_to_page(guardsize); 2106a185718SNoah Goldstein if (!round_or_err) 2116a185718SNoah Goldstein return round_or_err.error(); 2126a185718SNoah Goldstein guardsize = round_or_err.value(); 2136a185718SNoah Goldstein 2146a185718SNoah Goldstein round_or_err = round_to_page(stacksize); 2156a185718SNoah Goldstein if (!round_or_err) 2166a185718SNoah Goldstein return round_or_err.error(); 2176a185718SNoah Goldstein 2186a185718SNoah Goldstein stacksize = round_or_err.value(); 2196a185718SNoah Goldstein auto alloc = alloc_stack(stacksize, guardsize); 220fe801747SSiva Chandra Reddy if (!alloc) 2219beb8d11SMichael Jones return alloc.error(); 222fe801747SSiva Chandra Reddy else 223fe801747SSiva Chandra Reddy stack = alloc.value(); 224fe801747SSiva Chandra Reddy owned_stack = true; 225fe801747SSiva Chandra Reddy } 226fe801747SSiva Chandra Reddy 2276a185718SNoah Goldstein // Validate that stack/stacksize are validly aligned. 2286a185718SNoah Goldstein uintptr_t stackaddr = reinterpret_cast<uintptr_t>(stack); 2296a185718SNoah Goldstein if ((stackaddr % STACK_ALIGNMENT != 0) || 2306a185718SNoah Goldstein ((stackaddr + stacksize) % STACK_ALIGNMENT != 0)) { 2316a185718SNoah Goldstein if (owned_stack) 2326a185718SNoah Goldstein free_stack(stack, stacksize, guardsize); 2336a185718SNoah Goldstein return EINVAL; 2346a185718SNoah Goldstein } 2356a185718SNoah Goldstein 236859c1897SSiva Chandra Reddy TLSDescriptor tls; 237859c1897SSiva Chandra Reddy init_tls(tls); 238859c1897SSiva Chandra Reddy 239fe801747SSiva Chandra Reddy // When the new thread is spawned by the kernel, the new thread gets the 240fe801747SSiva Chandra Reddy // stack we pass to the clone syscall. However, this stack is empty and does 241fe801747SSiva Chandra Reddy // not have any local vars present in this function. Hence, one cannot 242fe801747SSiva Chandra Reddy // pass arguments to the thread start function, or use any local vars from 243fe801747SSiva Chandra Reddy // here. So, we pack them into the new stack from where the thread can sniff 244fe801747SSiva Chandra Reddy // them out. 245fe801747SSiva Chandra Reddy // 246fe801747SSiva Chandra Reddy // Likewise, the actual thread state information is also stored on the 247fe801747SSiva Chandra Reddy // stack memory. 2486a185718SNoah Goldstein 2496a185718SNoah Goldstein static constexpr size_t INTERNAL_STACK_DATA_SIZE = 250ab3a9e72SSchrodinger ZHU Yifan sizeof(StartArgs) + sizeof(ThreadAttributes) + sizeof(Futex); 2516a185718SNoah Goldstein 2526a185718SNoah Goldstein // This is pretty arbitrary, but at the moment we don't adjust user provided 2536a185718SNoah Goldstein // stacksize (or default) to account for this data as its assumed minimal. If 2546a185718SNoah Goldstein // this assert starts failing we probably should. Likewise if we can't bound 2556a185718SNoah Goldstein // this we may overflow when we subtract it from the top of the stack. 2566a185718SNoah Goldstein static_assert(INTERNAL_STACK_DATA_SIZE < EXEC_PAGESIZE); 2576a185718SNoah Goldstein 2586a185718SNoah Goldstein // TODO: We are assuming stack growsdown here. 2596a185718SNoah Goldstein auto adjusted_stack_or_err = 2606a185718SNoah Goldstein add_no_overflow(reinterpret_cast<uintptr_t>(stack), stacksize); 2616a185718SNoah Goldstein if (!adjusted_stack_or_err) { 2626a185718SNoah Goldstein cleanup_tls(tls.addr, tls.size); 2636a185718SNoah Goldstein if (owned_stack) 2646a185718SNoah Goldstein free_stack(stack, stacksize, guardsize); 2656a185718SNoah Goldstein return adjusted_stack_or_err.error(); 2666a185718SNoah Goldstein } 2676a185718SNoah Goldstein 2686a185718SNoah Goldstein uintptr_t adjusted_stack = 2696a185718SNoah Goldstein adjusted_stack_or_err.value() - INTERNAL_STACK_DATA_SIZE; 270fe801747SSiva Chandra Reddy adjusted_stack &= ~(uintptr_t(STACK_ALIGNMENT) - 1); 271fe801747SSiva Chandra Reddy 272fe801747SSiva Chandra Reddy auto *start_args = reinterpret_cast<StartArgs *>(adjusted_stack); 273fe801747SSiva Chandra Reddy 274fe801747SSiva Chandra Reddy attrib = 275fe801747SSiva Chandra Reddy reinterpret_cast<ThreadAttributes *>(adjusted_stack + sizeof(StartArgs)); 276fe801747SSiva Chandra Reddy attrib->style = style; 277fe801747SSiva Chandra Reddy attrib->detach_state = 278fe801747SSiva Chandra Reddy uint32_t(detached ? DetachState::DETACHED : DetachState::JOINABLE); 279fe801747SSiva Chandra Reddy attrib->stack = stack; 2806a185718SNoah Goldstein attrib->stacksize = stacksize; 2816a185718SNoah Goldstein attrib->guardsize = guardsize; 282fe801747SSiva Chandra Reddy attrib->owned_stack = owned_stack; 283859c1897SSiva Chandra Reddy attrib->tls = tls.addr; 284859c1897SSiva Chandra Reddy attrib->tls_size = tls.size; 285fe801747SSiva Chandra Reddy 286379428c2SSiva Chandra Reddy start_args->thread_attrib = attrib; 287379428c2SSiva Chandra Reddy start_args->runner = runner; 288379428c2SSiva Chandra Reddy start_args->arg = arg; 289379428c2SSiva Chandra Reddy 290ab3a9e72SSchrodinger ZHU Yifan auto clear_tid = reinterpret_cast<Futex *>( 291fe801747SSiva Chandra Reddy adjusted_stack + sizeof(StartArgs) + sizeof(ThreadAttributes)); 292ab3a9e72SSchrodinger ZHU Yifan clear_tid->set(CLEAR_TID_VALUE); 2933c5d6312SSiva Chandra Reddy attrib->platform_data = clear_tid; 294fe801747SSiva Chandra Reddy 295fe801747SSiva Chandra Reddy // The clone syscall takes arguments in an architecture specific order. 296fe801747SSiva Chandra Reddy // Also, we want the result of the syscall to be in a register as the child 297fe801747SSiva Chandra Reddy // thread gets a completely different stack after it is created. The stack 298fe801747SSiva Chandra Reddy // variables from this function will not be availalbe to the child thread. 299cf90633cSSiva Chandra #if defined(LIBC_TARGET_ARCH_IS_X86_64) 300cf90633cSSiva Chandra long register clone_result asm(CLONE_RESULT_REGISTER); 301b6bc9d72SGuillaume Chatelet clone_result = LIBC_NAMESPACE::syscall_impl<long>( 302fe801747SSiva Chandra Reddy SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack, 303fe801747SSiva Chandra Reddy &attrib->tid, // The address where the child tid is written 304fe801747SSiva Chandra Reddy &clear_tid->val, // The futex where the child thread status is signalled 305859c1897SSiva Chandra Reddy tls.tp // The thread pointer value for the new thread. 306fe801747SSiva Chandra Reddy ); 307cf90633cSSiva Chandra #elif defined(LIBC_TARGET_ARCH_IS_AARCH64) || \ 308e3087c4bSMikhail R. Gadelha defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) 309cf90633cSSiva Chandra long register clone_result asm(CLONE_RESULT_REGISTER); 310b6bc9d72SGuillaume Chatelet clone_result = LIBC_NAMESPACE::syscall_impl<long>( 311fe801747SSiva Chandra Reddy SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack, 312fe801747SSiva Chandra Reddy &attrib->tid, // The address where the child tid is written 313859c1897SSiva Chandra Reddy tls.tp, // The thread pointer value for the new thread. 314fe801747SSiva Chandra Reddy &clear_tid->val // The futex where the child thread status is signalled 315fe801747SSiva Chandra Reddy ); 316fe801747SSiva Chandra Reddy #else 317fe801747SSiva Chandra Reddy #error "Unsupported architecture for the clone syscall." 318fe801747SSiva Chandra Reddy #endif 319fe801747SSiva Chandra Reddy 320fe801747SSiva Chandra Reddy if (clone_result == 0) { 321a2569a76SGuillaume Chatelet #ifdef LIBC_TARGET_ARCH_IS_AARCH64 322fe801747SSiva Chandra Reddy // We set the frame pointer to be the same as the "sp" so that start args 323fe801747SSiva Chandra Reddy // can be sniffed out from start_thread. 32478cd158cSDavid Spickett #ifdef __clang__ 32578cd158cSDavid Spickett // GCC does not currently implement __arm_wsr64/__arm_rsr64. 326fe801747SSiva Chandra Reddy __arm_wsr64("x29", __arm_rsr64("sp")); 32778cd158cSDavid Spickett #else 32878cd158cSDavid Spickett asm volatile("mov x29, sp"); 32978cd158cSDavid Spickett #endif 330c9783d2bSMikhail R. Gadelha #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) 331cf90633cSSiva Chandra asm volatile("mv fp, sp"); 332fe801747SSiva Chandra Reddy #endif 333fe801747SSiva Chandra Reddy start_thread(); 334fe801747SSiva Chandra Reddy } else if (clone_result < 0) { 335859c1897SSiva Chandra Reddy cleanup_thread_resources(attrib); 336f0a3954eSMichael Jones return static_cast<int>(-clone_result); 337fe801747SSiva Chandra Reddy } 338fe801747SSiva Chandra Reddy 339fe801747SSiva Chandra Reddy return 0; 340fe801747SSiva Chandra Reddy } 341fe801747SSiva Chandra Reddy 342fe801747SSiva Chandra Reddy int Thread::join(ThreadReturnValue &retval) { 343fe801747SSiva Chandra Reddy wait(); 344fe801747SSiva Chandra Reddy 345fe801747SSiva Chandra Reddy if (attrib->style == ThreadStyle::POSIX) 346fe801747SSiva Chandra Reddy retval.posix_retval = attrib->retval.posix_retval; 347fe801747SSiva Chandra Reddy else 348fe801747SSiva Chandra Reddy retval.stdc_retval = attrib->retval.stdc_retval; 349fe801747SSiva Chandra Reddy 350859c1897SSiva Chandra Reddy cleanup_thread_resources(attrib); 351fe801747SSiva Chandra Reddy 352fe801747SSiva Chandra Reddy return 0; 353fe801747SSiva Chandra Reddy } 354fe801747SSiva Chandra Reddy 355fe801747SSiva Chandra Reddy int Thread::detach() { 356fe801747SSiva Chandra Reddy uint32_t joinable_state = uint32_t(DetachState::JOINABLE); 357fe801747SSiva Chandra Reddy if (attrib->detach_state.compare_exchange_strong( 358fe801747SSiva Chandra Reddy joinable_state, uint32_t(DetachState::DETACHED))) { 359fe801747SSiva Chandra Reddy return int(DetachType::SIMPLE); 360fe801747SSiva Chandra Reddy } 361fe801747SSiva Chandra Reddy 362fe801747SSiva Chandra Reddy // If the thread was already detached, then the detach method should not 363fe801747SSiva Chandra Reddy // be called at all. If the thread is exiting, then we wait for it to exit 364fe801747SSiva Chandra Reddy // and free up resources. 365fe801747SSiva Chandra Reddy wait(); 366fe801747SSiva Chandra Reddy 367859c1897SSiva Chandra Reddy cleanup_thread_resources(attrib); 368859c1897SSiva Chandra Reddy 369fe801747SSiva Chandra Reddy return int(DetachType::CLEANUP); 370fe801747SSiva Chandra Reddy } 371fe801747SSiva Chandra Reddy 372fe801747SSiva Chandra Reddy void Thread::wait() { 373fe801747SSiva Chandra Reddy // The kernel should set the value at the clear tid address to zero. 374fe801747SSiva Chandra Reddy // If not, it is a spurious wake and we should continue to wait on 375fe801747SSiva Chandra Reddy // the futex. 376ab3a9e72SSchrodinger ZHU Yifan auto *clear_tid = reinterpret_cast<Futex *>(attrib->platform_data); 377fe801747SSiva Chandra Reddy // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a 378fe801747SSiva Chandra Reddy // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE. 379ab3a9e72SSchrodinger ZHU Yifan while (clear_tid->load() != 0) 380ab3a9e72SSchrodinger ZHU Yifan clear_tid->wait(CLEAR_TID_VALUE, cpp::nullopt, true); 381fe801747SSiva Chandra Reddy } 382fe801747SSiva Chandra Reddy 3838dc42802SSiva Chandra Reddy bool Thread::operator==(const Thread &thread) const { 3848dc42802SSiva Chandra Reddy return attrib->tid == thread.attrib->tid; 3858dc42802SSiva Chandra Reddy } 3868dc42802SSiva Chandra Reddy 387aa59c981SGuillaume Chatelet static constexpr cpp::string_view THREAD_NAME_PATH_PREFIX("/proc/self/task/"); 388658c84e4SSiva Chandra Reddy static constexpr size_t THREAD_NAME_PATH_SIZE = 389658c84e4SSiva Chandra Reddy THREAD_NAME_PATH_PREFIX.size() + 390b555912eSGuillaume Chatelet IntegerToString<int>::buffer_size() + // Size of tid 391658c84e4SSiva Chandra Reddy 1 + // For '/' character 392658c84e4SSiva Chandra Reddy 5; // For the file name "comm" and the nullterminator. 393658c84e4SSiva Chandra Reddy 394658c84e4SSiva Chandra Reddy static void construct_thread_name_file_path(cpp::StringStream &stream, 395658c84e4SSiva Chandra Reddy int tid) { 396aa59c981SGuillaume Chatelet stream << THREAD_NAME_PATH_PREFIX << tid << '/' << cpp::string_view("comm") 397658c84e4SSiva Chandra Reddy << cpp::StringStream::ENDS; 398658c84e4SSiva Chandra Reddy } 399658c84e4SSiva Chandra Reddy 400aa59c981SGuillaume Chatelet int Thread::set_name(const cpp::string_view &name) { 401658c84e4SSiva Chandra Reddy if (name.size() >= NAME_SIZE_MAX) 402658c84e4SSiva Chandra Reddy return ERANGE; 403658c84e4SSiva Chandra Reddy 404658c84e4SSiva Chandra Reddy if (*this == self) { 405658c84e4SSiva Chandra Reddy // If we are setting the name of the current thread, then we can 406658c84e4SSiva Chandra Reddy // use the syscall to set the name. 407f0a3954eSMichael Jones int retval = 408b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<int>(SYS_prctl, PR_SET_NAME, name.data()); 409658c84e4SSiva Chandra Reddy if (retval < 0) 410658c84e4SSiva Chandra Reddy return -retval; 411658c84e4SSiva Chandra Reddy else 412658c84e4SSiva Chandra Reddy return 0; 413658c84e4SSiva Chandra Reddy } 414658c84e4SSiva Chandra Reddy 415658c84e4SSiva Chandra Reddy char path_name_buffer[THREAD_NAME_PATH_SIZE]; 416658c84e4SSiva Chandra Reddy cpp::StringStream path_stream(path_name_buffer); 417658c84e4SSiva Chandra Reddy construct_thread_name_file_path(path_stream, attrib->tid); 418658c84e4SSiva Chandra Reddy #ifdef SYS_open 419b6bc9d72SGuillaume Chatelet int fd = 420b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<int>(SYS_open, path_name_buffer, O_RDWR); 421658c84e4SSiva Chandra Reddy #else 422b6bc9d72SGuillaume Chatelet int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, 423f0a3954eSMichael Jones path_name_buffer, O_RDWR); 424658c84e4SSiva Chandra Reddy #endif 425658c84e4SSiva Chandra Reddy if (fd < 0) 426658c84e4SSiva Chandra Reddy return -fd; 427658c84e4SSiva Chandra Reddy 428b6bc9d72SGuillaume Chatelet int retval = LIBC_NAMESPACE::syscall_impl<int>(SYS_write, fd, name.data(), 429b6bc9d72SGuillaume Chatelet name.size()); 430b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_close, fd); 431658c84e4SSiva Chandra Reddy 432658c84e4SSiva Chandra Reddy if (retval < 0) 433658c84e4SSiva Chandra Reddy return -retval; 434658c84e4SSiva Chandra Reddy else if (retval != int(name.size())) 435658c84e4SSiva Chandra Reddy return EIO; 436658c84e4SSiva Chandra Reddy else 437658c84e4SSiva Chandra Reddy return 0; 438658c84e4SSiva Chandra Reddy } 439658c84e4SSiva Chandra Reddy 440658c84e4SSiva Chandra Reddy int Thread::get_name(cpp::StringStream &name) const { 441658c84e4SSiva Chandra Reddy if (name.bufsize() < NAME_SIZE_MAX) 442658c84e4SSiva Chandra Reddy return ERANGE; 443658c84e4SSiva Chandra Reddy 444658c84e4SSiva Chandra Reddy char name_buffer[NAME_SIZE_MAX]; 445658c84e4SSiva Chandra Reddy 446658c84e4SSiva Chandra Reddy if (*this == self) { 447658c84e4SSiva Chandra Reddy // If we are getting the name of the current thread, then we can 448658c84e4SSiva Chandra Reddy // use the syscall to get the name. 449f0a3954eSMichael Jones int retval = 450b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<int>(SYS_prctl, PR_GET_NAME, name_buffer); 451658c84e4SSiva Chandra Reddy if (retval < 0) 452658c84e4SSiva Chandra Reddy return -retval; 453596d87c4SSiva Chandra Reddy name << name_buffer << cpp::StringStream::ENDS; 454658c84e4SSiva Chandra Reddy return 0; 455658c84e4SSiva Chandra Reddy } 456658c84e4SSiva Chandra Reddy 457658c84e4SSiva Chandra Reddy char path_name_buffer[THREAD_NAME_PATH_SIZE]; 458658c84e4SSiva Chandra Reddy cpp::StringStream path_stream(path_name_buffer); 459658c84e4SSiva Chandra Reddy construct_thread_name_file_path(path_stream, attrib->tid); 460658c84e4SSiva Chandra Reddy #ifdef SYS_open 461b6bc9d72SGuillaume Chatelet int fd = 462b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<int>(SYS_open, path_name_buffer, O_RDONLY); 463658c84e4SSiva Chandra Reddy #else 464b6bc9d72SGuillaume Chatelet int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, 465f0a3954eSMichael Jones path_name_buffer, O_RDONLY); 466658c84e4SSiva Chandra Reddy #endif 467658c84e4SSiva Chandra Reddy if (fd < 0) 468658c84e4SSiva Chandra Reddy return -fd; 469658c84e4SSiva Chandra Reddy 470b6bc9d72SGuillaume Chatelet int retval = LIBC_NAMESPACE::syscall_impl<int>(SYS_read, fd, name_buffer, 471b6bc9d72SGuillaume Chatelet NAME_SIZE_MAX); 472b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_close, fd); 473658c84e4SSiva Chandra Reddy if (retval < 0) 474658c84e4SSiva Chandra Reddy return -retval; 475658c84e4SSiva Chandra Reddy if (retval == NAME_SIZE_MAX) 476658c84e4SSiva Chandra Reddy return ERANGE; 477658c84e4SSiva Chandra Reddy if (name_buffer[retval - 1] == '\n') 478658c84e4SSiva Chandra Reddy name_buffer[retval - 1] = '\0'; 479658c84e4SSiva Chandra Reddy else 480658c84e4SSiva Chandra Reddy name_buffer[retval] = '\0'; 4818972c0dfSSiva Chandra Reddy name << name_buffer << cpp::StringStream::ENDS; 482658c84e4SSiva Chandra Reddy return 0; 483658c84e4SSiva Chandra Reddy } 484658c84e4SSiva Chandra Reddy 4850071a795SSiva Chandra Reddy void thread_exit(ThreadReturnValue retval, ThreadStyle style) { 4860071a795SSiva Chandra Reddy auto attrib = self.attrib; 4870071a795SSiva Chandra Reddy 4880071a795SSiva Chandra Reddy // The very first thing we do is to call the thread's atexit callbacks. 4890071a795SSiva Chandra Reddy // These callbacks could be the ones registered by the language runtimes, 4900071a795SSiva Chandra Reddy // for example, the destructors of thread local objects. They can also 4910071a795SSiva Chandra Reddy // be destructors of the TSS objects set using API like pthread_setspecific. 4920071a795SSiva Chandra Reddy // NOTE: We cannot call the atexit callbacks as part of the 4930071a795SSiva Chandra Reddy // cleanup_thread_resources function as that function can be called from a 4940071a795SSiva Chandra Reddy // different thread. The destructors of thread local and TSS objects should 4950071a795SSiva Chandra Reddy // be called by the thread which owns them. 4960071a795SSiva Chandra Reddy internal::call_atexit_callbacks(attrib); 4970071a795SSiva Chandra Reddy 4980071a795SSiva Chandra Reddy uint32_t joinable_state = uint32_t(DetachState::JOINABLE); 4990071a795SSiva Chandra Reddy if (!attrib->detach_state.compare_exchange_strong( 5000071a795SSiva Chandra Reddy joinable_state, uint32_t(DetachState::EXITING))) { 5010071a795SSiva Chandra Reddy // Thread is detached so cleanup the resources. 5020071a795SSiva Chandra Reddy cleanup_thread_resources(attrib); 5030071a795SSiva Chandra Reddy 5040071a795SSiva Chandra Reddy // Set the CLEAR_TID address to nullptr to prevent the kernel 5050071a795SSiva Chandra Reddy // from signalling at a non-existent futex location. 506b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_set_tid_address, 0); 507916e9be4SNoah Goldstein // Return value for detached thread should be unused. We need to avoid 508916e9be4SNoah Goldstein // referencing `style` or `retval.*` because they may be stored on the stack 509916e9be4SNoah Goldstein // and we have deallocated our stack! 510b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 0); 511916e9be4SNoah Goldstein __builtin_unreachable(); 5120071a795SSiva Chandra Reddy } 5130071a795SSiva Chandra Reddy 5140071a795SSiva Chandra Reddy if (style == ThreadStyle::POSIX) 515b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, retval.posix_retval); 5160071a795SSiva Chandra Reddy else 517b6bc9d72SGuillaume Chatelet LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, retval.stdc_retval); 518916e9be4SNoah Goldstein __builtin_unreachable(); 5190071a795SSiva Chandra Reddy } 5200071a795SSiva Chandra Reddy 5215ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 522