summaryrefslogtreecommitdiff
path: root/libc/src/threads
diff options
context:
space:
mode:
authorSiva Chandra Reddy <sivachandra@google.com>2022-04-01 06:42:14 +0000
committerSiva Chandra Reddy <sivachandra@google.com>2022-04-07 16:13:21 +0000
commit2ce09e680a7dc1201463ae74e199eac66ac52a8d (patch)
tree4b14f88eb781045a5141c6c1fb51933bfe9f78f9 /libc/src/threads
parent0a77e633226b5598e426603c03e54d62ed275670 (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.txt20
-rw-r--r--libc/src/threads/linux/CMakeLists.txt37
-rw-r--r--libc/src/threads/linux/CndVar.h3
-rw-r--r--libc/src/threads/linux/Thread.h23
-rw-r--r--libc/src/threads/linux/thrd_create.cpp153
-rw-r--r--libc/src/threads/linux/thrd_join.cpp46
-rw-r--r--libc/src/threads/thrd_create.cpp33
-rw-r--r--libc/src/threads/thrd_create.h2
-rw-r--r--libc/src/threads/thrd_join.cpp30
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