
Since stacktrace header is WIP and it's not sure that will be done before LLVM17 update the documentation. When the header is implemented implementing the formatter is trivial, so that can be done quickly afterwards. Implements parts of: - P2693R1 Formatting thread::id and stacktrace Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D144331
709 lines
18 KiB
C++
709 lines
18 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 <__compare/ordering.h>
|
|
#include <__config>
|
|
#include <__fwd/hash.h>
|
|
#include <__thread/poll_with_backoff.h>
|
|
#include <errno.h>
|
|
#include <iosfwd>
|
|
#include <limits>
|
|
|
|
#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_LIBRARY_EXTERNAL) || \
|
|
defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL) || \
|
|
defined(_LIBCPP_HAS_THREAD_API_WIN32)
|
|
#define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS
|
|
#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_LIBRARY_EXTERNAL) || \
|
|
defined(_LIBCPP_BUILDING_THREAD_LIBRARY_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_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
|
|
|
|
class _LIBCPP_TYPE_VIS thread;
|
|
class _LIBCPP_TYPE_VIS __thread_id;
|
|
|
|
namespace this_thread
|
|
{
|
|
|
|
_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT;
|
|
|
|
} // namespace this_thread
|
|
|
|
template<> struct hash<__thread_id>;
|
|
|
|
class _LIBCPP_TEMPLATE_VIS __thread_id
|
|
{
|
|
// FIXME: pthread_t is a pointer on Darwin but a long on Linux.
|
|
// NULL is the no-thread value on Darwin. Someone needs to check
|
|
// on other platforms. We assume 0 works everywhere for now.
|
|
__libcpp_thread_id __id_;
|
|
|
|
static _LIBCPP_HIDE_FROM_ABI
|
|
bool __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT
|
|
{ // id==0 is always less than any other thread_id
|
|
if (__x.__id_ == 0) return __y.__id_ != 0;
|
|
if (__y.__id_ == 0) return false;
|
|
return __libcpp_thread_id_less(__x.__id_, __y.__id_);
|
|
}
|
|
|
|
public:
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
__thread_id() _NOEXCEPT : __id_(0) {}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void __reset() { __id_ = 0; }
|
|
|
|
friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
|
|
#if _LIBCPP_STD_VER <= 17
|
|
friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT;
|
|
#else // _LIBCPP_STD_VER <= 17
|
|
friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept;
|
|
#endif // _LIBCPP_STD_VER <= 17
|
|
|
|
template<class _CharT, class _Traits>
|
|
friend
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
basic_ostream<_CharT, _Traits>&
|
|
operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id);
|
|
|
|
private:
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
__thread_id(__libcpp_thread_id __id) : __id_(__id) {}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI friend __libcpp_thread_id __get_underlying_id(const __thread_id __id) { return __id.__id_; }
|
|
|
|
friend __thread_id this_thread::get_id() _NOEXCEPT;
|
|
friend class _LIBCPP_TYPE_VIS thread;
|
|
friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>;
|
|
};
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
|
bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
|
|
// Don't pass id==0 to underlying routines
|
|
if (__x.__id_ == 0)
|
|
return __y.__id_ == 0;
|
|
if (__y.__id_ == 0)
|
|
return false;
|
|
return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
|
|
}
|
|
|
|
#if _LIBCPP_STD_VER <= 17
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
|
bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT {
|
|
return !(__x == __y);
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
|
bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT {
|
|
return __thread_id::__lt_impl(__x.__id_, __y.__id_);
|
|
}
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__y < __x); }
|
|
inline _LIBCPP_HIDE_FROM_ABI bool operator>(__thread_id __x, __thread_id __y) _NOEXCEPT { return __y < __x; }
|
|
inline _LIBCPP_HIDE_FROM_ABI bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__x < __y); }
|
|
|
|
#else // _LIBCPP_STD_VER <= 17
|
|
|
|
inline _LIBCPP_HIDE_FROM_ABI
|
|
strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept {
|
|
if (__x == __y)
|
|
return strong_ordering::equal;
|
|
if (__thread_id::__lt_impl(__x, __y))
|
|
return strong_ordering::less;
|
|
return strong_ordering::greater;
|
|
}
|
|
|
|
#endif // _LIBCPP_STD_VER <= 17
|
|
|
|
namespace this_thread
|
|
{
|
|
|
|
inline _LIBCPP_INLINE_VISIBILITY
|
|
__thread_id
|
|
get_id() _NOEXCEPT
|
|
{
|
|
return __libcpp_thread_get_current_id();
|
|
}
|
|
|
|
} // namespace this_thread
|
|
|
|
#endif // !_LIBCPP_HAS_NO_THREADS
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // _LIBCPP___THREADING_SUPPORT
|