diff options
| author | Siva Chandra Reddy <sivachandra@google.com> | 2019-12-04 09:06:56 -0800 |
|---|---|---|
| committer | Siva Chandra Reddy <sivachandra@google.com> | 2020-03-05 13:53:17 -0800 |
| commit | abc040e9533011a62a25c93b07b4fc31c8a641f7 (patch) | |
| tree | f5d6e0b5c2a175732ea9bc98755226f66a14eeb5 /libc/src/threads | |
| parent | a0cd413426479abb207381bdbab862f3dfb3ce7d (diff) | |
[libc] Add linux implementations of thrd_create and thrd_join functions.
Reviewers: abrachet, phosek
Differential Revision: https://reviews.llvm.org/D75380
Diffstat (limited to 'libc/src/threads')
| -rw-r--r-- | libc/src/threads/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | libc/src/threads/linux/CMakeLists.txt | 37 | ||||
| -rw-r--r-- | libc/src/threads/linux/thrd_create.cpp | 74 | ||||
| -rw-r--r-- | libc/src/threads/linux/thrd_join.cpp | 44 | ||||
| -rw-r--r-- | libc/src/threads/linux/thread_utils.h | 21 | ||||
| -rw-r--r-- | libc/src/threads/thrd_create.h | 20 | ||||
| -rw-r--r-- | libc/src/threads/thrd_join.h | 20 |
7 files changed, 219 insertions, 0 deletions
diff --git a/libc/src/threads/CMakeLists.txt b/libc/src/threads/CMakeLists.txt new file mode 100644 index 000000000000..b4bbe81c92ff --- /dev/null +++ b/libc/src/threads/CMakeLists.txt @@ -0,0 +1,3 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${LIBC_TARGET_OS}) +endif() diff --git a/libc/src/threads/linux/CMakeLists.txt b/libc/src/threads/linux/CMakeLists.txt new file mode 100644 index 000000000000..809a365a834d --- /dev/null +++ b/libc/src/threads/linux/CMakeLists.txt @@ -0,0 +1,37 @@ +add_header_library( + threads_utils + HDRS + thread_utils.h +) + +add_entrypoint_object( + thrd_create + SRCS + thrd_create.cpp + HDRS + ../thrd_create.h + DEPENDS + errno_h + linux_syscall_h + mmap + support_common_h + sys_syscall_h + threads_h + threads_utils + __errno_location +) + +add_entrypoint_object( + thrd_join + SRCS + thrd_join.cpp + HDRS + ../thrd_join.h + DEPENDS + linux_syscall_h + munmap + support_common_h + sys_syscall_h + threads_h + threads_utils +) diff --git a/libc/src/threads/linux/thrd_create.cpp b/libc/src/threads/linux/thrd_create.cpp new file mode 100644 index 000000000000..650c38cab924 --- /dev/null +++ b/libc/src/threads/linux/thrd_create.cpp @@ -0,0 +1,74 @@ +//===---------- 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 "config/linux/syscall.h" // For syscall function. +#include "include/errno.h" // For E* error values. +#include "include/sys/mman.h" // For PROT_* and MAP_* definitions. +#include "include/sys/syscall.h" // For syscall numbers. +#include "include/threads.h" // For thrd_* type definitions. +#include "src/__support/common.h" +#include "src/errno/llvmlibc_errno.h" +#include "src/sys/mman/mmap.h" +#include "src/sys/mman/munmap.h" +#include "src/threads/linux/thread_utils.h" + +#include <linux/futex.h> // For futex operations. +#include <linux/sched.h> // For CLONE_* flags. +#include <stdint.h> + +namespace __llvm_libc { + +static void start_thread(thrd_t *thread, thrd_start_t func, void *arg) { + __llvm_libc::syscall(SYS_exit, thread->__retval = func(arg)); +} + +int LLVM_LIBC_ENTRYPOINT(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. + + void *stack = __llvm_libc::mmap(nullptr, ThreadParams::DefaultStackSize, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (stack == MAP_FAILED) + return llvmlibc_errno == ENOMEM ? thrd_nomem : thrd_error; + + thread->__stack = stack; + thread->__stack_size = ThreadParams::DefaultStackSize; + thread->__retval = -1; + FutexData *clear_tid_address = + reinterpret_cast<FutexData *>(thread->__clear_tid); + *clear_tid_address = ThreadParams::ClearTIDValue; + + long clone_result = __llvm_libc::syscall( + SYS_clone, clone_flags, + reinterpret_cast<uintptr_t>(stack) + ThreadParams::DefaultStackSize - 1, + &thread->__tid, clear_tid_address, 0); + + if (clone_result == 0) { + start_thread(thread, func, arg); + } else if (clone_result < 0) { + 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 new file mode 100644 index 000000000000..7237354f89e9 --- /dev/null +++ b/libc/src/threads/linux/thrd_join.cpp @@ -0,0 +1,44 @@ +//===----------- 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 "config/linux/syscall.h" // For syscall function. +#include "include/sys/syscall.h" // For syscall numbers. +#include "include/threads.h" // For thrd_* type definitions. +#include "src/__support/common.h" +#include "src/sys/mman/munmap.h" +#include "src/threads/linux/thread_utils.h" + +#include <linux/futex.h> // For futex operations. +#include <stdatomic.h> // For atomic_load. + +namespace __llvm_libc { + +int LLVM_LIBC_ENTRYPOINT(thrd_join)(thrd_t *thread, int *retval) { + FutexData *clear_tid_address = + reinterpret_cast<FutexData *>(thread->__clear_tid); + + while (atomic_load(clear_tid_address) != 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, FUTEX_WAIT, + ThreadParams::ClearTIDValue, nullptr); + + // 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. + } + + *retval = thread->__retval; + + if (__llvm_libc::munmap(thread->__stack, thread->__stack_size) == -1) + return thrd_error; + + return thrd_success; +} + +} // namespace __llvm_libc diff --git a/libc/src/threads/linux/thread_utils.h b/libc/src/threads/linux/thread_utils.h new file mode 100644 index 000000000000..b6f41b47d81e --- /dev/null +++ b/libc/src/threads/linux/thread_utils.h @@ -0,0 +1,21 @@ +//===--- Linux specific definitions to support mutex operations --*- 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> + +using FutexData = _Atomic uint32_t; + +struct ThreadParams { + static constexpr uintptr_t DefaultStackSize = 1 << 15; // 32 KB + static constexpr uint32_t ClearTIDValue = 0xABCD1234; +}; + +#endif // LLVM_LIBC_SRC_THREADS_LINUX_THREAD_UTILS_H diff --git a/libc/src/threads/thrd_create.h b/libc/src/threads/thrd_create.h new file mode 100644 index 000000000000..311929020905 --- /dev/null +++ b/libc/src/threads/thrd_create.h @@ -0,0 +1,20 @@ +//===------- Implementation header for thrd_create 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_THREADS_LINUX_THRD_CREATE_H +#define LLVM_LIBC_SRC_THREADS_LINUX_THRD_CREATE_H + +#include "include/threads.h" + +namespace __llvm_libc { + +int thrd_create(thrd_t *thread, thrd_start_t func, void *arg); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_THREADS_LINUX_THRD_CREATE_H diff --git a/libc/src/threads/thrd_join.h b/libc/src/threads/thrd_join.h new file mode 100644 index 000000000000..495b049d5f06 --- /dev/null +++ b/libc/src/threads/thrd_join.h @@ -0,0 +1,20 @@ +//===-------- Implementation header for thrd_join 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_THREADS_LINUX_THRD_JOIN_H +#define LLVM_LIBC_SRC_THREADS_LINUX_THRD_JOIN_H + +#include "include/threads.h" + +namespace __llvm_libc { + +int thrd_join(thrd_t *thread, int *retval); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_THREADS_LINUX_THRD_JOIN_H |
