1*fe801747SSiva Chandra Reddy //===--- Implementation of a Linux thread class -----------------*- C++ -*-===// 2*fe801747SSiva Chandra Reddy // 3*fe801747SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*fe801747SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 5*fe801747SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*fe801747SSiva Chandra Reddy // 7*fe801747SSiva Chandra Reddy //===----------------------------------------------------------------------===// 8*fe801747SSiva Chandra Reddy 9*fe801747SSiva Chandra Reddy #include "src/__support/threads/thread.h" 10*fe801747SSiva Chandra Reddy #include "src/__support/CPP/atomic.h" 11*fe801747SSiva Chandra Reddy #include "src/__support/CPP/error.h" 12*fe801747SSiva Chandra Reddy #include "src/__support/OSUtil/syscall.h" // For syscall functions. 13*fe801747SSiva Chandra Reddy #include "src/__support/threads/linux/futex_word.h" // For FutexWordType 14*fe801747SSiva Chandra Reddy 15*fe801747SSiva Chandra Reddy #ifdef LLVM_LIBC_ARCH_AARCH64 16*fe801747SSiva Chandra Reddy #include <arm_acle.h> 17*fe801747SSiva Chandra Reddy #endif 18*fe801747SSiva Chandra Reddy 19*fe801747SSiva Chandra Reddy #include <linux/futex.h> 20*fe801747SSiva Chandra Reddy #include <linux/sched.h> // For CLONE_* flags. 21*fe801747SSiva Chandra Reddy #include <stdint.h> 22*fe801747SSiva Chandra Reddy #include <sys/mman.h> // For PROT_* and MAP_* definitions. 23*fe801747SSiva Chandra Reddy #include <sys/syscall.h> // For syscall numbers. 24*fe801747SSiva Chandra Reddy 25*fe801747SSiva Chandra Reddy namespace __llvm_libc { 26*fe801747SSiva Chandra Reddy 27*fe801747SSiva Chandra Reddy #ifdef SYS_mmap2 28*fe801747SSiva Chandra Reddy static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2; 29*fe801747SSiva Chandra Reddy #elif SYS_mmap 30*fe801747SSiva Chandra Reddy static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap; 31*fe801747SSiva Chandra Reddy #else 32*fe801747SSiva Chandra Reddy #error "SYS_mmap or SYS_mmap2 not available on the target platform" 33*fe801747SSiva Chandra Reddy #endif 34*fe801747SSiva Chandra Reddy 35*fe801747SSiva Chandra Reddy static constexpr size_t DEFAULT_STACK_SIZE = (1 << 16); // 64KB 36*fe801747SSiva Chandra Reddy static constexpr uint32_t CLEAR_TID_VALUE = 0xABCD1234; 37*fe801747SSiva Chandra Reddy static constexpr unsigned CLONE_SYSCALL_FLAGS = 38*fe801747SSiva Chandra Reddy CLONE_VM // Share the memory space with the parent. 39*fe801747SSiva Chandra Reddy | CLONE_FS // Share the file system with the parent. 40*fe801747SSiva Chandra Reddy | CLONE_FILES // Share the files with the parent. 41*fe801747SSiva Chandra Reddy | CLONE_SIGHAND // Share the signal handlers with the parent. 42*fe801747SSiva Chandra Reddy | CLONE_THREAD // Same thread group as the parent. 43*fe801747SSiva Chandra Reddy | CLONE_SYSVSEM // Share a single list of System V semaphore adjustment 44*fe801747SSiva Chandra Reddy // values 45*fe801747SSiva Chandra Reddy | CLONE_PARENT_SETTID // Set child thread ID in |ptid| of the parent. 46*fe801747SSiva Chandra Reddy | CLONE_CHILD_CLEARTID; // Let the kernel clear the tid address 47*fe801747SSiva Chandra Reddy // wake the joining thread. 48*fe801747SSiva Chandra Reddy // TODO: Add the CLONE_SETTLS flag and setup the TLS area correctly 49*fe801747SSiva Chandra Reddy // when making the clone syscall. 50*fe801747SSiva Chandra Reddy 51*fe801747SSiva Chandra Reddy static inline cpp::ErrorOr<void *> alloc_stack(size_t size) { 52*fe801747SSiva Chandra Reddy long mmap_result = 53*fe801747SSiva Chandra Reddy __llvm_libc::syscall(MMAP_SYSCALL_NUMBER, 54*fe801747SSiva Chandra Reddy 0, // No special address 55*fe801747SSiva Chandra Reddy size, 56*fe801747SSiva Chandra Reddy PROT_READ | PROT_WRITE, // Read and write stack 57*fe801747SSiva Chandra Reddy MAP_ANONYMOUS | MAP_PRIVATE, // Process private 58*fe801747SSiva Chandra Reddy -1, // Not backed by any file 59*fe801747SSiva Chandra Reddy 0 // No offset 60*fe801747SSiva Chandra Reddy ); 61*fe801747SSiva Chandra Reddy if (mmap_result < 0 && (uintptr_t(mmap_result) >= UINTPTR_MAX - size)) 62*fe801747SSiva Chandra Reddy return cpp::Error{int(-mmap_result)}; 63*fe801747SSiva Chandra Reddy return reinterpret_cast<void *>(mmap_result); 64*fe801747SSiva Chandra Reddy } 65*fe801747SSiva Chandra Reddy 66*fe801747SSiva Chandra Reddy static inline void free_stack(void *stack, size_t size) { 67*fe801747SSiva Chandra Reddy __llvm_libc::syscall(SYS_munmap, stack, size); 68*fe801747SSiva Chandra Reddy } 69*fe801747SSiva Chandra Reddy 70*fe801747SSiva Chandra Reddy struct Thread; 71*fe801747SSiva Chandra Reddy 72*fe801747SSiva Chandra Reddy // We align the start args to 16-byte boundary as we adjust the allocated 73*fe801747SSiva Chandra Reddy // stack memory with its size. We want the adjusted address to be at a 74*fe801747SSiva Chandra Reddy // 16-byte boundary to satisfy the x86_64 and aarch64 ABI requirements. 75*fe801747SSiva Chandra Reddy // If different architecture in future requires higher alignment, then we 76*fe801747SSiva Chandra Reddy // can add a platform specific alignment spec. 77*fe801747SSiva Chandra Reddy struct alignas(STACK_ALIGNMENT) StartArgs { 78*fe801747SSiva Chandra Reddy Thread *thread; 79*fe801747SSiva Chandra Reddy ThreadRunner runner; 80*fe801747SSiva Chandra Reddy void *arg; 81*fe801747SSiva Chandra Reddy }; 82*fe801747SSiva Chandra Reddy 83*fe801747SSiva Chandra Reddy __attribute__((always_inline)) inline uintptr_t get_start_args_addr() { 84*fe801747SSiva Chandra Reddy // NOTE: For __builtin_frame_address to work reliably across compilers, 85*fe801747SSiva Chandra Reddy // architectures and various optimization levels, the TU including this file 86*fe801747SSiva Chandra Reddy // should be compiled with -fno-omit-frame-pointer. 87*fe801747SSiva Chandra Reddy #ifdef LLVM_LIBC_ARCH_X86_64 88*fe801747SSiva Chandra Reddy return reinterpret_cast<uintptr_t>(__builtin_frame_address(0)) 89*fe801747SSiva Chandra Reddy // The x86_64 call instruction pushes resume address on to the stack. 90*fe801747SSiva Chandra Reddy // Next, The x86_64 SysV ABI requires that the frame pointer be pushed 91*fe801747SSiva Chandra Reddy // on to the stack. So, we have to step past two 64-bit values to get 92*fe801747SSiva Chandra Reddy // to the start args. 93*fe801747SSiva Chandra Reddy + sizeof(uintptr_t) * 2; 94*fe801747SSiva Chandra Reddy #elif defined(LLVM_LIBC_ARCH_AARCH64) 95*fe801747SSiva Chandra Reddy // The frame pointer after cloning the new thread in the Thread::run method 96*fe801747SSiva Chandra Reddy // is set to the stack pointer where start args are stored. So, we fetch 97*fe801747SSiva Chandra Reddy // from there. 98*fe801747SSiva Chandra Reddy return reinterpret_cast<uintptr_t>(__builtin_frame_address(1)); 99*fe801747SSiva Chandra Reddy #endif 100*fe801747SSiva Chandra Reddy } 101*fe801747SSiva Chandra Reddy 102*fe801747SSiva Chandra Reddy static void start_thread() __attribute__((noinline)) { 103*fe801747SSiva Chandra Reddy auto *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr()); 104*fe801747SSiva Chandra Reddy auto *thread = start_args->thread; 105*fe801747SSiva Chandra Reddy auto *attrib = thread->attrib; 106*fe801747SSiva Chandra Reddy long retval; 107*fe801747SSiva Chandra Reddy if (attrib->style == ThreadStyle::POSIX) { 108*fe801747SSiva Chandra Reddy attrib->retval.posix_retval = 109*fe801747SSiva Chandra Reddy start_args->runner.posix_runner(start_args->arg); 110*fe801747SSiva Chandra Reddy retval = long(attrib->retval.posix_retval); 111*fe801747SSiva Chandra Reddy } else { 112*fe801747SSiva Chandra Reddy attrib->retval.stdc_retval = 113*fe801747SSiva Chandra Reddy start_args->runner.stdc_runner(start_args->arg); 114*fe801747SSiva Chandra Reddy retval = long(attrib->retval.stdc_retval); 115*fe801747SSiva Chandra Reddy } 116*fe801747SSiva Chandra Reddy 117*fe801747SSiva Chandra Reddy uint32_t joinable_state = uint32_t(DetachState::JOINABLE); 118*fe801747SSiva Chandra Reddy if (!thread->attrib->detach_state.compare_exchange_strong( 119*fe801747SSiva Chandra Reddy joinable_state, uint32_t(DetachState::EXITING))) { 120*fe801747SSiva Chandra Reddy // Thread is detached so cleanup the resources. 121*fe801747SSiva Chandra Reddy if (thread->attrib->owned_stack) 122*fe801747SSiva Chandra Reddy free_stack(thread->attrib->stack, thread->attrib->stack_size); 123*fe801747SSiva Chandra Reddy } 124*fe801747SSiva Chandra Reddy 125*fe801747SSiva Chandra Reddy __llvm_libc::syscall(SYS_exit, retval); 126*fe801747SSiva Chandra Reddy } 127*fe801747SSiva Chandra Reddy 128*fe801747SSiva Chandra Reddy int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, 129*fe801747SSiva Chandra Reddy size_t size, bool detached) { 130*fe801747SSiva Chandra Reddy bool owned_stack = false; 131*fe801747SSiva Chandra Reddy if (stack == nullptr) { 132*fe801747SSiva Chandra Reddy if (size == 0) 133*fe801747SSiva Chandra Reddy size = DEFAULT_STACK_SIZE; 134*fe801747SSiva Chandra Reddy auto alloc = alloc_stack(size); 135*fe801747SSiva Chandra Reddy if (!alloc) 136*fe801747SSiva Chandra Reddy return alloc.error_code(); 137*fe801747SSiva Chandra Reddy else 138*fe801747SSiva Chandra Reddy stack = alloc.value(); 139*fe801747SSiva Chandra Reddy owned_stack = true; 140*fe801747SSiva Chandra Reddy } 141*fe801747SSiva Chandra Reddy 142*fe801747SSiva Chandra Reddy // When the new thread is spawned by the kernel, the new thread gets the 143*fe801747SSiva Chandra Reddy // stack we pass to the clone syscall. However, this stack is empty and does 144*fe801747SSiva Chandra Reddy // not have any local vars present in this function. Hence, one cannot 145*fe801747SSiva Chandra Reddy // pass arguments to the thread start function, or use any local vars from 146*fe801747SSiva Chandra Reddy // here. So, we pack them into the new stack from where the thread can sniff 147*fe801747SSiva Chandra Reddy // them out. 148*fe801747SSiva Chandra Reddy // 149*fe801747SSiva Chandra Reddy // Likewise, the actual thread state information is also stored on the 150*fe801747SSiva Chandra Reddy // stack memory. 151*fe801747SSiva Chandra Reddy uintptr_t adjusted_stack = reinterpret_cast<uintptr_t>(stack) + size - 152*fe801747SSiva Chandra Reddy sizeof(StartArgs) - sizeof(ThreadAttributes) - 153*fe801747SSiva Chandra Reddy sizeof(cpp::Atomic<FutexWordType>); 154*fe801747SSiva Chandra Reddy adjusted_stack &= ~(uintptr_t(STACK_ALIGNMENT) - 1); 155*fe801747SSiva Chandra Reddy 156*fe801747SSiva Chandra Reddy auto *start_args = reinterpret_cast<StartArgs *>(adjusted_stack); 157*fe801747SSiva Chandra Reddy start_args->thread = this; 158*fe801747SSiva Chandra Reddy start_args->runner = runner; 159*fe801747SSiva Chandra Reddy start_args->arg = arg; 160*fe801747SSiva Chandra Reddy 161*fe801747SSiva Chandra Reddy attrib = 162*fe801747SSiva Chandra Reddy reinterpret_cast<ThreadAttributes *>(adjusted_stack + sizeof(StartArgs)); 163*fe801747SSiva Chandra Reddy attrib->style = style; 164*fe801747SSiva Chandra Reddy attrib->detach_state = 165*fe801747SSiva Chandra Reddy uint32_t(detached ? DetachState::DETACHED : DetachState::JOINABLE); 166*fe801747SSiva Chandra Reddy attrib->stack = stack; 167*fe801747SSiva Chandra Reddy attrib->stack_size = size; 168*fe801747SSiva Chandra Reddy attrib->owned_stack = owned_stack; 169*fe801747SSiva Chandra Reddy 170*fe801747SSiva Chandra Reddy auto clear_tid = reinterpret_cast<cpp::Atomic<FutexWordType> *>( 171*fe801747SSiva Chandra Reddy adjusted_stack + sizeof(StartArgs) + sizeof(ThreadAttributes)); 172*fe801747SSiva Chandra Reddy clear_tid->val = CLEAR_TID_VALUE; 173*fe801747SSiva Chandra Reddy platform_data = clear_tid; 174*fe801747SSiva Chandra Reddy 175*fe801747SSiva Chandra Reddy // The clone syscall takes arguments in an architecture specific order. 176*fe801747SSiva Chandra Reddy // Also, we want the result of the syscall to be in a register as the child 177*fe801747SSiva Chandra Reddy // thread gets a completely different stack after it is created. The stack 178*fe801747SSiva Chandra Reddy // variables from this function will not be availalbe to the child thread. 179*fe801747SSiva Chandra Reddy #ifdef LLVM_LIBC_ARCH_X86_64 180*fe801747SSiva Chandra Reddy long register clone_result asm("rax"); 181*fe801747SSiva Chandra Reddy clone_result = __llvm_libc::syscall( 182*fe801747SSiva Chandra Reddy SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack, 183*fe801747SSiva Chandra Reddy &attrib->tid, // The address where the child tid is written 184*fe801747SSiva Chandra Reddy &clear_tid->val, // The futex where the child thread status is signalled 185*fe801747SSiva Chandra Reddy 0 // Set TLS to null for now. 186*fe801747SSiva Chandra Reddy ); 187*fe801747SSiva Chandra Reddy #elif defined(LLVM_LIBC_ARCH_AARCH64) 188*fe801747SSiva Chandra Reddy long register clone_result asm("x0"); 189*fe801747SSiva Chandra Reddy clone_result = __llvm_libc::syscall( 190*fe801747SSiva Chandra Reddy SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack, 191*fe801747SSiva Chandra Reddy &attrib->tid, // The address where the child tid is written 192*fe801747SSiva Chandra Reddy 0, // Set TLS to null for now. 193*fe801747SSiva Chandra Reddy &clear_tid->val // The futex where the child thread status is signalled 194*fe801747SSiva Chandra Reddy ); 195*fe801747SSiva Chandra Reddy #else 196*fe801747SSiva Chandra Reddy #error "Unsupported architecture for the clone syscall." 197*fe801747SSiva Chandra Reddy #endif 198*fe801747SSiva Chandra Reddy 199*fe801747SSiva Chandra Reddy if (clone_result == 0) { 200*fe801747SSiva Chandra Reddy #ifdef LLVM_LIBC_ARCH_AARCH64 201*fe801747SSiva Chandra Reddy // We set the frame pointer to be the same as the "sp" so that start args 202*fe801747SSiva Chandra Reddy // can be sniffed out from start_thread. 203*fe801747SSiva Chandra Reddy __arm_wsr64("x29", __arm_rsr64("sp")); 204*fe801747SSiva Chandra Reddy #endif 205*fe801747SSiva Chandra Reddy start_thread(); 206*fe801747SSiva Chandra Reddy } else if (clone_result < 0) { 207*fe801747SSiva Chandra Reddy if (attrib->owned_stack) 208*fe801747SSiva Chandra Reddy free_stack(attrib->stack, attrib->stack_size); 209*fe801747SSiva Chandra Reddy return -clone_result; 210*fe801747SSiva Chandra Reddy } 211*fe801747SSiva Chandra Reddy 212*fe801747SSiva Chandra Reddy return 0; 213*fe801747SSiva Chandra Reddy } 214*fe801747SSiva Chandra Reddy 215*fe801747SSiva Chandra Reddy int Thread::join(ThreadReturnValue &retval) { 216*fe801747SSiva Chandra Reddy wait(); 217*fe801747SSiva Chandra Reddy 218*fe801747SSiva Chandra Reddy if (attrib->style == ThreadStyle::POSIX) 219*fe801747SSiva Chandra Reddy retval.posix_retval = attrib->retval.posix_retval; 220*fe801747SSiva Chandra Reddy else 221*fe801747SSiva Chandra Reddy retval.stdc_retval = attrib->retval.stdc_retval; 222*fe801747SSiva Chandra Reddy 223*fe801747SSiva Chandra Reddy if (attrib->owned_stack) 224*fe801747SSiva Chandra Reddy free_stack(attrib->stack, attrib->stack_size); 225*fe801747SSiva Chandra Reddy 226*fe801747SSiva Chandra Reddy return 0; 227*fe801747SSiva Chandra Reddy } 228*fe801747SSiva Chandra Reddy 229*fe801747SSiva Chandra Reddy int Thread::detach() { 230*fe801747SSiva Chandra Reddy uint32_t joinable_state = uint32_t(DetachState::JOINABLE); 231*fe801747SSiva Chandra Reddy if (attrib->detach_state.compare_exchange_strong( 232*fe801747SSiva Chandra Reddy joinable_state, uint32_t(DetachState::DETACHED))) { 233*fe801747SSiva Chandra Reddy return int(DetachType::SIMPLE); 234*fe801747SSiva Chandra Reddy } 235*fe801747SSiva Chandra Reddy 236*fe801747SSiva Chandra Reddy // If the thread was already detached, then the detach method should not 237*fe801747SSiva Chandra Reddy // be called at all. If the thread is exiting, then we wait for it to exit 238*fe801747SSiva Chandra Reddy // and free up resources. 239*fe801747SSiva Chandra Reddy wait(); 240*fe801747SSiva Chandra Reddy 241*fe801747SSiva Chandra Reddy if (attrib->owned_stack) 242*fe801747SSiva Chandra Reddy free_stack(attrib->stack, attrib->stack_size); 243*fe801747SSiva Chandra Reddy return int(DetachType::CLEANUP); 244*fe801747SSiva Chandra Reddy } 245*fe801747SSiva Chandra Reddy 246*fe801747SSiva Chandra Reddy void Thread::wait() { 247*fe801747SSiva Chandra Reddy // The kernel should set the value at the clear tid address to zero. 248*fe801747SSiva Chandra Reddy // If not, it is a spurious wake and we should continue to wait on 249*fe801747SSiva Chandra Reddy // the futex. 250*fe801747SSiva Chandra Reddy auto *clear_tid = 251*fe801747SSiva Chandra Reddy reinterpret_cast<cpp::Atomic<FutexWordType> *>(platform_data); 252*fe801747SSiva Chandra Reddy while (clear_tid->load() != 0) { 253*fe801747SSiva Chandra Reddy // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a 254*fe801747SSiva Chandra Reddy // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE. 255*fe801747SSiva Chandra Reddy __llvm_libc::syscall(SYS_futex, &clear_tid->val, FUTEX_WAIT, 256*fe801747SSiva Chandra Reddy CLEAR_TID_VALUE, nullptr); 257*fe801747SSiva Chandra Reddy } 258*fe801747SSiva Chandra Reddy } 259*fe801747SSiva Chandra Reddy 260*fe801747SSiva Chandra Reddy } // namespace __llvm_libc 261