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 <__config>
15#include <__thread/poll_with_backoff.h>
16#include <chrono>
17#include <errno.h>
18#include <iosfwd>
19#include <limits>
20
21#ifdef __MVS__
22# include <__support/ibm/nanosleep.h>
23#endif
24
25#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
26#pragma GCC system_header
27#endif
28
29#if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
30# include <__external_threading>
31#elif !defined(_LIBCPP_HAS_NO_THREADS)
32
33#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
34# include <pthread.h>
35# include <sched.h>
36#elif defined(_LIBCPP_HAS_THREAD_API_C11)
37# include <threads.h>
38#endif
39
40#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
41    defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL) || \
42    defined(_LIBCPP_HAS_THREAD_API_WIN32)
43#define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS
44#else
45#define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
46#endif
47
48#if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(no_thread_safety_analysis)
49#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
50#else
51#define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
52#endif
53
54typedef ::timespec __libcpp_timespec_t;
55#endif // !defined(_LIBCPP_HAS_NO_THREADS)
56
57_LIBCPP_PUSH_MACROS
58#include <__undef_macros>
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
255struct __libcpp_timed_backoff_policy {
256  _LIBCPP_INLINE_VISIBILITY
257  bool operator()(chrono::nanoseconds __elapsed) const
258  {
259      if(__elapsed > chrono::milliseconds(128))
260          __libcpp_thread_sleep_for(chrono::milliseconds(8));
261      else if(__elapsed > chrono::microseconds(64))
262          __libcpp_thread_sleep_for(__elapsed / 2);
263      else if(__elapsed > chrono::microseconds(4))
264        __libcpp_thread_yield();
265      else
266        {} // poll
267      return false;
268  }
269};
270
271#if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
272     defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL))
273
274
275namespace __thread_detail {
276
277inline __libcpp_timespec_t __convert_to_timespec(const chrono::nanoseconds& __ns)
278{
279  using namespace chrono;
280  seconds __s = duration_cast<seconds>(__ns);
281  __libcpp_timespec_t __ts;
282  typedef decltype(__ts.tv_sec) __ts_sec;
283  const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
284
285  if (__s.count() < __ts_sec_max)
286  {
287    __ts.tv_sec = static_cast<__ts_sec>(__s.count());
288    __ts.tv_nsec = static_cast<decltype(__ts.tv_nsec)>((__ns - __s).count());
289  }
290  else
291  {
292    __ts.tv_sec = __ts_sec_max;
293    __ts.tv_nsec = 999999999; // (10^9 - 1)
294  }
295
296  return __ts;
297}
298
299} // namespace __thread_detail
300
301#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
302
303int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
304{
305  pthread_mutexattr_t attr;
306  int __ec = pthread_mutexattr_init(&attr);
307  if (__ec)
308    return __ec;
309  __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
310  if (__ec) {
311    pthread_mutexattr_destroy(&attr);
312    return __ec;
313  }
314  __ec = pthread_mutex_init(__m, &attr);
315  if (__ec) {
316    pthread_mutexattr_destroy(&attr);
317    return __ec;
318  }
319  __ec = pthread_mutexattr_destroy(&attr);
320  if (__ec) {
321    pthread_mutex_destroy(__m);
322    return __ec;
323  }
324  return 0;
325}
326
327int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
328{
329  return pthread_mutex_lock(__m);
330}
331
332bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
333{
334  return pthread_mutex_trylock(__m) == 0;
335}
336
337int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
338{
339  return pthread_mutex_unlock(__m);
340}
341
342int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
343{
344  return pthread_mutex_destroy(__m);
345}
346
347int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
348{
349  return pthread_mutex_lock(__m);
350}
351
352bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
353{
354  return pthread_mutex_trylock(__m) == 0;
355}
356
357int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
358{
359  return pthread_mutex_unlock(__m);
360}
361
362int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
363{
364  return pthread_mutex_destroy(__m);
365}
366
367// Condition Variable
368int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
369{
370  return pthread_cond_signal(__cv);
371}
372
373int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
374{
375  return pthread_cond_broadcast(__cv);
376}
377
378int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
379{
380  return pthread_cond_wait(__cv, __m);
381}
382
383int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
384                               __libcpp_timespec_t *__ts)
385{
386  return pthread_cond_timedwait(__cv, __m, __ts);
387}
388
389int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
390{
391  return pthread_cond_destroy(__cv);
392}
393
394// Execute once
395int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
396                          void (*init_routine)()) {
397  return pthread_once(flag, init_routine);
398}
399
400// Thread id
401// Returns non-zero if the thread ids are equal, otherwise 0
402bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2)
403{
404  return t1 == t2;
405}
406
407// Returns non-zero if t1 < t2, otherwise 0
408bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2)
409{
410  return t1 < t2;
411}
412
413// Thread
414bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
415  return __libcpp_thread_get_id(__t) == 0;
416}
417
418int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
419                           void *__arg)
420{
421  return pthread_create(__t, nullptr, __func, __arg);
422}
423
424__libcpp_thread_id __libcpp_thread_get_current_id()
425{
426  const __libcpp_thread_t thread = pthread_self();
427  return __libcpp_thread_get_id(&thread);
428}
429
430__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
431{
432#if defined(__MVS__)
433  return __t->__;
434#else
435  return *__t;
436#endif
437}
438
439int __libcpp_thread_join(__libcpp_thread_t *__t)
440{
441  return pthread_join(*__t, nullptr);
442}
443
444int __libcpp_thread_detach(__libcpp_thread_t *__t)
445{
446  return pthread_detach(*__t);
447}
448
449void __libcpp_thread_yield()
450{
451  sched_yield();
452}
453
454void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
455{
456   __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns);
457   while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR);
458}
459
460// Thread local storage
461int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
462{
463  return pthread_key_create(__key, __at_exit);
464}
465
466void *__libcpp_tls_get(__libcpp_tls_key __key)
467{
468  return pthread_getspecific(__key);
469}
470
471int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
472{
473    return pthread_setspecific(__key, __p);
474}
475
476#elif defined(_LIBCPP_HAS_THREAD_API_C11)
477
478int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
479{
480  return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL;
481}
482
483int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
484{
485  return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
486}
487
488bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
489{
490  return mtx_trylock(__m) == thrd_success;
491}
492
493int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
494{
495  return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
496}
497
498int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
499{
500  mtx_destroy(__m);
501  return 0;
502}
503
504int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
505{
506  return mtx_lock(__m) == thrd_success ? 0 : EINVAL;
507}
508
509bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
510{
511  return mtx_trylock(__m) == thrd_success;
512}
513
514int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
515{
516  return mtx_unlock(__m) == thrd_success ? 0 : EINVAL;
517}
518
519int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
520{
521  mtx_destroy(__m);
522  return 0;
523}
524
525// Condition Variable
526int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
527{
528  return cnd_signal(__cv) == thrd_success ? 0 : EINVAL;
529}
530
531int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
532{
533  return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL;
534}
535
536int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
537{
538  return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL;
539}
540
541int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
542                               timespec *__ts)
543{
544  int __ec = cnd_timedwait(__cv, __m, __ts);
545  return __ec == thrd_timedout ? ETIMEDOUT : __ec;
546}
547
548int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
549{
550  cnd_destroy(__cv);
551  return 0;
552}
553
554// Execute once
555int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
556                          void (*init_routine)(void)) {
557  ::call_once(flag, init_routine);
558  return 0;
559}
560
561// Thread id
562// Returns non-zero if the thread ids are equal, otherwise 0
563bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2)
564{
565  return thrd_equal(t1, t2) != 0;
566}
567
568// Returns non-zero if t1 < t2, otherwise 0
569bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2)
570{
571  return t1 < t2;
572}
573
574// Thread
575bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
576  return __libcpp_thread_get_id(__t) == 0;
577}
578
579int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
580                           void *__arg)
581{
582  int __ec = thrd_create(__t, reinterpret_cast<thrd_start_t>(__func), __arg);
583  return __ec == thrd_nomem ? ENOMEM : __ec;
584}
585
586__libcpp_thread_id __libcpp_thread_get_current_id()
587{
588  return thrd_current();
589}
590
591__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
592{
593  return *__t;
594}
595
596int __libcpp_thread_join(__libcpp_thread_t *__t)
597{
598  return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL;
599}
600
601int __libcpp_thread_detach(__libcpp_thread_t *__t)
602{
603  return thrd_detach(*__t) == thrd_success ? 0 : EINVAL;
604}
605
606void __libcpp_thread_yield()
607{
608  thrd_yield();
609}
610
611void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
612{
613   __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns);
614  thrd_sleep(&__ts, nullptr);
615}
616
617// Thread local storage
618int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
619{
620  return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL;
621}
622
623void *__libcpp_tls_get(__libcpp_tls_key __key)
624{
625  return tss_get(__key);
626}
627
628int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
629{
630  return tss_set(__key, __p) == thrd_success ? 0 : EINVAL;
631}
632
633#endif
634
635
636#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
637
638class _LIBCPP_TYPE_VIS thread;
639class _LIBCPP_TYPE_VIS __thread_id;
640
641namespace this_thread
642{
643
644_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT;
645
646} // namespace this_thread
647
648template<> struct hash<__thread_id>;
649
650class _LIBCPP_TEMPLATE_VIS __thread_id
651{
652    // FIXME: pthread_t is a pointer on Darwin but a long on Linux.
653    // NULL is the no-thread value on Darwin.  Someone needs to check
654    // on other platforms.  We assume 0 works everywhere for now.
655    __libcpp_thread_id __id_;
656
657public:
658    _LIBCPP_INLINE_VISIBILITY
659    __thread_id() _NOEXCEPT : __id_(0) {}
660
661    friend _LIBCPP_INLINE_VISIBILITY
662        bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT
663        { // don't pass id==0 to underlying routines
664        if (__x.__id_ == 0) return __y.__id_ == 0;
665        if (__y.__id_ == 0) return false;
666        return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
667        }
668    friend _LIBCPP_INLINE_VISIBILITY
669        bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT
670        {return !(__x == __y);}
671    friend _LIBCPP_INLINE_VISIBILITY
672        bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT
673        { // id==0 is always less than any other thread_id
674        if (__x.__id_ == 0) return __y.__id_ != 0;
675        if (__y.__id_ == 0) return false;
676        return  __libcpp_thread_id_less(__x.__id_, __y.__id_);
677        }
678    friend _LIBCPP_INLINE_VISIBILITY
679        bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT
680        {return !(__y < __x);}
681    friend _LIBCPP_INLINE_VISIBILITY
682        bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT
683        {return   __y < __x ;}
684    friend _LIBCPP_INLINE_VISIBILITY
685        bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT
686        {return !(__x < __y);}
687
688    _LIBCPP_INLINE_VISIBILITY
689    void __reset() { __id_ = 0; }
690
691    template<class _CharT, class _Traits>
692    friend
693    _LIBCPP_INLINE_VISIBILITY
694    basic_ostream<_CharT, _Traits>&
695    operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id);
696
697private:
698    _LIBCPP_INLINE_VISIBILITY
699    __thread_id(__libcpp_thread_id __id) : __id_(__id) {}
700
701    friend __thread_id this_thread::get_id() _NOEXCEPT;
702    friend class _LIBCPP_TYPE_VIS thread;
703    friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>;
704};
705
706namespace this_thread
707{
708
709inline _LIBCPP_INLINE_VISIBILITY
710__thread_id
711get_id() _NOEXCEPT
712{
713    return __libcpp_thread_get_current_id();
714}
715
716} // namespace this_thread
717
718#endif // !_LIBCPP_HAS_NO_THREADS
719
720_LIBCPP_END_NAMESPACE_STD
721
722_LIBCPP_POP_MACROS
723
724#endif // _LIBCPP_THREADING_SUPPORT
725