1// -*- C++ -*- 2//===----------------------------------------------------------------------===// 3// 4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5// See https://llvm.org/LICENSE.txt for license information. 6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef _LIBCPP___THREADING_SUPPORT 11#define _LIBCPP___THREADING_SUPPORT 12 13#include <__availability> 14#include <__chrono/convert_to_timespec.h> 15#include <__chrono/duration.h> 16#include <__compare/ordering.h> 17#include <__config> 18#include <__fwd/hash.h> 19#include <__thread/poll_with_backoff.h> 20#include <errno.h> 21#include <iosfwd> 22#include <limits> 23 24#ifdef __MVS__ 25# include <__support/ibm/nanosleep.h> 26#endif 27 28#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER 29# pragma GCC system_header 30#endif 31 32#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) 33# include <__external_threading> 34#elif !defined(_LIBCPP_HAS_NO_THREADS) 35 36#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) 37# include <pthread.h> 38# include <sched.h> 39#elif defined(_LIBCPP_HAS_THREAD_API_C11) 40# include <threads.h> 41#endif 42 43#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ 44 defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL) || \ 45 defined(_LIBCPP_HAS_THREAD_API_WIN32) 46#define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS 47#else 48#define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY 49#endif 50 51#if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(no_thread_safety_analysis) 52#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis)) 53#else 54#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 55#endif 56 57typedef ::timespec __libcpp_timespec_t; 58#endif // !defined(_LIBCPP_HAS_NO_THREADS) 59 60_LIBCPP_BEGIN_NAMESPACE_STD 61 62#if !defined(_LIBCPP_HAS_NO_THREADS) 63 64#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) 65// Mutex 66typedef pthread_mutex_t __libcpp_mutex_t; 67#define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER 68 69typedef pthread_mutex_t __libcpp_recursive_mutex_t; 70 71// Condition Variable 72typedef pthread_cond_t __libcpp_condvar_t; 73#define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER 74 75// Execute once 76typedef pthread_once_t __libcpp_exec_once_flag; 77#define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT 78 79// Thread id 80#if defined(__MVS__) 81 typedef unsigned long long __libcpp_thread_id; 82#else 83 typedef pthread_t __libcpp_thread_id; 84#endif 85 86// Thread 87#define _LIBCPP_NULL_THREAD ((__libcpp_thread_t())) 88typedef pthread_t __libcpp_thread_t; 89 90// Thread Local Storage 91typedef pthread_key_t __libcpp_tls_key; 92 93#define _LIBCPP_TLS_DESTRUCTOR_CC 94#elif defined(_LIBCPP_HAS_THREAD_API_C11) 95// Mutex 96typedef mtx_t __libcpp_mutex_t; 97// mtx_t is a struct so using {} for initialization is valid. 98#define _LIBCPP_MUTEX_INITIALIZER {} 99 100typedef mtx_t __libcpp_recursive_mutex_t; 101 102// Condition Variable 103typedef cnd_t __libcpp_condvar_t; 104// cnd_t is a struct so using {} for initialization is valid. 105#define _LIBCPP_CONDVAR_INITIALIZER {} 106 107// Execute once 108typedef once_flag __libcpp_exec_once_flag; 109#define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT 110 111// Thread id 112typedef thrd_t __libcpp_thread_id; 113 114// Thread 115#define _LIBCPP_NULL_THREAD 0U 116 117typedef thrd_t __libcpp_thread_t; 118 119// Thread Local Storage 120typedef tss_t __libcpp_tls_key; 121 122#define _LIBCPP_TLS_DESTRUCTOR_CC 123#elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) 124// Mutex 125typedef void* __libcpp_mutex_t; 126#define _LIBCPP_MUTEX_INITIALIZER 0 127 128#if defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__arm__) 129typedef void* __libcpp_recursive_mutex_t[6]; 130#elif defined(_M_AMD64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__) 131typedef void* __libcpp_recursive_mutex_t[5]; 132#else 133# error Unsupported architecture 134#endif 135 136// Condition Variable 137typedef void* __libcpp_condvar_t; 138#define _LIBCPP_CONDVAR_INITIALIZER 0 139 140// Execute Once 141typedef void* __libcpp_exec_once_flag; 142#define _LIBCPP_EXEC_ONCE_INITIALIZER 0 143 144// Thread ID 145typedef long __libcpp_thread_id; 146 147// Thread 148#define _LIBCPP_NULL_THREAD 0U 149 150typedef void* __libcpp_thread_t; 151 152// Thread Local Storage 153typedef long __libcpp_tls_key; 154 155#define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall 156#endif // !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) 157 158#if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) 159// Mutex 160_LIBCPP_THREAD_ABI_VISIBILITY 161int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m); 162 163_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 164int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m); 165 166_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 167bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m); 168 169_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 170int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m); 171 172_LIBCPP_THREAD_ABI_VISIBILITY 173int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m); 174 175_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 176int __libcpp_mutex_lock(__libcpp_mutex_t *__m); 177 178_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 179bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m); 180 181_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 182int __libcpp_mutex_unlock(__libcpp_mutex_t *__m); 183 184_LIBCPP_THREAD_ABI_VISIBILITY 185int __libcpp_mutex_destroy(__libcpp_mutex_t *__m); 186 187// Condition variable 188_LIBCPP_THREAD_ABI_VISIBILITY 189int __libcpp_condvar_signal(__libcpp_condvar_t* __cv); 190 191_LIBCPP_THREAD_ABI_VISIBILITY 192int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv); 193 194_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 195int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m); 196 197_LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS 198int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, 199 __libcpp_timespec_t *__ts); 200 201_LIBCPP_THREAD_ABI_VISIBILITY 202int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv); 203 204// Execute once 205_LIBCPP_THREAD_ABI_VISIBILITY 206int __libcpp_execute_once(__libcpp_exec_once_flag *__flag, 207 void (*__init_routine)()); 208 209// Thread id 210_LIBCPP_THREAD_ABI_VISIBILITY 211bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2); 212 213_LIBCPP_THREAD_ABI_VISIBILITY 214bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2); 215 216// Thread 217_LIBCPP_THREAD_ABI_VISIBILITY 218bool __libcpp_thread_isnull(const __libcpp_thread_t *__t); 219 220_LIBCPP_THREAD_ABI_VISIBILITY 221int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), 222 void *__arg); 223 224_LIBCPP_THREAD_ABI_VISIBILITY 225__libcpp_thread_id __libcpp_thread_get_current_id(); 226 227_LIBCPP_THREAD_ABI_VISIBILITY 228__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t); 229 230_LIBCPP_THREAD_ABI_VISIBILITY 231int __libcpp_thread_join(__libcpp_thread_t *__t); 232 233_LIBCPP_THREAD_ABI_VISIBILITY 234int __libcpp_thread_detach(__libcpp_thread_t *__t); 235 236_LIBCPP_THREAD_ABI_VISIBILITY 237void __libcpp_thread_yield(); 238 239_LIBCPP_THREAD_ABI_VISIBILITY 240void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns); 241 242// Thread local storage 243_LIBCPP_THREAD_ABI_VISIBILITY 244int __libcpp_tls_create(__libcpp_tls_key* __key, 245 void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*)); 246 247_LIBCPP_THREAD_ABI_VISIBILITY 248void *__libcpp_tls_get(__libcpp_tls_key __key); 249 250_LIBCPP_THREAD_ABI_VISIBILITY 251int __libcpp_tls_set(__libcpp_tls_key __key, void *__p); 252 253#endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) 254 255#if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ 256 defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) 257 258#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) 259 260int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) 261{ 262 pthread_mutexattr_t attr; 263 int __ec = pthread_mutexattr_init(&attr); 264 if (__ec) 265 return __ec; 266 __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 267 if (__ec) { 268 pthread_mutexattr_destroy(&attr); 269 return __ec; 270 } 271 __ec = pthread_mutex_init(__m, &attr); 272 if (__ec) { 273 pthread_mutexattr_destroy(&attr); 274 return __ec; 275 } 276 __ec = pthread_mutexattr_destroy(&attr); 277 if (__ec) { 278 pthread_mutex_destroy(__m); 279 return __ec; 280 } 281 return 0; 282} 283 284int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) 285{ 286 return pthread_mutex_lock(__m); 287} 288 289bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) 290{ 291 return pthread_mutex_trylock(__m) == 0; 292} 293 294int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) 295{ 296 return pthread_mutex_unlock(__m); 297} 298 299int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) 300{ 301 return pthread_mutex_destroy(__m); 302} 303 304int __libcpp_mutex_lock(__libcpp_mutex_t *__m) 305{ 306 return pthread_mutex_lock(__m); 307} 308 309bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) 310{ 311 return pthread_mutex_trylock(__m) == 0; 312} 313 314int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) 315{ 316 return pthread_mutex_unlock(__m); 317} 318 319int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) 320{ 321 return pthread_mutex_destroy(__m); 322} 323 324// Condition Variable 325int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) 326{ 327 return pthread_cond_signal(__cv); 328} 329 330int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) 331{ 332 return pthread_cond_broadcast(__cv); 333} 334 335int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m) 336{ 337 return pthread_cond_wait(__cv, __m); 338} 339 340int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, 341 __libcpp_timespec_t *__ts) 342{ 343 return pthread_cond_timedwait(__cv, __m, __ts); 344} 345 346int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) 347{ 348 return pthread_cond_destroy(__cv); 349} 350 351// Execute once 352int __libcpp_execute_once(__libcpp_exec_once_flag *__flag, 353 void (*__init_routine)()) { 354 return pthread_once(__flag, __init_routine); 355} 356 357// Thread id 358// Returns non-zero if the thread ids are equal, otherwise 0 359bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) 360{ 361 return __t1 == __t2; 362} 363 364// Returns non-zero if t1 < t2, otherwise 0 365bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) 366{ 367 return __t1 < __t2; 368} 369 370// Thread 371bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { 372 return __libcpp_thread_get_id(__t) == 0; 373} 374 375int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), 376 void *__arg) 377{ 378 return pthread_create(__t, nullptr, __func, __arg); 379} 380 381__libcpp_thread_id __libcpp_thread_get_current_id() 382{ 383 const __libcpp_thread_t thread = pthread_self(); 384 return __libcpp_thread_get_id(&thread); 385} 386 387__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) 388{ 389#if defined(__MVS__) 390 return __t->__; 391#else 392 return *__t; 393#endif 394} 395 396int __libcpp_thread_join(__libcpp_thread_t *__t) 397{ 398 return pthread_join(*__t, nullptr); 399} 400 401int __libcpp_thread_detach(__libcpp_thread_t *__t) 402{ 403 return pthread_detach(*__t); 404} 405 406void __libcpp_thread_yield() 407{ 408 sched_yield(); 409} 410 411void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) 412{ 413 __libcpp_timespec_t __ts = _VSTD::__convert_to_timespec<__libcpp_timespec_t>(__ns); 414 while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR); 415} 416 417// Thread local storage 418int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *)) 419{ 420 return pthread_key_create(__key, __at_exit); 421} 422 423void *__libcpp_tls_get(__libcpp_tls_key __key) 424{ 425 return pthread_getspecific(__key); 426} 427 428int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) 429{ 430 return pthread_setspecific(__key, __p); 431} 432 433#elif defined(_LIBCPP_HAS_THREAD_API_C11) 434 435int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) 436{ 437 return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL; 438} 439 440int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) 441{ 442 return mtx_lock(__m) == thrd_success ? 0 : EINVAL; 443} 444 445bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) 446{ 447 return mtx_trylock(__m) == thrd_success; 448} 449 450int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) 451{ 452 return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; 453} 454 455int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) 456{ 457 mtx_destroy(__m); 458 return 0; 459} 460 461int __libcpp_mutex_lock(__libcpp_mutex_t *__m) 462{ 463 return mtx_lock(__m) == thrd_success ? 0 : EINVAL; 464} 465 466bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) 467{ 468 return mtx_trylock(__m) == thrd_success; 469} 470 471int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) 472{ 473 return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; 474} 475 476int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) 477{ 478 mtx_destroy(__m); 479 return 0; 480} 481 482// Condition Variable 483int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) 484{ 485 return cnd_signal(__cv) == thrd_success ? 0 : EINVAL; 486} 487 488int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) 489{ 490 return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL; 491} 492 493int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m) 494{ 495 return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL; 496} 497 498int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, 499 timespec *__ts) 500{ 501 int __ec = cnd_timedwait(__cv, __m, __ts); 502 return __ec == thrd_timedout ? ETIMEDOUT : __ec; 503} 504 505int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) 506{ 507 cnd_destroy(__cv); 508 return 0; 509} 510 511// Execute once 512int __libcpp_execute_once(__libcpp_exec_once_flag *flag, 513 void (*init_routine)(void)) { 514 ::call_once(flag, init_routine); 515 return 0; 516} 517 518// Thread id 519// Returns non-zero if the thread ids are equal, otherwise 0 520bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) 521{ 522 return thrd_equal(t1, t2) != 0; 523} 524 525// Returns non-zero if t1 < t2, otherwise 0 526bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) 527{ 528 return t1 < t2; 529} 530 531// Thread 532bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { 533 return __libcpp_thread_get_id(__t) == 0; 534} 535 536int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), 537 void *__arg) 538{ 539 int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg); 540 return __ec == thrd_nomem ? ENOMEM : __ec; 541} 542 543__libcpp_thread_id __libcpp_thread_get_current_id() 544{ 545 return thrd_current(); 546} 547 548__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) 549{ 550 return *__t; 551} 552 553int __libcpp_thread_join(__libcpp_thread_t *__t) 554{ 555 return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL; 556} 557 558int __libcpp_thread_detach(__libcpp_thread_t *__t) 559{ 560 return thrd_detach(*__t) == thrd_success ? 0 : EINVAL; 561} 562 563void __libcpp_thread_yield() 564{ 565 thrd_yield(); 566} 567 568void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) 569{ 570 __libcpp_timespec_t __ts = _VSTD::__convert_to_timespec<__libcpp_timespec_t>(__ns); 571 thrd_sleep(&__ts, nullptr); 572} 573 574// Thread local storage 575int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *)) 576{ 577 return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL; 578} 579 580void *__libcpp_tls_get(__libcpp_tls_key __key) 581{ 582 return tss_get(__key); 583} 584 585int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) 586{ 587 return tss_set(__key, __p) == thrd_success ? 0 : EINVAL; 588} 589 590#endif 591 592 593#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL 594 595class _LIBCPP_TYPE_VIS thread; 596class _LIBCPP_TYPE_VIS __thread_id; 597 598namespace this_thread 599{ 600 601_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; 602 603} // namespace this_thread 604 605template<> struct hash<__thread_id>; 606 607class _LIBCPP_TEMPLATE_VIS __thread_id 608{ 609 // FIXME: pthread_t is a pointer on Darwin but a long on Linux. 610 // NULL is the no-thread value on Darwin. Someone needs to check 611 // on other platforms. We assume 0 works everywhere for now. 612 __libcpp_thread_id __id_; 613 614 static _LIBCPP_HIDE_FROM_ABI 615 bool __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT 616 { // id==0 is always less than any other thread_id 617 if (__x.__id_ == 0) return __y.__id_ != 0; 618 if (__y.__id_ == 0) return false; 619 return __libcpp_thread_id_less(__x.__id_, __y.__id_); 620 } 621 622public: 623 _LIBCPP_INLINE_VISIBILITY 624 __thread_id() _NOEXCEPT : __id_(0) {} 625 626 _LIBCPP_INLINE_VISIBILITY 627 void __reset() { __id_ = 0; } 628 629 friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT; 630#if _LIBCPP_STD_VER <= 17 631 friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT; 632#else // _LIBCPP_STD_VER <= 17 633 friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept; 634#endif // _LIBCPP_STD_VER <= 17 635 636 template<class _CharT, class _Traits> 637 friend 638 _LIBCPP_INLINE_VISIBILITY 639 basic_ostream<_CharT, _Traits>& 640 operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id); 641 642private: 643 _LIBCPP_INLINE_VISIBILITY 644 __thread_id(__libcpp_thread_id __id) : __id_(__id) {} 645 646 friend __thread_id this_thread::get_id() _NOEXCEPT; 647 friend class _LIBCPP_TYPE_VIS thread; 648 friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>; 649}; 650 651inline _LIBCPP_HIDE_FROM_ABI 652bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT { 653 // Don't pass id==0 to underlying routines 654 if (__x.__id_ == 0) 655 return __y.__id_ == 0; 656 if (__y.__id_ == 0) 657 return false; 658 return __libcpp_thread_id_equal(__x.__id_, __y.__id_); 659} 660 661#if _LIBCPP_STD_VER <= 17 662 663inline _LIBCPP_HIDE_FROM_ABI 664bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT { 665 return !(__x == __y); 666} 667 668inline _LIBCPP_HIDE_FROM_ABI 669bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT { 670 return __thread_id::__lt_impl(__x.__id_, __y.__id_); 671} 672 673inline _LIBCPP_HIDE_FROM_ABI bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__y < __x); } 674inline _LIBCPP_HIDE_FROM_ABI bool operator>(__thread_id __x, __thread_id __y) _NOEXCEPT { return __y < __x; } 675inline _LIBCPP_HIDE_FROM_ABI bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT { return !(__x < __y); } 676 677#else // _LIBCPP_STD_VER <= 17 678 679inline _LIBCPP_HIDE_FROM_ABI 680strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept { 681 if (__x == __y) 682 return strong_ordering::equal; 683 if (__thread_id::__lt_impl(__x, __y)) 684 return strong_ordering::less; 685 return strong_ordering::greater; 686} 687 688#endif // _LIBCPP_STD_VER <= 17 689 690namespace this_thread 691{ 692 693inline _LIBCPP_INLINE_VISIBILITY 694__thread_id 695get_id() _NOEXCEPT 696{ 697 return __libcpp_thread_get_current_id(); 698} 699 700} // namespace this_thread 701 702#endif // !_LIBCPP_HAS_NO_THREADS 703 704_LIBCPP_END_NAMESPACE_STD 705 706#endif // _LIBCPP___THREADING_SUPPORT 707