diff options
| author | Siva Chandra Reddy <sivachandra@google.com> | 2022-04-01 06:42:14 +0000 |
|---|---|---|
| committer | Siva Chandra Reddy <sivachandra@google.com> | 2022-04-07 16:13:21 +0000 |
| commit | 2ce09e680a7dc1201463ae74e199eac66ac52a8d (patch) | |
| tree | 4b14f88eb781045a5141c6c1fb51933bfe9f78f9 /libc/src/threads | |
| parent | 0a77e633226b5598e426603c03e54d62ed275670 (diff) | |
[libc] Add a linux Thread class in __support/threads.
This change is essentially a mechanical change which moves the thread
creation and join implementations from src/threads/linux to
src/__support/threads/linux/thread.h. The idea being that, in future, a
pthread implementation can reuse the common thread implementations in
src/__support/threads.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D123287
Diffstat (limited to 'libc/src/threads')
| -rw-r--r-- | libc/src/threads/CMakeLists.txt | 20 | ||||
| -rw-r--r-- | libc/src/threads/linux/CMakeLists.txt | 37 | ||||
| -rw-r--r-- | libc/src/threads/linux/CndVar.h | 3 | ||||
| -rw-r--r-- | libc/src/threads/linux/Thread.h | 23 | ||||
| -rw-r--r-- | libc/src/threads/linux/thrd_create.cpp | 153 | ||||
| -rw-r--r-- | libc/src/threads/linux/thrd_join.cpp | 46 | ||||
| -rw-r--r-- | libc/src/threads/thrd_create.cpp | 33 | ||||
| -rw-r--r-- | libc/src/threads/thrd_create.h | 2 | ||||
| -rw-r--r-- | libc/src/threads/thrd_join.cpp | 30 |
9 files changed, 83 insertions, 264 deletions
diff --git a/libc/src/threads/CMakeLists.txt b/libc/src/threads/CMakeLists.txt index a02fc161ecc5..bd63a53061f3 100644 --- a/libc/src/threads/CMakeLists.txt +++ b/libc/src/threads/CMakeLists.txt @@ -11,16 +11,28 @@ add_entrypoint_object( add_entrypoint_object( thrd_create - ALIAS + SRCS + thrd_create.cpp + HDRS + thrd_create.h DEPENDS - .${LIBC_TARGET_OS}.thrd_create + libc.src.__support.threads.thread + libc.include.threads + COMPILE_OPTIONS + -O3 + -fno-omit-frame-pointer # This allows us to sniff out the thread args from + # the new thread's stack reliably. ) add_entrypoint_object( thrd_join - ALIAS + SRCS + thrd_join.cpp + HDRS + thrd_join.h DEPENDS - .${LIBC_TARGET_OS}.thrd_join + libc.include.threads + libc.src.__support.threads.thread ) add_entrypoint_object( diff --git a/libc/src/threads/linux/CMakeLists.txt b/libc/src/threads/linux/CMakeLists.txt index 0abdf5d23363..339c2b5dc3d5 100644 --- a/libc/src/threads/linux/CMakeLists.txt +++ b/libc/src/threads/linux/CMakeLists.txt @@ -17,48 +17,13 @@ add_header_library( HDRS CndVar.h Futex.h - Thread.h DEPENDS libc.include.sys_syscall libc.include.threads libc.src.__support.CPP.atomic libc.src.__support.OSUtil.osutil libc.src.__support.threads.mutex -) - -add_entrypoint_object( - thrd_create - SRCS - thrd_create.cpp - HDRS - ../thrd_create.h - DEPENDS - .threads_utils - libc.include.errno - libc.include.sys_mman - libc.include.sys_syscall - libc.include.threads - libc.src.__support.common - libc.src.__support.OSUtil.osutil - COMPILE_OPTIONS - -O3 - -fno-omit-frame-pointer # This allows us to sniff out the thread args from - # the new thread's stack reliably. -) - -add_entrypoint_object( - thrd_join - SRCS - thrd_join.cpp - HDRS - ../thrd_join.h - DEPENDS - .threads_utils - libc.include.sys_syscall - libc.include.threads - libc.src.__support.CPP.atomic - libc.src.__support.common - libc.src.__support.OSUtil.osutil + libc.src.__support.threads.linux.futex_word_type ) add_entrypoint_object( diff --git a/libc/src/threads/linux/CndVar.h b/libc/src/threads/linux/CndVar.h index 2b914d480c76..009cb9f06c3f 100644 --- a/libc/src/threads/linux/CndVar.h +++ b/libc/src/threads/linux/CndVar.h @@ -13,6 +13,7 @@ #include "include/threads.h" // For values like thrd_success etc. #include "src/__support/CPP/atomic.h" #include "src/__support/OSUtil/syscall.h" // For syscall functions. +#include "src/__support/threads/linux/futex_word.h" #include "src/__support/threads/mutex.h" #include <linux/futex.h> // For futex operations. @@ -106,7 +107,7 @@ struct CndVar { if (waitq_front == nullptr) waitq_back = nullptr; - qmtx.futex_word = Mutex::FutexWordType(Mutex::LockState::Free); + qmtx.futex_word = FutexWordType(Mutex::LockState::Free); __llvm_libc::syscall( SYS_futex, &qmtx.futex_word.val, FUTEX_WAKE_OP, 1, 1, diff --git a/libc/src/threads/linux/Thread.h b/libc/src/threads/linux/Thread.h deleted file mode 100644 index de58ae4c64c6..000000000000 --- a/libc/src/threads/linux/Thread.h +++ /dev/null @@ -1,23 +0,0 @@ -//===-- Linux specific definitions for threads implementations. --*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H -#define LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H - -#include <stdint.h> - -namespace __llvm_libc { - -struct ThreadParams { - static constexpr uintptr_t DEFAULT_STACK_SIZE = 1 << 16; // 64 KB - static constexpr uint32_t CLEAR_TID_VALUE = 0xABCD1234; -}; - -} // namespace __llvm_libc - -#endif // LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H diff --git a/libc/src/threads/linux/thrd_create.cpp b/libc/src/threads/linux/thrd_create.cpp deleted file mode 100644 index 5f25ded38bd3..000000000000 --- a/libc/src/threads/linux/thrd_create.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//===-- Linux implementation of the thrd_create function ------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "Futex.h" - -#include "src/__support/OSUtil/syscall.h" // For syscall function. -#include "src/__support/architectures.h" -#include "src/__support/common.h" -#include "src/threads/linux/Thread.h" -#include "src/threads/thrd_create.h" - -#include <errno.h> // For E* error values. -#include <linux/sched.h> // For CLONE_* flags. -#include <stdint.h> -#include <sys/mman.h> // For PROT_* and MAP_* definitions. -#include <sys/syscall.h> // For syscall numbers. -#include <threads.h> // For thrd_* type definitions. - -#ifdef SYS_mmap2 -constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2; -#elif SYS_mmap -constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap; -#else -#error "SYS_mmap or SYS_mmap2 not available on the target platform" -#endif - -namespace __llvm_libc { - -// 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<uintptr_t>(__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<StartArgs *>(get_start_args_addr()); - __llvm_libc::syscall(SYS_exit, start_args->thread->__retval = - start_args->func(start_args->arg)); -} - -LLVM_LIBC_FUNCTION(int, thrd_create, - (thrd_t * thread, thrd_start_t func, void *arg)) { - unsigned clone_flags = - CLONE_VM // Share the memory space with the parent. - | CLONE_FS // Share the file system with the parent. - | CLONE_FILES // Share the files with the parent. - | CLONE_SIGHAND // Share the signal handlers with the parent. - | CLONE_THREAD // Same thread group as the parent. - | CLONE_SYSVSEM // Share a single list of System V semaphore adjustment - // values - | CLONE_PARENT_SETTID // Set child thread ID in |ptid| of the parent. - | CLONE_CHILD_CLEARTID; // Let the kernel clear the tid address and futex - // wake the joining thread. - // TODO: Add the CLONE_SETTLS flag and setup the TLS area correctly when - // making the clone syscall. - - // Allocate thread stack. - long mmap_result = - __llvm_libc::syscall(MMAP_SYSCALL_NUMBER, - 0, // No special address - ThreadParams::DEFAULT_STACK_SIZE, - PROT_READ | PROT_WRITE, // Read and write stack - MAP_ANONYMOUS | MAP_PRIVATE, // Process private - -1, // Not backed by any file - 0 // No offset - ); - if (mmap_result < 0 && (uintptr_t(mmap_result) >= - UINTPTR_MAX - ThreadParams::DEFAULT_STACK_SIZE)) { - return -mmap_result == ENOMEM ? thrd_nomem : thrd_error; - } - void *stack = reinterpret_cast<void *>(mmap_result); - - thread->__stack = stack; - thread->__stack_size = ThreadParams::DEFAULT_STACK_SIZE; - thread->__retval = -1; - FutexWordType *clear_tid_address = &thread->__clear_tid.__word; - *clear_tid_address = ThreadParams::CLEAR_TID_VALUE; - - // When the new thread is spawned by the kernel, the new thread gets the - // stack we pass to the clone syscall. However, this stack is empty and does - // not have any local vars present in this function. Hence, one cannot - // pass arguments to the thread start function, or use any local vars from - // here. So, we pack them into the new stack from where the thread can sniff - // them out. - uintptr_t adjusted_stack = reinterpret_cast<uintptr_t>(stack) + - ThreadParams::DEFAULT_STACK_SIZE - - sizeof(StartArgs); - StartArgs *start_args = reinterpret_cast<StartArgs *>(adjusted_stack); - start_args->thread = thread; - start_args->func = func; - start_args->arg = arg; - - // 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, // 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(); - } else if (clone_result < 0) { - __llvm_libc::syscall(SYS_munmap, mmap_result, - ThreadParams::DEFAULT_STACK_SIZE); - int error_val = -clone_result; - return error_val == ENOMEM ? thrd_nomem : thrd_error; - } - - return thrd_success; -} - -} // namespace __llvm_libc diff --git a/libc/src/threads/linux/thrd_join.cpp b/libc/src/threads/linux/thrd_join.cpp deleted file mode 100644 index 30275ff73754..000000000000 --- a/libc/src/threads/linux/thrd_join.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//===-- Linux implementation of the thrd_join function --------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "Futex.h" - -#include "src/__support/CPP/atomic.h" -#include "src/__support/OSUtil/syscall.h" // For syscall function. -#include "src/__support/common.h" -#include "src/threads/linux/Thread.h" -#include "src/threads/thrd_join.h" - -#include <linux/futex.h> // For futex operations. -#include <sys/syscall.h> // For syscall numbers. -#include <threads.h> // For thrd_* type definitions. - -namespace __llvm_libc { - -LLVM_LIBC_FUNCTION(int, thrd_join, (thrd_t * thread, int *retval)) { - auto *clear_tid_address = - reinterpret_cast<cpp::Atomic<FutexWordType> *>(&thread->__clear_tid); - - // The kernel should set the value at the clear tid address to zero. - // If not, it is a spurious wake and we should continue to wait on - // the futex. - while (clear_tid_address->load() != 0) { - // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a - // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE. - __llvm_libc::syscall(SYS_futex, &clear_tid_address->val, FUTEX_WAIT, - ThreadParams::CLEAR_TID_VALUE, nullptr); - } - - *retval = thread->__retval; - - if (__llvm_libc::syscall(SYS_munmap, reinterpret_cast<long>(thread->__stack), - thread->__stack_size) == -1) - return thrd_error; - - return thrd_success; -} - -} // namespace __llvm_libc diff --git a/libc/src/threads/thrd_create.cpp b/libc/src/threads/thrd_create.cpp new file mode 100644 index 000000000000..91b36a71f823 --- /dev/null +++ b/libc/src/threads/thrd_create.cpp @@ -0,0 +1,33 @@ +//===-- Linux implementation of the thrd_create function ------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/threads/thrd_create.h" +#include "src/__support/common.h" +#include "src/__support/threads/thread.h" + +#include <errno.h> +#include <threads.h> // For thrd_* type definitions. + +namespace __llvm_libc { + +static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread<int>), + "Mismatch between thrd_t and internal Thread<int>."); + +LLVM_LIBC_FUNCTION(int, thrd_create, + (thrd_t * th, thrd_start_t func, void *arg)) { + auto *thread = reinterpret_cast<__llvm_libc::Thread<int> *>(th); + int result = thread->run(func, arg, nullptr, 0); + if (result == 0) + return thrd_success; + else if (result == ENOMEM) + return thrd_nomem; + else + return thrd_error; +} + +} // namespace __llvm_libc diff --git a/libc/src/threads/thrd_create.h b/libc/src/threads/thrd_create.h index d2bb7dfad41c..9ed19c48c0a4 100644 --- a/libc/src/threads/thrd_create.h +++ b/libc/src/threads/thrd_create.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC_THREADS_THRD_CREATE_H #define LLVM_LIBC_SRC_THREADS_THRD_CREATE_H -#include "include/threads.h" +#include <threads.h> namespace __llvm_libc { diff --git a/libc/src/threads/thrd_join.cpp b/libc/src/threads/thrd_join.cpp new file mode 100644 index 000000000000..20096a7be1bf --- /dev/null +++ b/libc/src/threads/thrd_join.cpp @@ -0,0 +1,30 @@ +//===-- Linux implementation of the thrd_join function --------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/threads/thrd_join.h" +#include "src/__support/common.h" +#include "src/__support/threads/thread.h" + +#include <threads.h> // For thrd_* type definitions. + +namespace __llvm_libc { + +static_assert(sizeof(thrd_t) == sizeof(__llvm_libc::Thread<int>), + "Mismatch between thrd_t and internal Thread<int>."); + +LLVM_LIBC_FUNCTION(int, thrd_join, (thrd_t * th, int *retval)) { + auto *thread = reinterpret_cast<Thread<int> *>(th); + int result = thread->join(); + if (result == 0) { + *retval = thread->return_value(); + return thrd_success; + } + return thrd_error; +} + +} // namespace __llvm_libc |
