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