[libc-commits] [libc] 4a738ee - [libc] Add implemementations of thread specific data related API.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Thu Aug 11 22:28:58 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-08-12T05:28:40Z
New Revision: 4a738ee8220e02df62b7b43d3fe5b2d6be88c482
URL: https://github.com/llvm/llvm-project/commit/4a738ee8220e02df62b7b43d3fe5b2d6be88c482
DIFF: https://github.com/llvm/llvm-project/commit/4a738ee8220e02df62b7b43d3fe5b2d6be88c482.diff
LOG: [libc] Add implemementations of thread specific data related API.
Specifically, POSIX functions pthread_key_create, pthread_key_delete,
pthread_setspecific and pthread_getspecific have been added. The C
standard equivalents tss_create, tss_delete, tss_set and tss_get have
also been added.
Reviewed By: lntue, michaelrj
Differential Revision: https://reviews.llvm.org/D131647
Added:
libc/include/llvm-libc-types/__pthread_tss_dtor_t.h
libc/include/llvm-libc-types/pthread_key_t.h
libc/include/llvm-libc-types/tss_dtor_t.h
libc/include/llvm-libc-types/tss_t.h
libc/src/pthread/pthread_getspecific.cpp
libc/src/pthread/pthread_getspecific.h
libc/src/pthread/pthread_key_create.cpp
libc/src/pthread/pthread_key_create.h
libc/src/pthread/pthread_key_delete.cpp
libc/src/pthread/pthread_key_delete.h
libc/src/pthread/pthread_setspecific.cpp
libc/src/pthread/pthread_setspecific.h
libc/src/threads/tss_create.cpp
libc/src/threads/tss_create.h
libc/src/threads/tss_delete.cpp
libc/src/threads/tss_delete.h
libc/src/threads/tss_get.cpp
libc/src/threads/tss_get.h
libc/src/threads/tss_set.cpp
libc/src/threads/tss_set.h
libc/test/integration/src/pthread/pthread_tss_test.cpp
libc/test/integration/src/threads/tss_test.cpp
Modified:
libc/config/linux/api.td
libc/config/linux/x86_64/entrypoints.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-types/CMakeLists.txt
libc/spec/posix.td
libc/spec/stdc.td
libc/src/__support/threads/CMakeLists.txt
libc/src/__support/threads/thread.cpp
libc/src/__support/threads/thread.h
libc/src/pthread/CMakeLists.txt
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/api.td b/libc/config/linux/api.td
index e7fe144b622d8..7aa23cc0c1bdd 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -231,6 +231,8 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
"mtx_t",
"thrd_t",
"thrd_start_t",
+ "tss_t",
+ "tss_dtor_t",
];
let Enumerations = [
@@ -248,10 +250,12 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
def PThreadAPI : PublicAPI<"pthread.h"> {
let Types = [
"__pthread_start_t",
+ "__pthread_tss_dtor_t",
"pthread_attr_t",
"pthread_mutex_t",
"pthread_mutexattr_t",
"pthread_t",
+ "pthread_key_t",
];
}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index fcef386186da9..585df9eba6efa 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -253,9 +253,12 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_equal
libc.src.pthread.pthread_exit
libc.src.pthread.pthread_getname_np
+ libc.src.pthread.pthread_getspecific
libc.src.pthread.pthread_join
libc.src.pthread.pthread_self
libc.src.pthread.pthread_setname_np
+ libc.src.pthread.pthread_key_create
+ libc.src.pthread.pthread_key_delete
libc.src.pthread.pthread_mutex_destroy
libc.src.pthread.pthread_mutex_init
libc.src.pthread.pthread_mutex_lock
@@ -268,6 +271,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_mutexattr_setpshared
libc.src.pthread.pthread_mutexattr_setrobust
libc.src.pthread.pthread_mutexattr_settype
+ libc.src.pthread.pthread_setspecific
# stdlib.h entrypoints
libc.src.stdlib._Exit
@@ -328,6 +332,10 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.threads.thrd_equal
libc.src.threads.thrd_exit
libc.src.threads.thrd_join
+ libc.src.threads.tss_create
+ libc.src.threads.tss_delete
+ libc.src.threads.tss_get
+ libc.src.threads.tss_set
# time.h entrypoints
libc.src.time.asctime
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 229abe25d23bb..faa8b1e8fcb1d 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -104,6 +104,8 @@ add_gen_header(
.llvm-libc-types.once_flag
.llvm-libc-types.thrd_start_t
.llvm-libc-types.thrd_t
+ .llvm-libc-types.tss_t
+ .llvm-libc-types.tss_dtor_t
)
add_gen_header(
@@ -174,7 +176,9 @@ add_gen_header(
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.__pthread_start_t
+ .llvm-libc-types.__pthread_tss_dtor_t
.llvm-libc-types.pthread_attr_t
+ .llvm-libc-types.pthread_key_t
.llvm-libc-types.pthread_mutex_t
.llvm-libc-types.pthread_mutexattr_t
.llvm-libc-types.pthread_t
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index c0e389eb355e2..e766b3e1fe2d0 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -3,6 +3,7 @@ add_header(__call_once_func_t HDR __call_once_func_t.h)
add_header(__futex_word HDR __futex_word.h)
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word)
add_header(__pthread_start_t HDR __pthread_start_t.h)
+add_header(__pthread_tss_dtor_t HDR __pthread_tss_dtor_t.h)
add_header(__qsortcompare_t HDR __qsortcompare_t.h)
add_header(__sighandler_t HDR __sighandler_t.h)
add_header(__thread_type HDR __thread_type.h)
@@ -25,6 +26,7 @@ add_header(off_t HDR off_t.h)
add_header(off64_t HDR off64_t.h)
add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t)
+add_header(pthread_key_t HDR pthread_key_t.h)
add_header(pthread_mutex_t HDR pthread_mutex_t.h DEPENDS .__futex_word .__mutex_type)
add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type)
add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h)
@@ -36,4 +38,6 @@ add_header(struct_tm HDR struct_tm.h)
add_header(thrd_start_t HDR thrd_start_t.h)
add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type)
add_header(time_t HDR time_t.h)
+add_header(tss_t HDR tss_t.h)
+add_header(tss_dtor_t HDR tss_dtor_t.h)
add_header(__atexithandler_t HDR __atexithandler_t.h)
diff --git a/libc/include/llvm-libc-types/__pthread_tss_dtor_t.h b/libc/include/llvm-libc-types/__pthread_tss_dtor_t.h
new file mode 100644
index 0000000000000..1b54d31a79771
--- /dev/null
+++ b/libc/include/llvm-libc-types/__pthread_tss_dtor_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of the type __pthread_tss_dtor_t -----------------------===//
+//
+// 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_TYPES_PTHREAD_TSS_DTOR_T_H__
+#define __LLVM_LIBC_TYPES_PTHREAD_TSS_DTOR_T_H__
+
+typedef void (*__pthread_tss_dtor_t)(void *);
+
+#endif // __LLVM_LIBC_TYPES_PTHREAD_TSS_DTOR_T_H__
diff --git a/libc/include/llvm-libc-types/pthread_key_t.h b/libc/include/llvm-libc-types/pthread_key_t.h
new file mode 100644
index 0000000000000..351e37614a01e
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_key_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of the type pthread_key_t ------------------------------===//
+//
+// 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_TYPES_PTHREAD_KEY_T_H__
+#define __LLVM_LIBC_TYPES_PTHREAD_KEY_T_H__
+
+typedef unsigned int pthread_key_t;
+
+#endif // __LLVM_LIBC_TYPES_PTHREAD_KEY_T_H__
diff --git a/libc/include/llvm-libc-types/tss_dtor_t.h b/libc/include/llvm-libc-types/tss_dtor_t.h
new file mode 100644
index 0000000000000..f80661b588ba3
--- /dev/null
+++ b/libc/include/llvm-libc-types/tss_dtor_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of the type tss_dtor_t ---------------------------------===//
+//
+// 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_TYPES_TSS_DTOR_T_H__
+#define __LLVM_LIBC_TYPES_TSS_DTOR_T_H__
+
+typedef void (*tss_dtor_t)(void *);
+
+#endif // __LLVM_LIBC_TYPES_TSS_DTOR_T_H__
diff --git a/libc/include/llvm-libc-types/tss_t.h b/libc/include/llvm-libc-types/tss_t.h
new file mode 100644
index 0000000000000..868ec1ac11288
--- /dev/null
+++ b/libc/include/llvm-libc-types/tss_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of the type tss_t --------------------------------------===//
+//
+// 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_TYPES_TSS_T_H__
+#define __LLVM_LIBC_TYPES_TSS_T_H__
+
+typedef unsigned int tss_t;
+
+#endif // __LLVM_LIBC_TYPES_TSS_T_H__
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 1a3177f50b810..fd5c0a9853597 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -11,6 +11,9 @@ def RestrictedStructSigactionPtr : RestrictedPtrType<StructSigaction>;
def ConstRestrictedStructSigactionPtr : ConstType<RestrictedStructSigactionPtr>;
def PThreadStartT : NamedType<"__pthread_start_t">;
+def PThreadTSSDtorT : NamedType<"__pthread_tss_dtor_t">;
+def PThreadKeyT : NamedType<"pthread_key_t">;
+def PThreadKeyTPtr : PtrType<PThreadKeyT>;
def InoT : NamedType<"ino_t">;
def DIR : NamedType<"DIR">;
@@ -406,7 +409,15 @@ def POSIX : StandardSpec<"POSIX"> {
HeaderSpec PThread = HeaderSpec<
"pthread.h",
[], // Macros
- [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType, PThreadStartT, PThreadTType], // Types
+ [
+ PThreadAttrTType,
+ PThreadKeyT,
+ PThreadMutexAttrTType,
+ PThreadMutexTType,
+ PThreadStartT,
+ PThreadTSSDtorT,
+ PThreadTType,
+ ], // Types
[], // Enumerations
[
FunctionSpec<
@@ -569,6 +580,26 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<PThreadMutexTPtr>]
>,
+ FunctionSpec<
+ "pthread_key_create",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadKeyTPtr>, ArgSpec<PThreadTSSDtorT>]
+ >,
+ FunctionSpec<
+ "pthread_key_delete",
+ RetValSpec<IntType>,
+ [ArgSpec<PThreadKeyT>]
+ >,
+ FunctionSpec<
+ "pthread_getspecific",
+ RetValSpec<VoidPtr>,
+ [ArgSpec<PThreadKeyT>]
+ >,
+ FunctionSpec<
+ "pthread_setspecific",
+ RetValSpec<VoidPtr>,
+ [ArgSpec<PThreadKeyT>, ArgSpec<ConstVoidPtr>]
+ >,
]
>;
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 4e7da2b67d9af..4986262364fb8 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -8,6 +8,10 @@ def StdC : StandardSpec<"stdc"> {
NamedType LDivTType = NamedType<"ldiv_t">;
NamedType LLDivTType = NamedType<"lldiv_t">;
+ NamedType TssTType = NamedType<"tss_t">;
+ PtrType TssTPtr = PtrType<TssTType>;
+ NamedType TssDtorTType = NamedType<"tss_dtor_t">;
+
HeaderSpec Assert = HeaderSpec<
"assert.h",
[
@@ -708,6 +712,8 @@ def StdC : StandardSpec<"stdc"> {
MtxTType,
ThrdStartTType,
ThrdTType,
+ TssTType,
+ TssDtorTType,
],
[
EnumeratedNameValue<"mtx_plain">,
@@ -830,6 +836,26 @@ def StdC : StandardSpec<"stdc"> {
RetValSpec<VoidType>,
[ArgSpec<IntType>]
>,
+ FunctionSpec<
+ "tss_create",
+ RetValSpec<IntType>,
+ [ArgSpec<TssTPtr>, ArgSpec<TssDtorTType>]
+ >,
+ FunctionSpec<
+ "tss_delete",
+ RetValSpec<IntType>,
+ [ArgSpec<TssTType>]
+ >,
+ FunctionSpec<
+ "tss_get",
+ RetValSpec<VoidPtr>,
+ [ArgSpec<TssTType>]
+ >,
+ FunctionSpec<
+ "tss_set",
+ RetValSpec<IntType>,
+ [ArgSpec<TssTType>, ArgSpec<VoidPtr>]
+ >,
]
>;
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index 9d4b0060c60f1..413989c5879d0 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -25,6 +25,7 @@ add_header_library(
DEPENDS
libc.src.__support.common
libc.src.__support.CPP.atomic
+ libc.src.__support.CPP.optional
libc.src.__support.CPP.string_view
libc.src.__support.CPP.stringstream
)
@@ -38,5 +39,7 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread)
.mutex
.${LIBC_TARGET_OS}.thread
libc.src.__support.fixedvector
+ libc.src.__support.CPP.array
+ libc.src.__support.CPP.optional
)
endif()
diff --git a/libc/src/__support/threads/thread.cpp b/libc/src/__support/threads/thread.cpp
index 205be944cc17a..b2680ecc0bda0 100644
--- a/libc/src/__support/threads/thread.cpp
+++ b/libc/src/__support/threads/thread.cpp
@@ -9,6 +9,8 @@
#include "thread.h"
#include "mutex.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/optional.h"
#include "src/__support/fixedvector.h"
namespace __llvm_libc {
@@ -26,6 +28,79 @@ struct AtExitUnit {
constexpr AtExitUnit(AtExitCallback *cb, void *o) : callback(cb), obj(o) {}
};
+constexpr size_t TSS_KEY_COUNT = 1024;
+
+struct TSSKeyUnit {
+ // Indicates whether is unit is active. Presence of a non-null dtor
+ // is not sufficient to indicate the same information as a TSS key can
+ // have a null destructor.
+ bool active = false;
+
+ TSSDtor *dtor = nullptr;
+
+ constexpr TSSKeyUnit() = default;
+ constexpr TSSKeyUnit(TSSDtor *d) : active(true), dtor(d) {}
+
+ void reset() {
+ active = false;
+ dtor = nullptr;
+ }
+};
+
+class TSSKeyMgr {
+ Mutex mtx;
+ cpp::array<TSSKeyUnit, TSS_KEY_COUNT> units;
+
+public:
+ constexpr TSSKeyMgr() : mtx(false, false, false) {}
+
+ cpp::optional<unsigned int> new_key(TSSDtor *dtor) {
+ MutexLock lock(&mtx);
+ for (size_t i = 0; i < TSS_KEY_COUNT; ++i) {
+ TSSKeyUnit &u = units[i];
+ if (!u.active) {
+ u = {dtor};
+ return i;
+ }
+ }
+ return cpp::optional<unsigned int>();
+ }
+
+ TSSDtor *get_dtor(unsigned int key) {
+ if (key >= TSS_KEY_COUNT)
+ return nullptr;
+ MutexLock lock(&mtx);
+ return units[key].dtor;
+ }
+
+ bool remove_key(unsigned int key) {
+ if (key >= TSS_KEY_COUNT)
+ return false;
+ MutexLock lock(&mtx);
+ units[key].reset();
+ return true;
+ }
+
+ bool is_valid_key(unsigned int key) {
+ MutexLock lock(&mtx);
+ return units[key].active;
+ }
+};
+
+TSSKeyMgr tss_key_mgr;
+
+struct TSSValueUnit {
+ bool active = false;
+ void *payload = nullptr;
+ TSSDtor *dtor = nullptr;
+
+ constexpr TSSValueUnit() = default;
+ constexpr TSSValueUnit(void *p, TSSDtor *d)
+ : active(true), payload(p), dtor(d) {}
+};
+
+static thread_local cpp::array<TSSValueUnit, TSS_KEY_COUNT> tss_values;
+
} // anonymous namespace
class ThreadAtExitCallbackMgr {
@@ -74,8 +149,36 @@ ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() {
void call_atexit_callbacks(ThreadAttributes *attrib) {
attrib->atexit_callback_mgr->call();
+ for (size_t i = 0; i < TSS_KEY_COUNT; ++i) {
+ TSSValueUnit &unit = tss_values[i];
+ if (unit.dtor != nullptr)
+ unit.dtor(unit.payload);
+ }
}
} // namespace internal
+cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) {
+ return tss_key_mgr.new_key(dtor);
+}
+
+bool tss_key_delete(unsigned int key) { return tss_key_mgr.remove_key(key); }
+
+bool set_tss_value(unsigned int key, void *val) {
+ if (!tss_key_mgr.is_valid_key(key))
+ return false;
+ tss_values[key] = {val, tss_key_mgr.get_dtor(key)};
+ return true;
+}
+
+void *get_tss_value(unsigned int key) {
+ if (key >= TSS_KEY_COUNT)
+ return nullptr;
+
+ auto &u = tss_values[key];
+ if (!u.active)
+ return nullptr;
+ return u.payload;
+}
+
} // namespace __llvm_libc
diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h
index 1b125dd65da50..134e0c9cd9447 100644
--- a/libc/src/__support/threads/thread.h
+++ b/libc/src/__support/threads/thread.h
@@ -11,6 +11,7 @@
#include "src/__support/CPP/StringView.h"
#include "src/__support/CPP/atomic.h"
+#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/stringstream.h"
#include "src/__support/architectures.h"
@@ -105,6 +106,30 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes {
platform_data(nullptr) {}
};
+using TSSDtor = void(void *);
+
+// Create a new TSS key and associate the |dtor| as the corresponding
+// destructor. Can be used to implement public functions like
+// pthread_key_create.
+cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor);
+
+// Delete the |key|. Can be used to implement public functions like
+// pthread_key_delete.
+//
+// Return true on success, false on failure.
+bool tss_key_delete(unsigned int key);
+
+// Set the value associated with |key| for the current thread. Can be used
+// to implement public functions like pthread_setspecific.
+//
+// Return true on success, false on failure.
+bool set_tss_value(unsigned int key, void *value);
+
+// Return the value associated with |key| for the current thread. Return
+// nullptr if |key| is invalid. Can be used to implement public functions like
+// pthread_getspecific.
+void *get_tss_value(unsigned int key);
+
struct Thread {
ThreadAttributes *attrib;
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index a1d92e6cbf4e6..43cffb6168c60 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -338,3 +338,51 @@ add_entrypoint_object(
libc.src.__support.CPP.stringstream
libc.src.__support.threads.thread
)
+
+add_entrypoint_object(
+ pthread_key_create
+ SRCS
+ pthread_key_create.cpp
+ HDRS
+ pthread_key_create.h
+ DEPENDS
+ libc.include.errno
+ libc.include.pthread
+ libc.src.__support.threads.thread
+)
+
+add_entrypoint_object(
+ pthread_key_delete
+ SRCS
+ pthread_key_delete.cpp
+ HDRS
+ pthread_key_delete.h
+ DEPENDS
+ libc.include.errno
+ libc.include.pthread
+ libc.src.__support.threads.thread
+)
+
+add_entrypoint_object(
+ pthread_getspecific
+ SRCS
+ pthread_getspecific.cpp
+ HDRS
+ pthread_getspecific.h
+ DEPENDS
+ libc.include.errno
+ libc.include.pthread
+ libc.src.__support.threads.thread
+)
+
+add_entrypoint_object(
+ pthread_setspecific
+ SRCS
+ pthread_setspecific.cpp
+ HDRS
+ pthread_setspecific.h
+ DEPENDS
+ libc.include.errno
+ libc.include.pthread
+ libc.src.__support.threads.thread
+)
diff --git a/libc/src/pthread/pthread_getspecific.cpp b/libc/src/pthread/pthread_getspecific.cpp
new file mode 100644
index 0000000000000..02545564a8ccc
--- /dev/null
+++ b/libc/src/pthread/pthread_getspecific.cpp
@@ -0,0 +1,23 @@
+//===-- Linux implementation of the pthread_getspecific 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_getspecific.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <pthread.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void *, pthread_getspecific, (pthread_key_t key)) {
+ return get_tss_value(key);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_getspecific.h b/libc/src/pthread/pthread_getspecific.h
new file mode 100644
index 0000000000000..c7da0137d5450
--- /dev/null
+++ b/libc/src/pthread/pthread_getspecific.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_getspecific 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_PTHREAD_PTHREAD_GETSPECIFIC_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSPECIFIC_H
+
+#include <pthread.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+void *pthread_getspecific(pthread_key_t);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSPECIFIC_H
diff --git a/libc/src/pthread/pthread_key_create.cpp b/libc/src/pthread/pthread_key_create.cpp
new file mode 100644
index 0000000000000..1dc8eecfa5a21
--- /dev/null
+++ b/libc/src/pthread/pthread_key_create.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of the pthread_key_create --------------------------===//
+//
+// 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_key_create.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, pthread_key_create,
+ (pthread_key_t * key, __pthread_tss_dtor_t dtor)) {
+ auto k = __llvm_libc::new_tss_key(dtor);
+ if (!k)
+ return EINVAL;
+ *key = *k;
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_key_create.h b/libc/src/pthread/pthread_key_create.h
new file mode 100644
index 0000000000000..cd5916ab01fbe
--- /dev/null
+++ b/libc/src/pthread/pthread_key_create.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_key_create ------------*- 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_PTHREAD_PTHREAD_KEY_CREATE_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_KEY_CREATE_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_key_create(pthread_key_t *key, __pthread_tss_dtor_t dtor);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_KEY_CREATE_H
diff --git a/libc/src/pthread/pthread_key_delete.cpp b/libc/src/pthread/pthread_key_delete.cpp
new file mode 100644
index 0000000000000..d45424cf60135
--- /dev/null
+++ b/libc/src/pthread/pthread_key_delete.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of the pthread_key_delete --------------------------===//
+//
+// 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_key_delete.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, pthread_key_delete, (pthread_key_t key)) {
+ if (__llvm_libc::tss_key_delete(key))
+ return 0;
+ else
+ return EINVAL;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_key_delete.h b/libc/src/pthread/pthread_key_delete.h
new file mode 100644
index 0000000000000..3ec528dde7197
--- /dev/null
+++ b/libc/src/pthread/pthread_key_delete.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_key_delete ------------*- 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_PTHREAD_PTHREAD_KEY_DELETE_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_KEY_DELETE_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_key_delete(pthread_key_t key);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_KEY_DELETE_H
diff --git a/libc/src/pthread/pthread_setspecific.cpp b/libc/src/pthread/pthread_setspecific.cpp
new file mode 100644
index 0000000000000..15504f7f53630
--- /dev/null
+++ b/libc/src/pthread/pthread_setspecific.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of the pthread_setspecific 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_setspecific.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, pthread_setspecific,
+ (pthread_key_t key, const void *data)) {
+ if (set_tss_value(key, const_cast<void *>(data)))
+ return 0;
+ else
+ return EINVAL;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/pthread/pthread_setspecific.h b/libc/src/pthread/pthread_setspecific.h
new file mode 100644
index 0000000000000..4211a8e79e876
--- /dev/null
+++ b/libc/src/pthread/pthread_setspecific.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_setspecific 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_PTHREAD_PTHREAD_SETSPECIFIC_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETSPECIFIC_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_setspecific(pthread_key_t, const void *);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETSPECIFIC_H
diff --git a/libc/src/threads/CMakeLists.txt b/libc/src/threads/CMakeLists.txt
index 15efef9221e07..db011caa57760 100644
--- a/libc/src/threads/CMakeLists.txt
+++ b/libc/src/threads/CMakeLists.txt
@@ -123,6 +123,50 @@ add_entrypoint_object(
libc.src.__support.threads.mutex
)
+add_entrypoint_object(
+ tss_create
+ SRCS
+ tss_create.cpp
+ HDRS
+ tss_create.h
+ DEPENDS
+ libc.include.threads
+ libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+ tss_delete
+ SRCS
+ tss_delete.cpp
+ HDRS
+ tss_delete.h
+ DEPENDS
+ libc.include.threads
+ libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+ tss_get
+ SRCS
+ tss_get.cpp
+ HDRS
+ tss_get.h
+ DEPENDS
+ libc.include.threads
+ libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+ tss_set
+ SRCS
+ tss_set.cpp
+ HDRS
+ tss_set.h
+ DEPENDS
+ libc.include.threads
+ libc.src.__support.threads.mutex
+)
+
add_entrypoint_object(
cnd_init
ALIAS
diff --git a/libc/src/threads/tss_create.cpp b/libc/src/threads/tss_create.cpp
new file mode 100644
index 0000000000000..f384565fbb9d1
--- /dev/null
+++ b/libc/src/threads/tss_create.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of the tss_create ----------------------------------===//
+//
+// 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 "tss_create.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, tss_create, (tss_t * key, tss_dtor_t dtor)) {
+ auto k = __llvm_libc::new_tss_key(dtor);
+ if (!k)
+ return thrd_error;
+ *key = *k;
+ return thrd_success;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/threads/tss_create.h b/libc/src/threads/tss_create.h
new file mode 100644
index 0000000000000..967bdca10c4fe
--- /dev/null
+++ b/libc/src/threads/tss_create.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for tss_create --------------------*- 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_TSS_CREATE_H
+#define LLVM_LIBC_SRC_THREADS_TSS_CREATE_H
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+int tss_create(tss_t *key, tss_dtor_t dtor);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_TSS_CREATE_H
diff --git a/libc/src/threads/tss_delete.cpp b/libc/src/threads/tss_delete.cpp
new file mode 100644
index 0000000000000..6bdd4aa91867e
--- /dev/null
+++ b/libc/src/threads/tss_delete.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of the tss_delete ----------------------------------===//
+//
+// 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 "tss_delete.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void, tss_delete, (tss_t key)) {
+ __llvm_libc::tss_key_delete(key);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/threads/tss_delete.h b/libc/src/threads/tss_delete.h
new file mode 100644
index 0000000000000..1f55d3ba69f59
--- /dev/null
+++ b/libc/src/threads/tss_delete.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for tss_delete --------------------*- 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_TSS_DELETE_H
+#define LLVM_LIBC_SRC_THREADS_TSS_DELETE_H
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+void tss_delete(tss_t key);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_TSS_DELETE_H
diff --git a/libc/src/threads/tss_get.cpp b/libc/src/threads/tss_get.cpp
new file mode 100644
index 0000000000000..4596a9337ffcc
--- /dev/null
+++ b/libc/src/threads/tss_get.cpp
@@ -0,0 +1,20 @@
+//===-- Linux implementation of the tss_get 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 "tss_get.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void *, tss_get, (tss_t key)) { return get_tss_value(key); }
+
+} // namespace __llvm_libc
diff --git a/libc/src/threads/tss_get.h b/libc/src/threads/tss_get.h
new file mode 100644
index 0000000000000..9f1d95ab747ed
--- /dev/null
+++ b/libc/src/threads/tss_get.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for tss_get 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_TSS_GET_H
+#define LLVM_LIBC_SRC_THREADS_TSS_GET_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+void *tss_get(pthread_key_t);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_TSS_GET_H
diff --git a/libc/src/threads/tss_set.cpp b/libc/src/threads/tss_set.cpp
new file mode 100644
index 0000000000000..977168a2a98cf
--- /dev/null
+++ b/libc/src/threads/tss_set.cpp
@@ -0,0 +1,25 @@
+//===-- Linux implementation of the tss_set 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 "tss_set.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/thread.h"
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, tss_set, (tss_t key, void *data)) {
+ if (set_tss_value(key, data))
+ return thrd_success;
+ else
+ return thrd_error;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/threads/tss_set.h b/libc/src/threads/tss_set.h
new file mode 100644
index 0000000000000..49d69efa62ade
--- /dev/null
+++ b/libc/src/threads/tss_set.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for tss_set 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_TSS_SET_H
+#define LLVM_LIBC_SRC_THREADS_TSS_SET_H
+
+#include <threads.h>
+
+namespace __llvm_libc {
+
+int tss_set(tss_t, void *);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_THREADS_TSS_SET_H
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index a1a34beef444e..31838fb04dfe5 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -91,3 +91,22 @@ add_integration_test(
libc.src.pthread.pthread_exit
libc.src.pthread.pthread_join
)
+
+add_integration_test(
+ pthread_tss_test
+ SUITE
+ libc-pthread-integration-tests
+ SRCS
+ pthread_tss_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc.include.pthread
+ libc.src.pthread.pthread_create
+ libc.src.pthread.pthread_exit
+ libc.src.pthread.pthread_join
+ libc.src.pthread.pthread_key_create
+ libc.src.pthread.pthread_key_delete
+ libc.src.pthread.pthread_getspecific
+ libc.src.pthread.pthread_setspecific
+)
diff --git a/libc/test/integration/src/pthread/pthread_tss_test.cpp b/libc/test/integration/src/pthread/pthread_tss_test.cpp
new file mode 100644
index 0000000000000..4c03872f9af2f
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_tss_test.cpp
@@ -0,0 +1,62 @@
+//===-- Tests for TSS API like pthread_setspecific etc. -------------------===//
+//
+// 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_exit.h"
+#include "src/pthread/pthread_getspecific.h"
+#include "src/pthread/pthread_join.h"
+#include "src/pthread/pthread_key_create.h"
+#include "src/pthread/pthread_key_delete.h"
+#include "src/pthread/pthread_setspecific.h"
+#include "utils/IntegrationTest/test.h"
+
+#include <pthread.h>
+
+static constexpr int THREAD_DATA_INITVAL = 0x1234;
+static constexpr int THREAD_DATA_FINIVAL = 0x4321;
+static constexpr int THREAD_RUN_VAL = 0x600D;
+
+int child_thread_data = THREAD_DATA_INITVAL;
+int main_thread_data = THREAD_DATA_INITVAL;
+
+pthread_key_t key;
+void dtor(void *data) {
+ auto *v = reinterpret_cast<int *>(data);
+ *v = THREAD_DATA_FINIVAL;
+}
+
+void *func(void *obj) {
+ ASSERT_EQ(__llvm_libc::pthread_setspecific(key, &child_thread_data), 0);
+ int *d = reinterpret_cast<int *>(__llvm_libc::pthread_getspecific(key));
+ ASSERT_TRUE(d != nullptr);
+ ASSERT_EQ(&child_thread_data, d);
+ ASSERT_EQ(*d, THREAD_DATA_INITVAL);
+ *reinterpret_cast<int *>(obj) = THREAD_RUN_VAL;
+ return nullptr;
+}
+
+TEST_MAIN() {
+ ASSERT_EQ(__llvm_libc::pthread_key_create(&key, &dtor), 0);
+ ASSERT_EQ(__llvm_libc::pthread_setspecific(key, &main_thread_data), 0);
+ int *d = reinterpret_cast<int *>(__llvm_libc::pthread_getspecific(key));
+ ASSERT_TRUE(d != nullptr);
+ ASSERT_EQ(&main_thread_data, d);
+ ASSERT_EQ(*d, THREAD_DATA_INITVAL);
+
+ pthread_t th;
+ int arg = 0xBAD;
+ ASSERT_EQ(__llvm_libc::pthread_create(&th, nullptr, &func, &arg), 0);
+ void *retval = &child_thread_data; // Init to some non-nullptr val.
+ ASSERT_EQ(__llvm_libc::pthread_join(th, &retval), 0);
+ ASSERT_EQ(retval, nullptr);
+ ASSERT_EQ(arg, THREAD_RUN_VAL);
+ ASSERT_EQ(child_thread_data, THREAD_DATA_FINIVAL);
+
+ ASSERT_EQ(__llvm_libc::pthread_key_delete(key), 0);
+ return 0;
+}
diff --git a/libc/test/integration/src/threads/CMakeLists.txt b/libc/test/integration/src/threads/CMakeLists.txt
index f3a70b61974fa..4dc82da58e051 100644
--- a/libc/test/integration/src/threads/CMakeLists.txt
+++ b/libc/test/integration/src/threads/CMakeLists.txt
@@ -69,6 +69,25 @@ add_integration_test(
libc.src.threads.thrd_join
)
+add_integration_test(
+ tss_test
+ SUITE
+ libc-threads-integration-tests
+ SRCS
+ tss_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc.include.threads
+ libc.src.threads.thrd_create
+ libc.src.threads.thrd_exit
+ libc.src.threads.thrd_join
+ libc.src.threads.tss_create
+ libc.src.threads.tss_delete
+ libc.src.threads.tss_get
+ libc.src.threads.tss_set
+)
+
add_integration_test(
call_once_test
SUITE
diff --git a/libc/test/integration/src/threads/tss_test.cpp b/libc/test/integration/src/threads/tss_test.cpp
new file mode 100644
index 0000000000000..065d4f5483c81
--- /dev/null
+++ b/libc/test/integration/src/threads/tss_test.cpp
@@ -0,0 +1,63 @@
+//===-- Tests for TSS API like tss_set, tss_get etc. ----------------------===//
+//
+// 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/threads/thrd_exit.h"
+#include "src/threads/thrd_join.h"
+#include "src/threads/tss_create.h"
+#include "src/threads/tss_delete.h"
+#include "src/threads/tss_get.h"
+#include "src/threads/tss_set.h"
+#include "utils/IntegrationTest/test.h"
+
+#include <threads.h>
+
+static constexpr int THREAD_DATA_INITVAL = 0x1234;
+static constexpr int THREAD_DATA_FINIVAL = 0x4321;
+static constexpr int THREAD_RUN_VAL = 0x600D;
+
+int child_thread_data = THREAD_DATA_INITVAL;
+int main_thread_data = THREAD_DATA_INITVAL;
+
+tss_t key;
+void dtor(void *data) {
+ auto *v = reinterpret_cast<int *>(data);
+ *v = THREAD_DATA_FINIVAL;
+}
+
+int func(void *obj) {
+ ASSERT_EQ(__llvm_libc::tss_set(key, &child_thread_data), thrd_success);
+ int *d = reinterpret_cast<int *>(__llvm_libc::tss_get(key));
+ ASSERT_TRUE(d != nullptr);
+ ASSERT_EQ(&child_thread_data, d);
+ ASSERT_EQ(*d, THREAD_DATA_INITVAL);
+ *reinterpret_cast<int *>(obj) = THREAD_RUN_VAL;
+ return 0;
+}
+
+TEST_MAIN() {
+ ASSERT_EQ(__llvm_libc::tss_create(&key, &dtor), thrd_success);
+ ASSERT_EQ(__llvm_libc::tss_set(key, &main_thread_data), thrd_success);
+ int *d = reinterpret_cast<int *>(__llvm_libc::tss_get(key));
+ ASSERT_TRUE(d != nullptr);
+ ASSERT_EQ(&main_thread_data, d);
+ ASSERT_EQ(*d, THREAD_DATA_INITVAL);
+
+ thrd_t th;
+ int arg = 0xBAD;
+ ASSERT_EQ(__llvm_libc::thrd_create(&th, &func, &arg), thrd_success);
+ int retval = THREAD_DATA_INITVAL; // Init to some non-zero val.
+ ASSERT_EQ(__llvm_libc::thrd_join(th, &retval), thrd_success);
+ ASSERT_EQ(retval, 0);
+ ASSERT_EQ(arg, THREAD_RUN_VAL);
+ ASSERT_EQ(child_thread_data, THREAD_DATA_FINIVAL);
+
+ __llvm_libc::tss_delete(key);
+
+ return 0;
+}
More information about the libc-commits
mailing list