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