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