Home | History | Annotate | Download | only in v1
      1 // -*- C++ -*-
      2 //===----------------------------------------------------------------------===//
      3 //
      4 //                     The LLVM Compiler Infrastructure
      5 //
      6 // This file is dual licensed under the MIT and the University of Illinois Open
      7 // Source Licenses. See LICENSE.TXT for details.
      8 //
      9 //===----------------------------------------------------------------------===//
     10 
     11 #ifndef _LIBCPP_THREADING_SUPPORT
     12 #define _LIBCPP_THREADING_SUPPORT
     13 
     14 #include <__config>
     15 #include <chrono>
     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_WIN32)
     30 #include <Windows.h>
     31 #include <process.h>
     32 #include <fibersapi.h>
     33 #endif
     34 
     35 #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
     36     defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)
     37 #define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS
     38 #else
     39 #define _LIBCPP_THREAD_ABI_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
     40 #endif
     41 
     42 #if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(no_thread_safety_analysis)
     43 #define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
     44 #else
     45 #define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
     46 #endif
     47 
     48 _LIBCPP_BEGIN_NAMESPACE_STD
     49 
     50 #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
     51 // Mutex
     52 typedef pthread_mutex_t __libcpp_mutex_t;
     53 #define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
     54 
     55 typedef pthread_mutex_t __libcpp_recursive_mutex_t;
     56 
     57 // Condition Variable
     58 typedef pthread_cond_t __libcpp_condvar_t;
     59 #define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
     60 
     61 // Execute once
     62 typedef pthread_once_t __libcpp_exec_once_flag;
     63 #define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
     64 
     65 // Thread id
     66 typedef pthread_t __libcpp_thread_id;
     67 
     68 // Thread
     69 #define _LIBCPP_NULL_THREAD 0U
     70 
     71 typedef pthread_t __libcpp_thread_t;
     72 
     73 // Thrad Local Storage
     74 typedef pthread_key_t __libcpp_tls_key;
     75 
     76 #define _LIBCPP_TLS_DESTRUCTOR_CC
     77 #else
     78 // Mutex
     79 typedef SRWLOCK __libcpp_mutex_t;
     80 #define _LIBCPP_MUTEX_INITIALIZER SRWLOCK_INIT
     81 
     82 typedef CRITICAL_SECTION __libcpp_recursive_mutex_t;
     83 
     84 // Condition Variable
     85 typedef CONDITION_VARIABLE __libcpp_condvar_t;
     86 #define _LIBCPP_CONDVAR_INITIALIZER CONDITION_VARIABLE_INIT
     87 
     88 // Execute Once
     89 typedef INIT_ONCE __libcpp_exec_once_flag;
     90 #define _LIBCPP_EXEC_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT
     91 
     92 // Thread ID
     93 typedef DWORD __libcpp_thread_id;
     94 
     95 // Thread
     96 #define _LIBCPP_NULL_THREAD 0U
     97 
     98 typedef HANDLE __libcpp_thread_t;
     99 
    100 // Thread Local Storage
    101 typedef DWORD __libcpp_tls_key;
    102 
    103 #define _LIBCPP_TLS_DESTRUCTOR_CC WINAPI
    104 #endif
    105 
    106 // Mutex
    107 _LIBCPP_THREAD_ABI_VISIBILITY
    108 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m);
    109 
    110 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    111 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m);
    112 
    113 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    114 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m);
    115 
    116 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    117 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m);
    118 
    119 _LIBCPP_THREAD_ABI_VISIBILITY
    120 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m);
    121 
    122 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    123 int __libcpp_mutex_lock(__libcpp_mutex_t *__m);
    124 
    125 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    126 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m);
    127 
    128 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    129 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m);
    130 
    131 _LIBCPP_THREAD_ABI_VISIBILITY
    132 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m);
    133 
    134 // Condition variable
    135 _LIBCPP_THREAD_ABI_VISIBILITY
    136 int __libcpp_condvar_signal(__libcpp_condvar_t* __cv);
    137 
    138 _LIBCPP_THREAD_ABI_VISIBILITY
    139 int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv);
    140 
    141 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    142 int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m);
    143 
    144 _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_NO_THREAD_SAFETY_ANALYSIS
    145 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
    146                                timespec *__ts);
    147 
    148 _LIBCPP_THREAD_ABI_VISIBILITY
    149 int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
    150 
    151 // Execute once
    152 _LIBCPP_THREAD_ABI_VISIBILITY
    153 int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
    154                           void (*init_routine)(void));
    155 
    156 // Thread id
    157 _LIBCPP_THREAD_ABI_VISIBILITY
    158 bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2);
    159 
    160 _LIBCPP_THREAD_ABI_VISIBILITY
    161 bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2);
    162 
    163 // Thread
    164 _LIBCPP_THREAD_ABI_VISIBILITY
    165 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t);
    166 
    167 _LIBCPP_THREAD_ABI_VISIBILITY
    168 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
    169                            void *__arg);
    170 
    171 _LIBCPP_THREAD_ABI_VISIBILITY
    172 __libcpp_thread_id __libcpp_thread_get_current_id();
    173 
    174 _LIBCPP_THREAD_ABI_VISIBILITY
    175 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t);
    176 
    177 _LIBCPP_THREAD_ABI_VISIBILITY
    178 int __libcpp_thread_join(__libcpp_thread_t *__t);
    179 
    180 _LIBCPP_THREAD_ABI_VISIBILITY
    181 int __libcpp_thread_detach(__libcpp_thread_t *__t);
    182 
    183 _LIBCPP_THREAD_ABI_VISIBILITY
    184 void __libcpp_thread_yield();
    185 
    186 _LIBCPP_THREAD_ABI_VISIBILITY
    187 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns);
    188 
    189 // Thread local storage
    190 _LIBCPP_THREAD_ABI_VISIBILITY
    191 int __libcpp_tls_create(__libcpp_tls_key* __key,
    192                         void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
    193 
    194 _LIBCPP_THREAD_ABI_VISIBILITY
    195 void *__libcpp_tls_get(__libcpp_tls_key __key);
    196 
    197 _LIBCPP_THREAD_ABI_VISIBILITY
    198 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p);
    199 
    200 #if !defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
    201     defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)
    202 
    203 #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
    204 
    205 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
    206 {
    207   pthread_mutexattr_t attr;
    208   int __ec = pthread_mutexattr_init(&attr);
    209   if (__ec)
    210     return __ec;
    211   __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    212   if (__ec) {
    213     pthread_mutexattr_destroy(&attr);
    214     return __ec;
    215   }
    216   __ec = pthread_mutex_init(__m, &attr);
    217   if (__ec) {
    218     pthread_mutexattr_destroy(&attr);
    219     return __ec;
    220   }
    221   __ec = pthread_mutexattr_destroy(&attr);
    222   if (__ec) {
    223     pthread_mutex_destroy(__m);
    224     return __ec;
    225   }
    226   return 0;
    227 }
    228 
    229 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
    230 {
    231   return pthread_mutex_lock(__m);
    232 }
    233 
    234 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
    235 {
    236   return pthread_mutex_trylock(__m) == 0;
    237 }
    238 
    239 int __libcpp_recursive_mutex_unlock(__libcpp_mutex_t *__m)
    240 {
    241   return pthread_mutex_unlock(__m);
    242 }
    243 
    244 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
    245 {
    246   return pthread_mutex_destroy(__m);
    247 }
    248 
    249 int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
    250 {
    251   return pthread_mutex_lock(__m);
    252 }
    253 
    254 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
    255 {
    256   return pthread_mutex_trylock(__m) == 0;
    257 }
    258 
    259 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
    260 {
    261   return pthread_mutex_unlock(__m);
    262 }
    263 
    264 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
    265 {
    266   return pthread_mutex_destroy(__m);
    267 }
    268 
    269 // Condition Variable
    270 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
    271 {
    272   return pthread_cond_signal(__cv);
    273 }
    274 
    275 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
    276 {
    277   return pthread_cond_broadcast(__cv);
    278 }
    279 
    280 int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
    281 {
    282   return pthread_cond_wait(__cv, __m);
    283 }
    284 
    285 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
    286                                timespec *__ts)
    287 {
    288   return pthread_cond_timedwait(__cv, __m, __ts);
    289 }
    290 
    291 int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
    292 {
    293   return pthread_cond_destroy(__cv);
    294 }
    295 
    296 // Execute once
    297 int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
    298                           void (*init_routine)(void)) {
    299   return pthread_once(flag, init_routine);
    300 }
    301 
    302 // Thread id
    303 // Returns non-zero if the thread ids are equal, otherwise 0
    304 bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2)
    305 {
    306   return pthread_equal(t1, t2) != 0;
    307 }
    308 
    309 // Returns non-zero if t1 < t2, otherwise 0
    310 bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2)
    311 {
    312   return t1 < t2;
    313 }
    314 
    315 // Thread
    316 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
    317   return *__t == 0;
    318 }
    319 
    320 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
    321                            void *__arg)
    322 {
    323   return pthread_create(__t, 0, __func, __arg);
    324 }
    325 
    326 __libcpp_thread_id __libcpp_thread_get_current_id()
    327 {
    328   return pthread_self();
    329 }
    330 
    331 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
    332 {
    333   return *__t;
    334 }
    335 
    336 int __libcpp_thread_join(__libcpp_thread_t *__t)
    337 {
    338   return pthread_join(*__t, 0);
    339 }
    340 
    341 int __libcpp_thread_detach(__libcpp_thread_t *__t)
    342 {
    343   return pthread_detach(*__t);
    344 }
    345 
    346 void __libcpp_thread_yield()
    347 {
    348   sched_yield();
    349 }
    350 
    351 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
    352 {
    353    using namespace chrono;
    354    seconds __s = duration_cast<seconds>(__ns);
    355    timespec __ts;
    356    typedef decltype(__ts.tv_sec) ts_sec;
    357    _LIBCPP_CONSTEXPR ts_sec __ts_sec_max = numeric_limits<ts_sec>::max();
    358 
    359    if (__s.count() < __ts_sec_max)
    360    {
    361      __ts.tv_sec = static_cast<ts_sec>(__s.count());
    362      __ts.tv_nsec = static_cast<decltype(__ts.tv_nsec)>((__ns - __s).count());
    363    }
    364    else
    365    {
    366      __ts.tv_sec = __ts_sec_max;
    367      __ts.tv_nsec = 999999999; // (10^9 - 1)
    368    }
    369 
    370    while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR);
    371 }
    372 
    373 // Thread local storage
    374 int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
    375 {
    376   return pthread_key_create(__key, __at_exit);
    377 }
    378 
    379 void *__libcpp_tls_get(__libcpp_tls_key __key)
    380 {
    381   return pthread_getspecific(__key);
    382 }
    383 
    384 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
    385 {
    386     return pthread_setspecific(__key, __p);
    387 }
    388 
    389 #elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
    390 
    391 // Mutex
    392 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
    393 {
    394   InitializeCriticalSection(__m);
    395   return 0;
    396 }
    397 
    398 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
    399 {
    400   EnterCriticalSection(__m);
    401   return 0;
    402 }
    403 
    404 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
    405 {
    406   return TryEnterCriticalSection(__m) != 0;
    407 }
    408 
    409 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
    410 {
    411   LeaveCriticalSection(__m);
    412   return 0;
    413 }
    414 
    415 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
    416 {
    417   DeleteCriticalSection(__m);
    418   return 0;
    419 }
    420 
    421 int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
    422 {
    423   AcquireSRWLockExclusive(__m);
    424   return 0;
    425 }
    426 
    427 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
    428 {
    429   return TryAcquireSRWLockExclusive(__m) != 0;
    430 }
    431 
    432 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
    433 {
    434   ReleaseSRWLockExclusive(__m);
    435   return 0;
    436 }
    437 
    438 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
    439 {
    440   static_cast<void>(__m);
    441   return 0;
    442 }
    443 
    444 // Condition Variable
    445 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
    446 {
    447   WakeConditionVariable(__cv);
    448   return 0;
    449 }
    450 
    451 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
    452 {
    453   WakeAllConditionVariable(__cv);
    454   return 0;
    455 }
    456 
    457 int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
    458 {
    459   SleepConditionVariableSRW(__cv, __m, INFINITE, 0);
    460   return 0;
    461 }
    462 
    463 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
    464                                timespec *__ts)
    465 {
    466   using namespace _VSTD::chrono;
    467 
    468   auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
    469   auto abstime =
    470       system_clock::time_point(duration_cast<system_clock::duration>(duration));
    471   auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
    472 
    473   if (!SleepConditionVariableSRW(__cv, __m,
    474                                  timeout_ms.count() > 0 ? timeout_ms.count()
    475                                                         : 0,
    476                                  0))
    477     return GetLastError();
    478   return 0;
    479 }
    480 
    481 int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
    482 {
    483   static_cast<void>(__cv);
    484   return 0;
    485 }
    486 
    487 // Execute Once
    488 static inline _LIBCPP_ALWAYS_INLINE BOOL CALLBACK
    489 __libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
    490                                       PVOID *__context)
    491 {
    492   static_cast<void>(__init_once);
    493   static_cast<void>(__context);
    494 
    495   void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
    496   init_routine();
    497   return TRUE;
    498 }
    499 
    500 int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
    501                           void (*__init_routine)(void))
    502 {
    503   if (!InitOnceExecuteOnce(__flag, __libcpp_init_once_execute_once_thunk,
    504                            reinterpret_cast<void *>(__init_routine), NULL))
    505     return GetLastError();
    506   return 0;
    507 }
    508 
    509 // Thread ID
    510 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
    511                               __libcpp_thread_id __rhs)
    512 {
    513   return __lhs == __rhs;
    514 }
    515 
    516 bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
    517 {
    518   return __lhs < __rhs;
    519 }
    520 
    521 // Thread
    522 struct __libcpp_beginthreadex_thunk_data
    523 {
    524   void *(*__func)(void *);
    525   void *__arg;
    526 };
    527 
    528 static inline _LIBCPP_ALWAYS_INLINE unsigned WINAPI
    529 __libcpp_beginthreadex_thunk(void *__raw_data)
    530 {
    531   auto *__data =
    532       static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
    533   auto *__func = __data->__func;
    534   void *__arg = __data->__arg;
    535   delete __data;
    536   return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
    537 }
    538 
    539 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
    540   return *__t == 0;
    541 }
    542 
    543 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
    544                            void *__arg)
    545 {
    546   auto *__data = new __libcpp_beginthreadex_thunk_data;
    547   __data->__func = __func;
    548   __data->__arg = __arg;
    549 
    550   *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
    551                                                  __libcpp_beginthreadex_thunk,
    552                                                  __data, 0, nullptr));
    553 
    554   if (*__t)
    555     return 0;
    556   return GetLastError();
    557 }
    558 
    559 __libcpp_thread_id __libcpp_thread_get_current_id()
    560 {
    561   return GetCurrentThreadId();
    562 }
    563 
    564 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
    565 {
    566   return GetThreadId(*__t);
    567 }
    568 
    569 int __libcpp_thread_join(__libcpp_thread_t *__t)
    570 {
    571   if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
    572     return GetLastError();
    573   if (!CloseHandle(*__t))
    574     return GetLastError();
    575   return 0;
    576 }
    577 
    578 int __libcpp_thread_detach(__libcpp_thread_t *__t)
    579 {
    580   if (!CloseHandle(*__t))
    581     return GetLastError();
    582   return 0;
    583 }
    584 
    585 void __libcpp_thread_yield()
    586 {
    587   SwitchToThread();
    588 }
    589 
    590 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
    591 {
    592   using namespace chrono;
    593   // round-up to the nearest milisecond
    594   milliseconds __ms =
    595       duration_cast<milliseconds>(__ns + chrono::nanoseconds(999999));
    596   // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
    597   Sleep(__ms.count());
    598 }
    599 
    600 // Thread Local Storage
    601 int __libcpp_tls_create(__libcpp_tls_key* __key,
    602                         void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
    603 {
    604   *__key = FlsAlloc(__at_exit);
    605   if (*__key == FLS_OUT_OF_INDEXES)
    606     return GetLastError();
    607   return 0;
    608 }
    609 
    610 void *__libcpp_tls_get(__libcpp_tls_key __key)
    611 {
    612   return FlsGetValue(__key);
    613 }
    614 
    615 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
    616 {
    617   if (!FlsSetValue(__key, __p))
    618     return GetLastError();
    619   return 0;
    620 }
    621 
    622 #endif // _LIBCPP_HAS_THREAD_API_PTHREAD
    623 
    624 #endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
    625 
    626 _LIBCPP_END_NAMESPACE_STD
    627 
    628 #endif // !_LIBCPP_HAS_NO_THREADS
    629 
    630 #endif // _LIBCPP_THREADING_SUPPORT
    631