Our threading support layer is currently a huge mess. There are too many configurations with too many confusing names, and none of them are tested in the usual CI. Here's a list of names related to these configurations: LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL LIBCXX_HAS_EXTERNAL_THREAD_API _LIBCPP_HAS_THREAD_API_EXTERNAL This patch cleans this up by removing the ability to build libc++ with an "external" threading library for testing purposes, removing 4 out of 6 "names" above. That setting was meant to be used by libc++ developers, but we don't use it in-tree and it's not part of our CI. I know the ability to use an external threading API is used by some folks out-of-tree, and this patch doesn't change that. This only changes the way they will have to test their external threading support. After this patch, the intent would be for them to set `-DLIBCXX_HAS_EXTERNAL_THREAD_API=ON` when building the library, and to provide their usual `<__external_threading>` header when they are testing the library. This can be done easily now that we support custom lit configuration files in test suites. The motivation for this patch is that our threading support layer is basically unmaintainable -- anything beyond adding a new "backend" in the slot designed for it requires incredible attention. The complexity added by this setting just doesn't pull its weigh considering the available alternatives. Concretely, this will also allow future patches to clean up `<__threading_support>` significantly. Differential Revision: https://reviews.llvm.org/D154466
588 lines
15 KiB
C++
588 lines
15 KiB
C++
// -*- 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 _LIBCPP___THREADING_SUPPORT
|
|
#define _LIBCPP___THREADING_SUPPORT
|
|
|
|
#include <__availability>
|
|
#include <__chrono/convert_to_timespec.h>
|
|
#include <__chrono/duration.h>
|
|
#include <__config>
|
|
#include <__thread/poll_with_backoff.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef __MVS__
|
|
# include <__support/ibm/nanosleep.h>
|
|
#endif
|
|
|
|
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
|
|
# include <__external_threading>
|
|
#elif !defined(_LIBCPP_HAS_NO_THREADS)
|
|
|
|
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
|
# include <pthread.h>
|
|
# include <sched.h>
|
|
#elif defined(_LIBCPP_HAS_THREAD_API_C11)
|
|
# include <threads.h>
|
|
#endif
|
|
|
|
#if defined(_LIBCPP_HAS_THREAD_API_WIN32)
|
|
#define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_EXPORTED_FROM_ABI
|
|
#else
|
|
#define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
|
|
#endif
|
|
|
|
#if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(no_thread_safety_analysis)
|
|
#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
|
|
#else
|
|
#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
#endif
|
|
|
|
typedef ::timespec __libcpp_timespec_t;
|
|
#endif // !defined(_LIBCPP_HAS_NO_THREADS)
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_THREADS)
|
|
|
|
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
|
// Mutex
|
|
typedef pthread_mutex_t __libcpp_mutex_t;
|
|
#define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
|
|
|
typedef pthread_mutex_t __libcpp_recursive_mutex_t;
|
|
|
|
// Condition Variable
|
|
typedef pthread_cond_t __libcpp_condvar_t;
|
|
#define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
|
|
|
|
// Execute once
|
|
typedef pthread_once_t __libcpp_exec_once_flag;
|
|
#define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
|
|
|
|
// Thread id
|
|
#if defined(__MVS__)
|
|
typedef unsigned long long __libcpp_thread_id;
|
|
#else
|
|
typedef pthread_t __libcpp_thread_id;
|
|
#endif
|
|
|
|
// Thread
|
|
#define _LIBCPP_NULL_THREAD ((__libcpp_thread_t()))
|
|
typedef pthread_t __libcpp_thread_t;
|
|
|
|
// Thread Local Storage
|
|
typedef pthread_key_t __libcpp_tls_key;
|
|
|
|
#define _LIBCPP_TLS_DESTRUCTOR_CC
|
|
#elif defined(_LIBCPP_HAS_THREAD_API_C11)
|
|
// Mutex
|
|
typedef mtx_t __libcpp_mutex_t;
|
|
// mtx_t is a struct so using {} for initialization is valid.
|
|
#define _LIBCPP_MUTEX_INITIALIZER {}
|
|
|
|
typedef mtx_t __libcpp_recursive_mutex_t;
|
|
|
|
// Condition Variable
|
|
typedef cnd_t __libcpp_condvar_t;
|
|
// cnd_t is a struct so using {} for initialization is valid.
|
|
#define _LIBCPP_CONDVAR_INITIALIZER {}
|
|
|
|
// Execute once
|
|
typedef once_flag __libcpp_exec_once_flag;
|
|
#define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT
|
|
|
|
// Thread id
|
|
typedef thrd_t __libcpp_thread_id;
|
|
|
|
// Thread
|
|
#define _LIBCPP_NULL_THREAD 0U
|
|
|
|
typedef thrd_t __libcpp_thread_t;
|
|
|
|
// Thread Local Storage
|
|
typedef tss_t __libcpp_tls_key;
|
|
|
|
#define _LIBCPP_TLS_DESTRUCTOR_CC
|
|
#elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
|
|
// Mutex
|
|
typedef void* __libcpp_mutex_t;
|
|
#define _LIBCPP_MUTEX_INITIALIZER 0
|
|
|
|
#if defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__arm__)
|
|
typedef void* __libcpp_recursive_mutex_t[6];
|
|
#elif defined(_M_AMD64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__)
|
|
typedef void* __libcpp_recursive_mutex_t[5];
|
|
#else
|
|
# error Unsupported architecture
|
|
#endif
|
|
|
|
// Condition Variable
|
|
typedef void* __libcpp_condvar_t;
|
|
#define _LIBCPP_CONDVAR_INITIALIZER 0
|
|
|
|
// Execute Once
|
|
typedef void* __libcpp_exec_once_flag;
|
|
#define _LIBCPP_EXEC_ONCE_INITIALIZER 0
|
|
|
|
// Thread ID
|
|
typedef long __libcpp_thread_id;
|
|
|
|
// Thread
|
|
#define _LIBCPP_NULL_THREAD 0U
|
|
|
|
typedef void* __libcpp_thread_t;
|
|
|
|
// Thread Local Storage
|
|
typedef long __libcpp_tls_key;
|
|
|
|
#define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall
|
|
#endif // !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
|
|
|
|
#if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
|
|
// Mutex
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
int __libcpp_mutex_lock(__libcpp_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
int __libcpp_mutex_unlock(__libcpp_mutex_t *__m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_mutex_destroy(__libcpp_mutex_t *__m);
|
|
|
|
// Condition variable
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
|
|
int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
|
|
__libcpp_timespec_t *__ts);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
|
|
|
|
// Execute once
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
|
|
void (*__init_routine)());
|
|
|
|
// Thread id
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2);
|
|
|
|
// Thread
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
bool __libcpp_thread_isnull(const __libcpp_thread_t *__t);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
|
|
void *__arg);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
__libcpp_thread_id __libcpp_thread_get_current_id();
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_thread_join(__libcpp_thread_t *__t);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_thread_detach(__libcpp_thread_t *__t);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
void __libcpp_thread_yield();
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns);
|
|
|
|
// Thread local storage
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_tls_create(__libcpp_tls_key* __key,
|
|
void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
void *__libcpp_tls_get(__libcpp_tls_key __key);
|
|
|
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
|
int __libcpp_tls_set(__libcpp_tls_key __key, void *__p);
|
|
|
|
#endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
|
|
|
|
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
|
|
|
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
pthread_mutexattr_t __attr;
|
|
int __ec = pthread_mutexattr_init(&__attr);
|
|
if (__ec)
|
|
return __ec;
|
|
__ec = pthread_mutexattr_settype(&__attr, PTHREAD_MUTEX_RECURSIVE);
|
|
if (__ec) {
|
|
pthread_mutexattr_destroy(&__attr);
|
|
return __ec;
|
|
}
|
|
__ec = pthread_mutex_init(__m, &__attr);
|
|
if (__ec) {
|
|
pthread_mutexattr_destroy(&__attr);
|
|
return __ec;
|
|
}
|
|
__ec = pthread_mutexattr_destroy(&__attr);
|
|
if (__ec) {
|
|
pthread_mutex_destroy(__m);
|
|
return __ec;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_lock(__m);
|
|
}
|
|
|
|
bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_trylock(__m) == 0;
|
|
}
|
|
|
|
int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_unlock(__m);
|
|
}
|
|
|
|
int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_destroy(__m);
|
|
}
|
|
|
|
int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_lock(__m);
|
|
}
|
|
|
|
bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_trylock(__m) == 0;
|
|
}
|
|
|
|
int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_unlock(__m);
|
|
}
|
|
|
|
int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
|
|
{
|
|
return pthread_mutex_destroy(__m);
|
|
}
|
|
|
|
// Condition Variable
|
|
int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
|
|
{
|
|
return pthread_cond_signal(__cv);
|
|
}
|
|
|
|
int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
|
|
{
|
|
return pthread_cond_broadcast(__cv);
|
|
}
|
|
|
|
int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
|
|
{
|
|
return pthread_cond_wait(__cv, __m);
|
|
}
|
|
|
|
int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
|
|
__libcpp_timespec_t *__ts)
|
|
{
|
|
return pthread_cond_timedwait(__cv, __m, __ts);
|
|
}
|
|
|
|
int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
|
|
{
|
|
return pthread_cond_destroy(__cv);
|
|
}
|
|
|
|
// Execute once
|
|
int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
|
|
void (*__init_routine)()) {
|
|
return pthread_once(__flag, __init_routine);
|
|
}
|
|
|
|
// Thread id
|
|
// Returns non-zero if the thread ids are equal, otherwise 0
|
|
bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2)
|
|
{
|
|
return __t1 == __t2;
|
|
}
|
|
|
|
// Returns non-zero if t1 < t2, otherwise 0
|
|
bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2)
|
|
{
|
|
return __t1 < __t2;
|
|
}
|
|
|
|
// Thread
|
|
bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
|
|
return __libcpp_thread_get_id(__t) == 0;
|
|
}
|
|
|
|
int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
|
|
void *__arg)
|
|
{
|
|
return pthread_create(__t, nullptr, __func, __arg);
|
|
}
|
|
|
|
__libcpp_thread_id __libcpp_thread_get_current_id()
|
|
{
|
|
const __libcpp_thread_t __current_thread = pthread_self();
|
|
return __libcpp_thread_get_id(&__current_thread);
|
|
}
|
|
|
|
__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
|
|
{
|
|
#if defined(__MVS__)
|
|
return __t->__;
|
|
#else
|
|
return *__t;
|
|
#endif
|
|
}
|
|
|
|
int __libcpp_thread_join(__libcpp_thread_t *__t)
|
|
{
|
|
return pthread_join(*__t, nullptr);
|
|
}
|
|
|
|
int __libcpp_thread_detach(__libcpp_thread_t *__t)
|
|
{
|
|
return pthread_detach(*__t);
|
|
}
|
|
|
|
void __libcpp_thread_yield()
|
|
{
|
|
sched_yield();
|
|
}
|
|
|
|
void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
|
|
{
|
|
__libcpp_timespec_t __ts = _VSTD::__convert_to_timespec<__libcpp_timespec_t>(__ns);
|
|
while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR);
|
|
}
|
|
|
|
// Thread local storage
|
|
int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
|
|
{
|
|
return pthread_key_create(__key, __at_exit);
|
|
}
|
|
|
|
void *__libcpp_tls_get(__libcpp_tls_key __key)
|
|
{
|
|
return pthread_getspecific(__key);
|
|
}
|
|
|
|
int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
|
|
{
|
|
return pthread_setspecific(__key, __p);
|
|
}
|
|
|
|
#elif defined(_LIBCPP_HAS_THREAD_API_C11)
|
|
|
|
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return mtx_trylock(__m) == thrd_success;
|
|
}
|
|
|
|
int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
|
|
{
|
|
mtx_destroy(__m);
|
|
return 0;
|
|
}
|
|
|
|
int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
|
|
{
|
|
return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
|
|
{
|
|
return mtx_trylock(__m) == thrd_success;
|
|
}
|
|
|
|
int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
|
|
{
|
|
return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
|
|
{
|
|
mtx_destroy(__m);
|
|
return 0;
|
|
}
|
|
|
|
// Condition Variable
|
|
int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
|
|
{
|
|
return cnd_signal(__cv) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
|
|
{
|
|
return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
|
|
{
|
|
return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
|
|
timespec *__ts)
|
|
{
|
|
int __ec = cnd_timedwait(__cv, __m, __ts);
|
|
return __ec == thrd_timedout ? ETIMEDOUT : __ec;
|
|
}
|
|
|
|
int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
|
|
{
|
|
cnd_destroy(__cv);
|
|
return 0;
|
|
}
|
|
|
|
// Execute once
|
|
int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
|
|
void (*init_routine)(void)) {
|
|
::call_once(flag, init_routine);
|
|
return 0;
|
|
}
|
|
|
|
// Thread id
|
|
// Returns non-zero if the thread ids are equal, otherwise 0
|
|
bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2)
|
|
{
|
|
return thrd_equal(t1, t2) != 0;
|
|
}
|
|
|
|
// Returns non-zero if t1 < t2, otherwise 0
|
|
bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2)
|
|
{
|
|
return t1 < t2;
|
|
}
|
|
|
|
// Thread
|
|
bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
|
|
return __libcpp_thread_get_id(__t) == 0;
|
|
}
|
|
|
|
int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
|
|
void *__arg)
|
|
{
|
|
int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg);
|
|
return __ec == thrd_nomem ? ENOMEM : __ec;
|
|
}
|
|
|
|
__libcpp_thread_id __libcpp_thread_get_current_id()
|
|
{
|
|
return thrd_current();
|
|
}
|
|
|
|
__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
|
|
{
|
|
return *__t;
|
|
}
|
|
|
|
int __libcpp_thread_join(__libcpp_thread_t *__t)
|
|
{
|
|
return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
int __libcpp_thread_detach(__libcpp_thread_t *__t)
|
|
{
|
|
return thrd_detach(*__t) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
void __libcpp_thread_yield()
|
|
{
|
|
thrd_yield();
|
|
}
|
|
|
|
void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
|
|
{
|
|
__libcpp_timespec_t __ts = _VSTD::__convert_to_timespec<__libcpp_timespec_t>(__ns);
|
|
thrd_sleep(&__ts, nullptr);
|
|
}
|
|
|
|
// Thread local storage
|
|
int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
|
|
{
|
|
return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
void *__libcpp_tls_get(__libcpp_tls_key __key)
|
|
{
|
|
return tss_get(__key);
|
|
}
|
|
|
|
int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
|
|
{
|
|
return tss_set(__key, __p) == thrd_success ? 0 : EINVAL;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif // !_LIBCPP_HAS_NO_THREADS
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // _LIBCPP___THREADING_SUPPORT
|