diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -213,6 +213,24 @@ libc.src.sys.mman.munmap ) +if(LLVM_LIBC_FULL_BUILD) + list(APPEND TARGET_LIBC_ENTRYPOINTS + # threads.h entrypoints + libc.src.threads.call_once + libc.src.threads.cnd_broadcast + libc.src.threads.cnd_destroy + libc.src.threads.cnd_init + libc.src.threads.cnd_signal + libc.src.threads.cnd_wait + libc.src.threads.mtx_destroy + libc.src.threads.mtx_init + libc.src.threads.mtx_lock + libc.src.threads.mtx_unlock + libc.src.threads.thrd_create + libc.src.threads.thrd_join + ) +endif() + set(TARGET_LLVMLIBC_ENTRYPOINTS ${TARGET_LIBC_ENTRYPOINTS} ${TARGET_LIBM_ENTRYPOINTS} diff --git a/libc/src/threads/linux/CMakeLists.txt b/libc/src/threads/linux/CMakeLists.txt --- a/libc/src/threads/linux/CMakeLists.txt +++ b/libc/src/threads/linux/CMakeLists.txt @@ -1,13 +1,3 @@ -add_gen_header( - thread_start_args_h - DEF_FILE thread_start_args.h.def - GEN_HDR thread_start_args.h - PARAMS - thread_start_args=${LIBC_TARGET_ARCHITECTURE}/thread_start_args.h.in - DATA_FILES - ${LIBC_TARGET_ARCHITECTURE}/thread_start_args.h.in -) - add_entrypoint_object( call_once SRCS @@ -29,7 +19,6 @@ Futex.h Thread.h DEPENDS - .thread_start_args_h libc.include.sys_syscall libc.include.threads libc.src.__support.CPP.atomic diff --git a/libc/src/threads/linux/Thread.h b/libc/src/threads/linux/Thread.h --- a/libc/src/threads/linux/Thread.h +++ b/libc/src/threads/linux/Thread.h @@ -9,8 +9,6 @@ #ifndef LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H #define LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H -#include "thread_start_args.h" - #include namespace __llvm_libc { diff --git a/libc/src/threads/linux/thrd_create.cpp b/libc/src/threads/linux/thrd_create.cpp --- a/libc/src/threads/linux/thrd_create.cpp +++ b/libc/src/threads/linux/thrd_create.cpp @@ -13,6 +13,7 @@ #include "include/sys/syscall.h" // For syscall numbers. #include "include/threads.h" // For thrd_* type definitions. #include "src/__support/OSUtil/syscall.h" // For syscall function. +#include "src/__support/architectures.h" #include "src/__support/common.h" #include "src/errno/llvmlibc_errno.h" #include "src/sys/mman/mmap.h" @@ -25,12 +26,31 @@ namespace __llvm_libc { -struct StartArgs { +// 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. +struct alignas(16) StartArgs { thrd_t *thread; thrd_start_t func; void *arg; }; +__attribute__((always_inline)) inline uintptr_t get_start_args_addr() { + // NOTE: For __builtin_frame_address to work reliably across compilers, + // architectures and various optimization levels, the TU including this file + // should be compiled with -fno-omit-frame-pointer. + return reinterpret_cast(__builtin_frame_address(0)) + // The x86_64 call instruction pushes resume address on to the stack. + // Next, The x86_64 SysV ABI requires that the frame pointer be pushed + // on to the stack. Similarly on aarch64, previous frame pointer and + // the value of the link register are pushed on to the stack. So, in + // both these cases, we have to step past two 64-bit values to get + // to the start args. + + sizeof(uintptr_t) * 2; +} + static __attribute__((noinline)) void start_thread() { StartArgs *start_args = reinterpret_cast(get_start_args_addr()); __llvm_libc::syscall(SYS_exit, start_args->thread->__retval = @@ -79,13 +99,29 @@ start_args->func = func; start_args->arg = arg; - // TODO: The arguments to the clone syscall below is correct for x86_64 - // but it might differ for other architectures. So, make this call - // architecture independent. May be implement a glibc like wrapper for clone - // and use it here. + // The clone syscall takes arguments in an architecture specific order. + // Also, we want the result of the syscall to be in a register as the child + // thread gets a completely different stack after it is created. The stack + // variables from this function will not be availalbe to the child thread. +#ifdef LLVM_LIBC_ARCH_X86_64 long register clone_result asm("rax"); - clone_result = __llvm_libc::syscall(SYS_clone, clone_flags, adjusted_stack, - &thread->__tid, clear_tid_address, 0); + clone_result = __llvm_libc::syscall( + SYS_clone, clone_flags, adjusted_stack, + &thread->__tid, // The address where the child tid is written + clear_tid_address, // The futex where the child thread status is signalled + 0 // Set TLS to null for now. + ); +#elif defined(LLVM_LIBC_ARCH_AARCH64) + long register clone_result asm("x0"); + clone_result = __llvm_libc::syscall( + SYS_clone, clone_flags, adjusted_stack, + &thread->__tid, // The address where the child tid is written + 0, // Set TLS to null for now. + clear_tid_address // The futex where the child thread status is signalled + ); +#else +#error "Unsupported architecture for the clone syscall." +#endif if (clone_result == 0) { start_thread(); diff --git a/libc/src/threads/linux/x86_64/thread_start_args.h.in b/libc/src/threads/linux/x86_64/thread_start_args.h.in deleted file mode 100644 --- a/libc/src/threads/linux/x86_64/thread_start_args.h.in +++ /dev/null @@ -1,24 +0,0 @@ -//===- x86_64 implementation of the get_start_args_addr function -*- C++ -*===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -%%begin() - -namespace __llvm_libc { - -__attribute__((always_inline)) inline uintptr_t get_start_args_addr() { - // NOTE: For __builtin_frame_address to work reliably across compilers, - // architectures and various optimization levels, the TU including this file - // should be compiled with -fno-omit-frame-pointer. - return reinterpret_cast(__builtin_frame_address(0)) + - // The x86_64 call instruction pushes resume address on to the stack. - // Next, The x86_64 SysV ABI also pushes the frame pointer on the - // stack. Hence, we look past these items to get to the start args. - sizeof(uintptr_t) * 2; -} - -} // namespace __llvm_libc