[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:
Siva Chandra Reddy 2022-08-09 20:40:53 +00:00
parent 12e1936f64
commit 4a738ee822
35 changed files with 878 additions and 1 deletions

View File

@ -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",
]; ];
} }

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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__

View File

@ -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__

View File

@ -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__

View File

@ -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__

View File

@ -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>]
>,
] ]
>; >;

View File

@ -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>]
>,
] ]
>; >;

View File

@ -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()

View File

@ -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

View File

@ -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;

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
)

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}