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