forked from OSchip/llvm-project
[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
This commit is contained in:
parent
12e1936f64
commit
4a738ee822
|
@ -231,6 +231,8 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
|
||||||
"mtx_t",
|
"mtx_t",
|
||||||
"thrd_t",
|
"thrd_t",
|
||||||
"thrd_start_t",
|
"thrd_start_t",
|
||||||
|
"tss_t",
|
||||||
|
"tss_dtor_t",
|
||||||
];
|
];
|
||||||
|
|
||||||
let Enumerations = [
|
let Enumerations = [
|
||||||
|
@ -248,10 +250,12 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
|
||||||
def PThreadAPI : PublicAPI<"pthread.h"> {
|
def PThreadAPI : PublicAPI<"pthread.h"> {
|
||||||
let Types = [
|
let Types = [
|
||||||
"__pthread_start_t",
|
"__pthread_start_t",
|
||||||
|
"__pthread_tss_dtor_t",
|
||||||
"pthread_attr_t",
|
"pthread_attr_t",
|
||||||
"pthread_mutex_t",
|
"pthread_mutex_t",
|
||||||
"pthread_mutexattr_t",
|
"pthread_mutexattr_t",
|
||||||
"pthread_t",
|
"pthread_t",
|
||||||
|
"pthread_key_t",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,9 +253,12 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||||
libc.src.pthread.pthread_equal
|
libc.src.pthread.pthread_equal
|
||||||
libc.src.pthread.pthread_exit
|
libc.src.pthread.pthread_exit
|
||||||
libc.src.pthread.pthread_getname_np
|
libc.src.pthread.pthread_getname_np
|
||||||
|
libc.src.pthread.pthread_getspecific
|
||||||
libc.src.pthread.pthread_join
|
libc.src.pthread.pthread_join
|
||||||
libc.src.pthread.pthread_self
|
libc.src.pthread.pthread_self
|
||||||
libc.src.pthread.pthread_setname_np
|
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_destroy
|
||||||
libc.src.pthread.pthread_mutex_init
|
libc.src.pthread.pthread_mutex_init
|
||||||
libc.src.pthread.pthread_mutex_lock
|
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_setpshared
|
||||||
libc.src.pthread.pthread_mutexattr_setrobust
|
libc.src.pthread.pthread_mutexattr_setrobust
|
||||||
libc.src.pthread.pthread_mutexattr_settype
|
libc.src.pthread.pthread_mutexattr_settype
|
||||||
|
libc.src.pthread.pthread_setspecific
|
||||||
|
|
||||||
# stdlib.h entrypoints
|
# stdlib.h entrypoints
|
||||||
libc.src.stdlib._Exit
|
libc.src.stdlib._Exit
|
||||||
|
@ -328,6 +332,10 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||||
libc.src.threads.thrd_equal
|
libc.src.threads.thrd_equal
|
||||||
libc.src.threads.thrd_exit
|
libc.src.threads.thrd_exit
|
||||||
libc.src.threads.thrd_join
|
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
|
# time.h entrypoints
|
||||||
libc.src.time.asctime
|
libc.src.time.asctime
|
||||||
|
|
|
@ -104,6 +104,8 @@ add_gen_header(
|
||||||
.llvm-libc-types.once_flag
|
.llvm-libc-types.once_flag
|
||||||
.llvm-libc-types.thrd_start_t
|
.llvm-libc-types.thrd_start_t
|
||||||
.llvm-libc-types.thrd_t
|
.llvm-libc-types.thrd_t
|
||||||
|
.llvm-libc-types.tss_t
|
||||||
|
.llvm-libc-types.tss_dtor_t
|
||||||
)
|
)
|
||||||
|
|
||||||
add_gen_header(
|
add_gen_header(
|
||||||
|
@ -174,7 +176,9 @@ add_gen_header(
|
||||||
DEPENDS
|
DEPENDS
|
||||||
.llvm_libc_common_h
|
.llvm_libc_common_h
|
||||||
.llvm-libc-types.__pthread_start_t
|
.llvm-libc-types.__pthread_start_t
|
||||||
|
.llvm-libc-types.__pthread_tss_dtor_t
|
||||||
.llvm-libc-types.pthread_attr_t
|
.llvm-libc-types.pthread_attr_t
|
||||||
|
.llvm-libc-types.pthread_key_t
|
||||||
.llvm-libc-types.pthread_mutex_t
|
.llvm-libc-types.pthread_mutex_t
|
||||||
.llvm-libc-types.pthread_mutexattr_t
|
.llvm-libc-types.pthread_mutexattr_t
|
||||||
.llvm-libc-types.pthread_t
|
.llvm-libc-types.pthread_t
|
||||||
|
|
|
@ -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(__futex_word HDR __futex_word.h)
|
||||||
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word)
|
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word)
|
||||||
add_header(__pthread_start_t HDR __pthread_start_t.h)
|
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(__qsortcompare_t HDR __qsortcompare_t.h)
|
||||||
add_header(__sighandler_t HDR __sighandler_t.h)
|
add_header(__sighandler_t HDR __sighandler_t.h)
|
||||||
add_header(__thread_type HDR __thread_type.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(off64_t HDR off64_t.h)
|
||||||
add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
|
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_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_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_t HDR pthread_t.h DEPENDS .__thread_type)
|
||||||
add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h)
|
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_start_t HDR thrd_start_t.h)
|
||||||
add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type)
|
add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type)
|
||||||
add_header(time_t HDR time_t.h)
|
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)
|
add_header(__atexithandler_t HDR __atexithandler_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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -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__
|
|
@ -11,6 +11,9 @@ def RestrictedStructSigactionPtr : RestrictedPtrType<StructSigaction>;
|
||||||
def ConstRestrictedStructSigactionPtr : ConstType<RestrictedStructSigactionPtr>;
|
def ConstRestrictedStructSigactionPtr : ConstType<RestrictedStructSigactionPtr>;
|
||||||
|
|
||||||
def PThreadStartT : NamedType<"__pthread_start_t">;
|
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 InoT : NamedType<"ino_t">;
|
||||||
def DIR : NamedType<"DIR">;
|
def DIR : NamedType<"DIR">;
|
||||||
|
@ -406,7 +409,15 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
HeaderSpec PThread = HeaderSpec<
|
HeaderSpec PThread = HeaderSpec<
|
||||||
"pthread.h",
|
"pthread.h",
|
||||||
[], // Macros
|
[], // Macros
|
||||||
[PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType, PThreadStartT, PThreadTType], // Types
|
[
|
||||||
|
PThreadAttrTType,
|
||||||
|
PThreadKeyT,
|
||||||
|
PThreadMutexAttrTType,
|
||||||
|
PThreadMutexTType,
|
||||||
|
PThreadStartT,
|
||||||
|
PThreadTSSDtorT,
|
||||||
|
PThreadTType,
|
||||||
|
], // Types
|
||||||
[], // Enumerations
|
[], // Enumerations
|
||||||
[
|
[
|
||||||
FunctionSpec<
|
FunctionSpec<
|
||||||
|
@ -569,6 +580,26 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
RetValSpec<IntType>,
|
RetValSpec<IntType>,
|
||||||
[ArgSpec<PThreadMutexTPtr>]
|
[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>]
|
||||||
|
>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,10 @@ def StdC : StandardSpec<"stdc"> {
|
||||||
NamedType LDivTType = NamedType<"ldiv_t">;
|
NamedType LDivTType = NamedType<"ldiv_t">;
|
||||||
NamedType LLDivTType = NamedType<"lldiv_t">;
|
NamedType LLDivTType = NamedType<"lldiv_t">;
|
||||||
|
|
||||||
|
NamedType TssTType = NamedType<"tss_t">;
|
||||||
|
PtrType TssTPtr = PtrType<TssTType>;
|
||||||
|
NamedType TssDtorTType = NamedType<"tss_dtor_t">;
|
||||||
|
|
||||||
HeaderSpec Assert = HeaderSpec<
|
HeaderSpec Assert = HeaderSpec<
|
||||||
"assert.h",
|
"assert.h",
|
||||||
[
|
[
|
||||||
|
@ -708,6 +712,8 @@ def StdC : StandardSpec<"stdc"> {
|
||||||
MtxTType,
|
MtxTType,
|
||||||
ThrdStartTType,
|
ThrdStartTType,
|
||||||
ThrdTType,
|
ThrdTType,
|
||||||
|
TssTType,
|
||||||
|
TssDtorTType,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
EnumeratedNameValue<"mtx_plain">,
|
EnumeratedNameValue<"mtx_plain">,
|
||||||
|
@ -830,6 +836,26 @@ def StdC : StandardSpec<"stdc"> {
|
||||||
RetValSpec<VoidType>,
|
RetValSpec<VoidType>,
|
||||||
[ArgSpec<IntType>]
|
[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>]
|
||||||
|
>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ add_header_library(
|
||||||
DEPENDS
|
DEPENDS
|
||||||
libc.src.__support.common
|
libc.src.__support.common
|
||||||
libc.src.__support.CPP.atomic
|
libc.src.__support.CPP.atomic
|
||||||
|
libc.src.__support.CPP.optional
|
||||||
libc.src.__support.CPP.string_view
|
libc.src.__support.CPP.string_view
|
||||||
libc.src.__support.CPP.stringstream
|
libc.src.__support.CPP.stringstream
|
||||||
)
|
)
|
||||||
|
@ -38,5 +39,7 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread)
|
||||||
.mutex
|
.mutex
|
||||||
.${LIBC_TARGET_OS}.thread
|
.${LIBC_TARGET_OS}.thread
|
||||||
libc.src.__support.fixedvector
|
libc.src.__support.fixedvector
|
||||||
|
libc.src.__support.CPP.array
|
||||||
|
libc.src.__support.CPP.optional
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
|
|
||||||
|
#include "src/__support/CPP/array.h"
|
||||||
|
#include "src/__support/CPP/optional.h"
|
||||||
#include "src/__support/fixedvector.h"
|
#include "src/__support/fixedvector.h"
|
||||||
|
|
||||||
namespace __llvm_libc {
|
namespace __llvm_libc {
|
||||||
|
@ -26,6 +28,79 @@ struct AtExitUnit {
|
||||||
constexpr AtExitUnit(AtExitCallback *cb, void *o) : callback(cb), obj(o) {}
|
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
|
} // anonymous namespace
|
||||||
|
|
||||||
class ThreadAtExitCallbackMgr {
|
class ThreadAtExitCallbackMgr {
|
||||||
|
@ -74,8 +149,36 @@ ThreadAtExitCallbackMgr *get_thread_atexit_callback_mgr() {
|
||||||
|
|
||||||
void call_atexit_callbacks(ThreadAttributes *attrib) {
|
void call_atexit_callbacks(ThreadAttributes *attrib) {
|
||||||
attrib->atexit_callback_mgr->call();
|
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
|
} // 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
|
} // namespace __llvm_libc
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "src/__support/CPP/StringView.h"
|
#include "src/__support/CPP/StringView.h"
|
||||||
#include "src/__support/CPP/atomic.h"
|
#include "src/__support/CPP/atomic.h"
|
||||||
|
#include "src/__support/CPP/optional.h"
|
||||||
#include "src/__support/CPP/stringstream.h"
|
#include "src/__support/CPP/stringstream.h"
|
||||||
#include "src/__support/architectures.h"
|
#include "src/__support/architectures.h"
|
||||||
|
|
||||||
|
@ -105,6 +106,30 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes {
|
||||||
platform_data(nullptr) {}
|
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 {
|
struct Thread {
|
||||||
ThreadAttributes *attrib;
|
ThreadAttributes *attrib;
|
||||||
|
|
||||||
|
|
|
@ -338,3 +338,51 @@ add_entrypoint_object(
|
||||||
libc.src.__support.CPP.stringstream
|
libc.src.__support.CPP.stringstream
|
||||||
libc.src.__support.threads.thread
|
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
|
||||||
|
)
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -123,6 +123,50 @@ add_entrypoint_object(
|
||||||
libc.src.__support.threads.mutex
|
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(
|
add_entrypoint_object(
|
||||||
cnd_init
|
cnd_init
|
||||||
ALIAS
|
ALIAS
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -91,3 +91,22 @@ add_integration_test(
|
||||||
libc.src.pthread.pthread_exit
|
libc.src.pthread.pthread_exit
|
||||||
libc.src.pthread.pthread_join
|
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
|
||||||
|
)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -69,6 +69,25 @@ add_integration_test(
|
||||||
libc.src.threads.thrd_join
|
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(
|
add_integration_test(
|
||||||
call_once_test
|
call_once_test
|
||||||
SUITE
|
SUITE
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue