xref: /llvm-project/libc/src/__support/threads/linux/thread.cpp (revision abc49cc19463970d5523d7d3332e4c1f83bc2ef7)
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