The headers that include_next compiler and OS headers need to be in different top level modules in order to avoid module cycles. e.g. libc++'s stdlib.h will #include_next stdlib.h from the compiler and then the C library. Either of those are likely to include stddef.h, which will come back up to the libc++ module map and create a module cycle. Putting stdlib.h and stddef.h (and the rest of the C standard library headers) in top level modules resolves this by letting the order go cxx_stdlib_h -> os_stdlib_h -> cxx_stddef_h -> os_stddef_h. All of those headers' dependencies then need to be moved into top level modules themselves to avoid module cycles between the new top level level cstd modules. This starts to get complicated, as the libc++ C headers, by standard, have to include many of the C++ headers, which include the private detail headers, which are intertwined. e.g. some `__algorithm` headers include `__memory` headers and vice versa. Make top level modules for all of the libc++ headers to easily guarantee that the modules aren't cyclic. Add enough module exports to fix `check-cxx` and `run-buildbot generic-modules`. `__stop_token/intrusive_shared_ptr.h` uses `__atomic/atomic.h` but has no include path to it. Add that include. `math.h` absorbs `bits/atomic_wide_counter.h` on some platforms that don't have modules, work around that by including `math.h` in `__threading_support`. <mutex> doesn't actually require threads, there are a few pieces like once_flag that work without threads. Remove the requirement from its module. AIX is no longer able to support modular builds. Reviewed By: ldionne, #libc Differential Revision: https://reviews.llvm.org/D144322
590 lines
15 KiB
C++
590 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)
|
|
// Some platforms require <bits/atomic_wide_counter.h> in order for
|
|
// PTHREAD_COND_INITIALIZER to be expanded. Normally that would come
|
|
// in via <pthread.h>, but it's a non-modular header on those platforms,
|
|
// so libc++'s <math.h> usually absorbs atomic_wide_counter.h into the
|
|
// module with <math.h> and makes atomic_wide_counter.h invisible.
|
|
// Include <math.h> here to work around that.
|
|
# include <math.h>
|
|
|
|
# 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
|
|
|
|
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
|