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