[libc-commits] [libc] 8dc4280 - [libc] Add implementations of pthread_equal and pthread_self.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Thu Jul 14 13:12:55 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-07-14T20:12:35Z
New Revision: 8dc42802f7052d2eed4f2267851b94578c0152fc
URL: https://github.com/llvm/llvm-project/commit/8dc42802f7052d2eed4f2267851b94578c0152fc
DIFF: https://github.com/llvm/llvm-project/commit/8dc42802f7052d2eed4f2267851b94578c0152fc.diff
LOG: [libc] Add implementations of pthread_equal and pthread_self.
Reviewed By: michaelrj, lntue
Differential Revision: https://reviews.llvm.org/D129729
Added:
libc/src/pthread/pthread_equal.cpp
libc/src/pthread/pthread_equal.h
libc/src/pthread/pthread_self.cpp
libc/src/pthread/pthread_self.h
libc/src/threads/thrd_current.cpp
libc/src/threads/thrd_current.h
libc/src/threads/thrd_equal.cpp
libc/src/threads/thrd_equal.h
libc/test/integration/src/pthread/pthread_equal_test.cpp
libc/test/integration/src/threads/thrd_equal_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/loader/linux/aarch64/start.cpp
libc/loader/linux/x86_64/CMakeLists.txt
libc/loader/linux/x86_64/start.cpp
libc/spec/posix.td
libc/spec/stdc.td
libc/src/__support/threads/linux/thread.cpp
libc/src/__support/threads/thread.cpp
libc/src/__support/threads/thread.h
libc/src/pthread/CMakeLists.txt
libc/src/pthread/pthread_join.cpp
libc/src/threads/CMakeLists.txt
libc/test/integration/src/pthread/CMakeLists.txt
libc/test/integration/src/threads/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 06258688b254d..93c76b305e1c9 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -241,7 +241,9 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_attr_init
libc.src.pthread.pthread_create
libc.src.pthread.pthread_detach
+ libc.src.pthread.pthread_equal
libc.src.pthread.pthread_join
+ libc.src.pthread.pthread_self
libc.src.pthread.pthread_mutex_destroy
libc.src.pthread.pthread_mutex_init
libc.src.pthread.pthread_mutex_lock
@@ -310,7 +312,9 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.threads.mtx_lock
libc.src.threads.mtx_unlock
libc.src.threads.thrd_create
+ libc.src.threads.thrd_current
libc.src.threads.thrd_detach
+ libc.src.threads.thrd_equal
libc.src.threads.thrd_join
# time.h entrypoints
diff --git a/libc/loader/linux/aarch64/start.cpp b/libc/loader/linux/aarch64/start.cpp
index 5835c838078c3..6c977860a28bd 100644
--- a/libc/loader/linux/aarch64/start.cpp
+++ b/libc/loader/linux/aarch64/start.cpp
@@ -8,6 +8,7 @@
#include "config/linux/app.h"
#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/threads/thread.h"
#include "src/string/memory_utils/memcpy_implementations.h"
#include <arm_acle.h>
@@ -35,6 +36,8 @@ static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
AppProperties app;
+static ThreadAttributes main_thread_attrib;
+
void init_tls(TLSDescriptor &tls_descriptor) {
if (app.tls.size == 0) {
tls_descriptor.size = 0;
@@ -105,6 +108,11 @@ extern "C" void _start() {
app.args = reinterpret_cast<__llvm_libc::Args *>(
reinterpret_cast<uintptr_t *>(__builtin_frame_address(0)) + 2);
+ auto tid = __llvm_libc::syscall(SYS_gettid);
+ if (tid <= 0)
+ __llvm_libc::syscall(SYS_exit, 1);
+ __llvm_libc::main_thread_attrib.tid = tid;
+
// After the argv array, is a 8-byte long NULL value before the array of env
// values. The end of the env values is marked by another 8-byte long NULL
// value. We step over it (the "+ 1" below) to get to the env values.
@@ -151,6 +159,8 @@ extern "C" void _start() {
if (tls.size != 0)
__llvm_libc::set_thread_ptr(tls.tp);
+ __llvm_libc::self.attrib = &__llvm_libc::main_thread_attrib;
+
int retval = main(app.args->argc, reinterpret_cast<char **>(app.args->argv),
reinterpret_cast<char **>(env_ptr));
__llvm_libc::cleanup_tls(tls.addr, tls.size);
diff --git a/libc/loader/linux/x86_64/CMakeLists.txt b/libc/loader/linux/x86_64/CMakeLists.txt
index 47c3d38e24e8e..238364ee21820 100644
--- a/libc/loader/linux/x86_64/CMakeLists.txt
+++ b/libc/loader/linux/x86_64/CMakeLists.txt
@@ -6,6 +6,7 @@ add_loader_object(
libc.config.linux.app_h
libc.include.sys_mman
libc.include.sys_syscall
+ libc.src.__support.threads.thread
libc.src.__support.OSUtil.osutil
libc.src.string.memory_utils.memcpy_implementation
COMPILE_OPTIONS
diff --git a/libc/loader/linux/x86_64/start.cpp b/libc/loader/linux/x86_64/start.cpp
index 514caaf4dca63..03382065dd35c 100644
--- a/libc/loader/linux/x86_64/start.cpp
+++ b/libc/loader/linux/x86_64/start.cpp
@@ -8,6 +8,7 @@
#include "config/linux/app.h"
#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/threads/thread.h"
#include "src/string/memory_utils/memcpy_implementations.h"
#include <asm/prctl.h>
@@ -31,6 +32,8 @@ static constexpr long mmapSyscallNumber = SYS_mmap;
AppProperties app;
+static ThreadAttributes main_thread_attrib;
+
// TODO: The function is x86_64 specific. Move it to config/linux/app.h
// and generalize it. Also, dynamic loading is not handled currently.
void init_tls(TLSDescriptor &tls_descriptor) {
@@ -118,6 +121,11 @@ extern "C" void _start() {
__asm__ __volatile__("andq $0xfffffffffffffff0, %%rsp\n\t" ::: "%rsp");
__asm__ __volatile__("andq $0xfffffffffffffff0, %%rbp\n\t" ::: "%rbp");
+ auto tid = __llvm_libc::syscall(SYS_gettid);
+ if (tid <= 0)
+ __llvm_libc::syscall(SYS_exit, 1);
+ __llvm_libc::main_thread_attrib.tid = tid;
+
// After the argv array, is a 8-byte long NULL value before the array of env
// values. The end of the env values is marked by another 8-byte long NULL
// value. We step over it (the "+ 1" below) to get to the env values.
@@ -165,6 +173,8 @@ extern "C" void _start() {
if (tls.size != 0 && !__llvm_libc::set_thread_ptr(tls.tp))
__llvm_libc::syscall(SYS_exit, 1);
+ __llvm_libc::self.attrib = &__llvm_libc::main_thread_attrib;
+
int retval = main(app.args->argc, reinterpret_cast<char **>(app.args->argv),
reinterpret_cast<char **>(env_ptr));
__llvm_libc::cleanup_tls(tls.addr, tls.size);
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 915a177913402..2840b5d911421 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -466,6 +466,16 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<PThreadTType>]
>,
+ FunctionSpec<
+ "pthread_self",
+ RetValSpec<PThreadTType>,
+ [ArgSpec<VoidType>]
+ >,
+ FunctionSpec<
+ "pthread_equal",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadTType>, ArgSpec<PThreadTType>]
+ >,
FunctionSpec<
"pthread_mutexattr_init",
RetValSpec<IntType>,
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 72809cc694cf2..b998c0da3aa20 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -810,6 +810,16 @@ def StdC : StandardSpec<"stdc"> {
"thrd_detach",
RetValSpec<IntType>,
[ArgSpec<ThrdTType>]
+ >,
+ FunctionSpec<
+ "thrd_current",
+ RetValSpec<ThrdTType>,
+ [ArgSpec<VoidType>]
+ >,
+ FunctionSpec<
+ "thrd_equal",
+ RetValSpec<IntType>,
+ [ArgSpec<ThrdTType>, ArgSpec<ThrdTType>]
>
]
>;
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index e5b73d43c0a4b..83c85f9b5128b 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -111,6 +111,8 @@ __attribute__((noinline))
static void start_thread() {
auto *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr());
auto *attrib = start_args->thread_attrib;
+ self.attrib = attrib;
+
long retval;
if (attrib->style == ThreadStyle::POSIX) {
attrib->retval.posix_retval =
@@ -272,4 +274,8 @@ void Thread::wait() {
}
}
+bool Thread::operator==(const Thread &thread) const {
+ return attrib->tid == thread.attrib->tid;
+}
+
} // namespace __llvm_libc
diff --git a/libc/src/__support/threads/thread.cpp b/libc/src/__support/threads/thread.cpp
index 1ca78ece703dd..6149f7724fca6 100644
--- a/libc/src/__support/threads/thread.cpp
+++ b/libc/src/__support/threads/thread.cpp
@@ -6,5 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// This file is currently emtpy. In future, declaration of a self thread object
-// etc. will be added here.
+#include "thread.h"
+
+namespace __llvm_libc {
+
+thread_local Thread self;
+
+} // namespace __llvm_libc
diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h
index 7f965923391d1..2ca17aa08dcfc 100644
--- a/libc/src/__support/threads/thread.h
+++ b/libc/src/__support/threads/thread.h
@@ -162,8 +162,13 @@ struct Thread {
// NOTE: This function is to be used for testing only. There is no standard
// which requires exposing it via a public API.
void wait();
+
+ // Return true if this thread is equal to the other thread.
+ bool operator==(const Thread &other) const;
};
+extern thread_local Thread self;
+
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SUPPORT_THREADS_THREAD_H
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index d786a35155492..4c45cc53a3e82 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -279,3 +279,25 @@ add_entrypoint_object(
libc.include.pthread
libc.src.__support.threads.thread
)
+
+add_entrypoint_object(
+ pthread_equal
+ SRCS
+ pthread_equal.cpp
+ HDRS
+ pthread_equal.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.thread
+)
+
+add_entrypoint_object(
+ pthread_self
+ SRCS
+ pthread_self.cpp
+ HDRS
+ pthread_self.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.thread
+)
diff --git a/libc/src/pthread/pthread_equal.cpp b/libc/src/pthread/pthread_equal.cpp
new file mode 100644
index 0000000000000..29460204ae1d9
--- /dev/null
+++ b/libc/src/pthread/pthread_equal.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of the pthread_equal 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 "pthread_equal.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <pthread.h> // For pthread_* type definitions.
+
+namespace __llvm_libc {
+
+static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread),
+ "Mismatch between pthread_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(int, pthread_equal, (pthread_t lhs, pthread_t rhs)) {
+ auto *lhs_internal = reinterpret_cast<Thread *>(&lhs);
+ auto *rhs_internal = reinterpret_cast<Thread *>(&rhs);
+ return *lhs_internal == *rhs_internal;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_equal.h b/libc/src/pthread/pthread_equal.h
new file mode 100644
index 0000000000000..a4518d179e78c
--- /dev/null
+++ b/libc/src/pthread/pthread_equal.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_equal 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_PTHREAD_EQUAL_H
+#define LLVM_LIBC_SRC_THREADS_PTHREAD_EQUAL_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_equal(pthread_t lhs, pthread_t rhs);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_PTHREAD_EQUAL_H
diff --git a/libc/src/pthread/pthread_join.cpp b/libc/src/pthread/pthread_join.cpp
index 0774d02680526..b888260247cd8 100644
--- a/libc/src/pthread/pthread_join.cpp
+++ b/libc/src/pthread/pthread_join.cpp
@@ -1,4 +1,4 @@
-//===-- Linux implementation of the pthread_join function -----------------===//
+//===-- Implementation of the pthread_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.
diff --git a/libc/src/pthread/pthread_self.cpp b/libc/src/pthread/pthread_self.cpp
new file mode 100644
index 0000000000000..5b3145f34930c
--- /dev/null
+++ b/libc/src/pthread/pthread_self.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of the pthread_self 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 "pthread_self.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <pthread.h> // For pthread_* type definitions.
+
+namespace __llvm_libc {
+
+static_assert(sizeof(pthread_t) == sizeof(__llvm_libc::Thread),
+ "Mismatch between pthread_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(pthread_t, pthread_self, ()) {
+ pthread_t th;
+ th.__attrib = self.attrib;
+ return th;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_self.h b/libc/src/pthread/pthread_self.h
new file mode 100644
index 0000000000000..dd4b920a0b04b
--- /dev/null
+++ b/libc/src/pthread/pthread_self.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_self 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_PTHREAD_SELF_H
+#define LLVM_LIBC_SRC_THREADS_PTHREAD_SELF_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+pthread_t pthread_self();
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_PTHREAD_SELF_H
diff --git a/libc/src/threads/CMakeLists.txt b/libc/src/threads/CMakeLists.txt
index bdbb32d81e1c1..179d1e56205b8 100644
--- a/libc/src/threads/CMakeLists.txt
+++ b/libc/src/threads/CMakeLists.txt
@@ -46,6 +46,28 @@ add_entrypoint_object(
libc.src.__support.threads.thread
)
+add_entrypoint_object(
+ thrd_current
+ SRCS
+ thrd_current.cpp
+ HDRS
+ thrd_current.h
+ DEPENDS
+ libc.include.threads
+ libc.src.__support.threads.thread
+)
+
+add_entrypoint_object(
+ thrd_equal
+ SRCS
+ thrd_equal.cpp
+ HDRS
+ thrd_equal.h
+ DEPENDS
+ libc.include.threads
+ libc.src.__support.threads.thread
+)
+
add_entrypoint_object(
mtx_init
SRCS
diff --git a/libc/src/threads/thrd_current.cpp b/libc/src/threads/thrd_current.cpp
new file mode 100644
index 0000000000000..e8afd7bf6c49a
--- /dev/null
+++ b/libc/src/threads/thrd_current.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of the thrd_current 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_current.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),
+ "Mismatch between thrd_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(thrd_t, thrd_current, ()) {
+ thrd_t th;
+ th.__attrib = self.attrib;
+ return th;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/threads/thrd_current.h b/libc/src/threads/thrd_current.h
new file mode 100644
index 0000000000000..774b445aa339b
--- /dev/null
+++ b/libc/src/threads/thrd_current.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for thrd_current 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_THRD_CURRENT_H
+#define LLVM_LIBC_SRC_THREADS_THRD_CURRENT_H
+
+#include "include/threads.h"
+
+namespace __llvm_libc {
+
+thrd_t thrd_current();
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_THRD_CURRENT_H
diff --git a/libc/src/threads/thrd_equal.cpp b/libc/src/threads/thrd_equal.cpp
new file mode 100644
index 0000000000000..aac220ec9adb4
--- /dev/null
+++ b/libc/src/threads/thrd_equal.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of the thrd_equal 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_equal.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),
+ "Mismatch between thrd_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(int, thrd_equal, (thrd_t lhs, thrd_t rhs)) {
+ auto *lhs_internal = reinterpret_cast<Thread *>(&lhs);
+ auto *rhs_internal = reinterpret_cast<Thread *>(&rhs);
+ return *lhs_internal == *rhs_internal;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/threads/thrd_equal.h b/libc/src/threads/thrd_equal.h
new file mode 100644
index 0000000000000..123563ea71247
--- /dev/null
+++ b/libc/src/threads/thrd_equal.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for thrd_equal 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_THRD_EQUAL_H
+#define LLVM_LIBC_SRC_THREADS_THRD_EQUAL_H
+
+#include "include/threads.h"
+
+namespace __llvm_libc {
+
+int thrd_equal(thrd_t lhs, thrd_t rhs);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_THRD_EQUAL_H
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 0f52d8ac28e63..e751318bb0012 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -32,3 +32,24 @@ add_integration_test(
libc.src.pthread.pthread_create
libc.src.pthread.pthread_join
)
+
+add_integration_test(
+ pthread_equal_test
+ SUITE
+ libc-pthread-integration-tests
+ SRCS
+ pthread_equal_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc.include.pthread
+ libc.src.errno.errno
+ libc.src.pthread.pthread_mutex_destroy
+ libc.src.pthread.pthread_mutex_init
+ libc.src.pthread.pthread_mutex_lock
+ libc.src.pthread.pthread_mutex_unlock
+ libc.src.pthread.pthread_create
+ libc.src.pthread.pthread_equal
+ libc.src.pthread.pthread_join
+ libc.src.pthread.pthread_self
+)
diff --git a/libc/test/integration/src/pthread/pthread_equal_test.cpp b/libc/test/integration/src/pthread/pthread_equal_test.cpp
new file mode 100644
index 0000000000000..2f1ff6a8c8730
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_equal_test.cpp
@@ -0,0 +1,67 @@
+//===-- Tests for pthread_equal -------------------------------------------===//
+//
+// 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/pthread/pthread_create.h"
+#include "src/pthread/pthread_equal.h"
+#include "src/pthread/pthread_join.h"
+#include "src/pthread/pthread_mutex_destroy.h"
+#include "src/pthread/pthread_mutex_init.h"
+#include "src/pthread/pthread_mutex_lock.h"
+#include "src/pthread/pthread_mutex_unlock.h"
+#include "src/pthread/pthread_self.h"
+
+#include "utils/IntegrationTest/test.h"
+
+#include <pthread.h>
+
+pthread_t child_thread;
+pthread_mutex_t mutex;
+
+static void *child_func(void *arg) {
+ __llvm_libc::pthread_mutex_lock(&mutex);
+ int *ret = reinterpret_cast<int *>(arg);
+ auto self = __llvm_libc::pthread_self();
+ *ret = __llvm_libc::pthread_equal(child_thread, self);
+ __llvm_libc::pthread_mutex_unlock(&mutex);
+ return nullptr;
+}
+
+int main() {
+ // We init and lock the mutex so that we guarantee that the child thread is
+ // waiting after startup.
+ ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0);
+ ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0);
+
+ auto main_thread = __llvm_libc::pthread_self();
+
+ // The idea here is that, we start a child thread which will immediately
+ // wait on |mutex|. The main thread will update the global |child_thread| var
+ // and unlock |mutex|. This will give the child thread a chance to compare
+ // the result of pthread_self with the |child_thread|. The result of the
+ // comparison is returned in the thread arg.
+ int result = 0;
+ pthread_t th;
+ ASSERT_EQ(__llvm_libc::pthread_create(&th, nullptr, child_func, &result), 0);
+ // This new thread should of course not be equal to the main thread.
+ ASSERT_EQ(__llvm_libc::pthread_equal(th, main_thread), 0);
+
+ // Set the |child_thread| global var and unlock to allow the child to perform
+ // the comparison.
+ child_thread = th;
+ ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0);
+
+ void *retval;
+ ASSERT_EQ(__llvm_libc::pthread_join(th, &retval), 0);
+ ASSERT_EQ(uintptr_t(retval), uintptr_t(nullptr));
+ // The child thread should see that pthread_self return value is the same as
+ // |child_thread|.
+ ASSERT_NE(result, 0);
+
+ __llvm_libc::pthread_mutex_destroy(&mutex);
+ return 0;
+}
diff --git a/libc/test/integration/src/threads/CMakeLists.txt b/libc/test/integration/src/threads/CMakeLists.txt
index 05acc7f1da456..34dc47127005d 100644
--- a/libc/test/integration/src/threads/CMakeLists.txt
+++ b/libc/test/integration/src/threads/CMakeLists.txt
@@ -19,6 +19,26 @@ add_integration_test(
libc.src.threads.thrd_join
)
+add_integration_test(
+ thrd_equal_test
+ SUITE
+ libc-threads-integration-tests
+ SRCS
+ thrd_equal_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc.include.threads
+ 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_current
+ libc.src.threads.thrd_equal
+ libc.src.threads.thrd_join
+)
+
add_integration_test(
thrd_test
SUITE
diff --git a/libc/test/integration/src/threads/thrd_equal_test.cpp b/libc/test/integration/src/threads/thrd_equal_test.cpp
new file mode 100644
index 0000000000000..4058d0d141815
--- /dev/null
+++ b/libc/test/integration/src/threads/thrd_equal_test.cpp
@@ -0,0 +1,68 @@
+//===-- Tests for thrd_equal ----------------------------------------------===//
+//
+// 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/mtx_destroy.h"
+#include "src/threads/mtx_init.h"
+#include "src/threads/mtx_lock.h"
+#include "src/threads/mtx_unlock.h"
+#include "src/threads/thrd_create.h"
+#include "src/threads/thrd_current.h"
+#include "src/threads/thrd_equal.h"
+#include "src/threads/thrd_join.h"
+
+#include "utils/IntegrationTest/test.h"
+
+#include <threads.h>
+
+thrd_t child_thread;
+mtx_t mutex;
+
+static int child_func(void *arg) {
+ __llvm_libc::mtx_lock(&mutex);
+ int *ret = reinterpret_cast<int *>(arg);
+ auto self = __llvm_libc::thrd_current();
+ *ret = __llvm_libc::thrd_equal(child_thread, self);
+ __llvm_libc::mtx_unlock(&mutex);
+ return 0;
+}
+
+int main() {
+ // We init and lock the mutex so that we guarantee that the child thread is
+ // waiting after startup.
+ ASSERT_EQ(__llvm_libc::mtx_init(&mutex, mtx_plain), int(thrd_success));
+ ASSERT_EQ(__llvm_libc::mtx_lock(&mutex), int(thrd_success));
+
+ auto main_thread = __llvm_libc::thrd_current();
+
+ // The idea here is that, we start a child thread which will immediately
+ // wait on |mutex|. The main thread will update the global |child_thread| var
+ // and unlock |mutex|. This will give the child thread a chance to compare
+ // the result of thrd_self with the |child_thread|. The result of the
+ // comparison is returned in the thread arg.
+ int result = 0;
+ thrd_t th;
+ ASSERT_EQ(__llvm_libc::thrd_create(&th, child_func, &result),
+ int(thrd_success));
+ // This new thread should of course not be equal to the main thread.
+ ASSERT_EQ(__llvm_libc::thrd_equal(th, main_thread), 0);
+
+ // Set the |child_thread| global var and unlock to allow the child to perform
+ // the comparison.
+ child_thread = th;
+ ASSERT_EQ(__llvm_libc::mtx_unlock(&mutex), int(thrd_success));
+
+ int retval;
+ ASSERT_EQ(__llvm_libc::thrd_join(&th, &retval), int(thrd_success));
+ ASSERT_EQ(retval, 0);
+ // The child thread should see that thrd_current return value is the same as
+ // |child_thread|.
+ ASSERT_NE(result, 0);
+
+ __llvm_libc::mtx_destroy(&mutex);
+ return 0;
+}
More information about the libc-commits
mailing list