summaryrefslogtreecommitdiff
path: root/libc/src/threads
diff options
context:
space:
mode:
authorSiva Chandra Reddy <sivachandra@google.com>2019-12-04 09:06:56 -0800
committerSiva Chandra Reddy <sivachandra@google.com>2020-03-05 13:53:17 -0800
commitabc040e9533011a62a25c93b07b4fc31c8a641f7 (patch)
treef5d6e0b5c2a175732ea9bc98755226f66a14eeb5 /libc/src/threads
parenta0cd413426479abb207381bdbab862f3dfb3ce7d (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.txt3
-rw-r--r--libc/src/threads/linux/CMakeLists.txt37
-rw-r--r--libc/src/threads/linux/thrd_create.cpp74
-rw-r--r--libc/src/threads/linux/thrd_join.cpp44
-rw-r--r--libc/src/threads/linux/thread_utils.h21
-rw-r--r--libc/src/threads/thrd_create.h20
-rw-r--r--libc/src/threads/thrd_join.h20
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