libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

thread_win32.cpp (14311B)


      1 // -*- C++ -*-
      2 //===-------------------- support/win32/thread_win32.cpp ------------------===//
      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 #include <__threading_support>
     12 #include <windows.h>
     13 #include <process.h>
     14 #include <fibersapi.h>
     15 
     16 _LIBCPP_BEGIN_NAMESPACE_STD
     17 
     18 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
     19 static_assert(sizeof(__libcpp_mutex_t) == sizeof(CRITICAL_SECTION), "");
     20 static_assert(alignof(__libcpp_mutex_t) == alignof(CRITICAL_SECTION), "");
     21 #else
     22 static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
     23 static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
     24 #endif
     25 
     26 static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
     27               "");
     28 static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
     29               "");
     30 
     31 #ifndef _LIBCPP_MUTEXES_ARE_SHIT
     32 static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
     33 static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
     34 #endif
     35 
     36 #ifndef _LIBCPP_MUTEXES_ARE_SHIT
     37 static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
     38 static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
     39 #endif
     40 
     41 static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
     42 static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
     43 
     44 #ifndef _LIBCPP_MUTEXES_ARE_SHIT
     45 static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
     46 static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
     47 #endif
     48 
     49 static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
     50 static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
     51 
     52 // Mutex
     53 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
     54 {
     55   InitializeCriticalSection((LPCRITICAL_SECTION)__m);
     56   return 0;
     57 }
     58 
     59 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
     60 {
     61   EnterCriticalSection((LPCRITICAL_SECTION)__m);
     62   return 0;
     63 }
     64 
     65 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
     66 {
     67   return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
     68 }
     69 
     70 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
     71 {
     72   LeaveCriticalSection((LPCRITICAL_SECTION)__m);
     73   return 0;
     74 }
     75 
     76 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
     77 {
     78   DeleteCriticalSection((LPCRITICAL_SECTION)__m);
     79   return 0;
     80 }
     81 
     82 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
     83 _LIBCPP_SAFE_STATIC static volatile long init_mutex = 0;
     84 
     85 static void init_mtx_if_needed(__libcpp_mutex_t *__m)
     86 {
     87   if (**__m != (size_t) -1) return;
     88   while (InterlockedCompareExchange(&init_mutex, 1, 0)) SwitchToThread();
     89 
     90   if (**__m == (size_t) -1) __libcpp_mutex_init(__m);
     91 
     92   InterlockedExchange(&init_mutex, 0);
     93 }
     94 
     95 void __libcpp_mutex_init(__libcpp_mutex_t *__m)
     96 {
     97   **__m = 0;
     98   InitializeCriticalSection((CRITICAL_SECTION*)__m);
     99 }
    100 #endif
    101 
    102 int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
    103 {
    104 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    105   init_mtx_if_needed(__m);
    106   EnterCriticalSection((CRITICAL_SECTION*)__m);
    107 #else
    108   AcquireSRWLockExclusive((PSRWLOCK)__m);
    109 #endif
    110   return 0;
    111 }
    112 
    113 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
    114 {
    115 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    116   init_mtx_if_needed(__m);
    117   return TryEnterCriticalSection((CRITICAL_SECTION*)__m);
    118 #else
    119   return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
    120 #endif
    121 }
    122 
    123 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
    124 {
    125 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    126   LeaveCriticalSection((CRITICAL_SECTION*)__m);
    127 #else
    128   ReleaseSRWLockExclusive((PSRWLOCK)__m);
    129 #endif
    130   return 0;
    131 }
    132 
    133 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
    134 {
    135 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    136   if (**__m != (size_t) -1) DeleteCriticalSection((CRITICAL_SECTION*)__m);
    137 #endif
    138   static_cast<void>(__m);
    139   return 0;
    140 }
    141 
    142 // Condition Variable
    143 // http://web.archive.org/web/20110721173110/https://www.cse.wustl.edu/~schmidt/win32-cv-1.html
    144 // the second best solution, since the best is fucking complicated and nt4+
    145 // todo error handling
    146 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    147 _LIBCPP_SAFE_STATIC static volatile long init_cv = 0;
    148 
    149 static int init_cv_if_needed(__libcpp_condvar_t *__cv)
    150 {
    151   if (__cv->event != (size_t) -2) return 0;
    152   while (InterlockedCompareExchange(&init_cv, 1, 0)) SwitchToThread();
    153 
    154   if (__cv->event != (size_t) -2)
    155   {
    156     // someone initialized it in the meantime
    157     InterlockedExchange(&init_cv, 0);
    158     return 0;
    159   }
    160 
    161   int res = __libcpp_condvar_init(__cv);
    162   InterlockedExchange(&init_cv, 0);
    163   return res;
    164 }
    165 
    166 int __libcpp_condvar_init(__libcpp_condvar_t *__cv)
    167 {
    168   __cv->waiter_count = __cv->release_count = __cv->generation_count = 0;
    169   InitializeCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    170   __cv->event = (size_t) CreateEventW(nullptr, true, false, nullptr);
    171   return __cv->event ? 0 : ENOMEM;
    172 }
    173 #endif
    174 
    175 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
    176 {
    177 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    178   int res = init_cv_if_needed(__cv); if (res != 0) return res;
    179   EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    180   if (__cv->waiter_count > __cv->release_count)
    181   {
    182     SetEvent((HANDLE)__cv->event);
    183     __cv->release_count++;
    184     __cv->generation_count++;
    185   }
    186   LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    187 #else
    188   WakeConditionVariable((PCONDITION_VARIABLE)__cv);
    189 #endif
    190   return 0;
    191 }
    192 
    193 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
    194 {
    195 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    196   int res = init_cv_if_needed(__cv); if (res != 0) return res;
    197   EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    198   if (__cv->waiter_count > 0)
    199   {
    200     SetEvent((HANDLE)__cv->event);
    201     __cv->release_count = __cv->waiter_count;
    202     __cv->generation_count++;
    203   }
    204   LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    205 #else
    206   WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
    207 #endif
    208   return 0;
    209 }
    210 
    211 int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
    212 {
    213 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    214   int res = init_cv_if_needed(__cv); if (res != 0) return res;
    215 #define WAIT_PRE                                            \
    216   EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \
    217   __cv->waiter_count++;                                     \
    218   unsigned my_gen = __cv->generation_count;                 \
    219   LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \
    220   __libcpp_mutex_unlock(__m)
    221   WAIT_PRE;
    222 
    223   while (true)
    224   {
    225     WaitForSingleObject((HANDLE)__cv->event, INFINITE);
    226 #define WAIT_LOOP                                                               \
    227     EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);                   \
    228     bool wait_done = __cv->release_count > 0 && __cv->generation_count != my_gen; \
    229     LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);                   \
    230     if (wait_done) break
    231     WAIT_LOOP;
    232   }
    233 
    234 #define WAIT_POST                                           \
    235   __libcpp_mutex_lock(__m);                                 \
    236   EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \
    237   --__cv->waiter_count;                                     \
    238   bool last_waiter = --__cv->release_count == 0;            \
    239   LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs); \
    240   if (last_waiter) ResetEvent((HANDLE)__cv->event)
    241   WAIT_POST;
    242 #else
    243   SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0);
    244 #endif
    245   return 0;
    246 }
    247 
    248 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
    249                                timespec *__ts)
    250 {
    251   using namespace _VSTD::chrono;
    252 
    253   auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
    254   auto abstime =
    255       system_clock::time_point(duration_cast<system_clock::duration>(duration));
    256 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    257   auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now()).count();
    258 
    259   WAIT_PRE;
    260   while (true)
    261   {
    262     switch (WaitForSingleObject((HANDLE)__cv->event, timeout_ms < 0 ? 0 : timeout_ms))
    263     {
    264     case WAIT_OBJECT_0: break;
    265     case WAIT_TIMEOUT:
    266       EnterCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    267       --__cv->waiter_count;
    268       LeaveCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    269       return false;
    270     default: abort();
    271     }
    272     WAIT_LOOP;
    273     timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now()).count();
    274   }
    275   WAIT_POST;
    276 #undef WAIT_PRE
    277 #undef WAIT_LOOP
    278 #undef WAIT_POST
    279 #else
    280   auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
    281 
    282   if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m,
    283                                  timeout_ms.count() > 0 ? timeout_ms.count()
    284                                                         : 0,
    285                                  0))
    286     {
    287       auto __ec = GetLastError();
    288       return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec;
    289     }
    290 #endif
    291   return 0;
    292 }
    293 
    294 int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
    295 {
    296 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    297   if (__cv->event == (size_t) -2) return 0;
    298   CloseHandle((HANDLE) __cv->event);
    299   DeleteCriticalSection((CRITICAL_SECTION*)__cv->waiter_cs);
    300 #else
    301   static_cast<void>(__cv);
    302 #endif
    303   return 0;
    304 }
    305 
    306 // Execute Once
    307 static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
    308 __libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
    309                                       PVOID *__context)
    310 {
    311   static_cast<void>(__init_once);
    312   static_cast<void>(__context);
    313 
    314   void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
    315   init_routine();
    316   return TRUE;
    317 }
    318 
    319 // only used by libcxxabi
    320 #ifndef _LIBCPP_MUTEXES_ARE_SHIT
    321 int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
    322                           void (*__init_routine)(void))
    323 {
    324   if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk,
    325                            reinterpret_cast<void *>(__init_routine), NULL))
    326     return GetLastError();
    327   return 0;
    328 }
    329 #endif
    330 
    331 // Thread ID
    332 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
    333                               __libcpp_thread_id __rhs)
    334 {
    335   return __lhs == __rhs;
    336 }
    337 
    338 bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
    339 {
    340   return __lhs < __rhs;
    341 }
    342 
    343 // Thread
    344 struct __libcpp_beginthreadex_thunk_data
    345 {
    346   void *(*__func)(void *);
    347   void *__arg;
    348 };
    349 
    350 static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
    351 __libcpp_beginthreadex_thunk(void *__raw_data)
    352 {
    353   auto *__data =
    354       static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
    355   auto *__func = __data->__func;
    356   void *__arg = __data->__arg;
    357   delete __data;
    358   return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
    359 }
    360 
    361 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    362 #  define THREAD_HANDLE(__t) (__t)->handle
    363 #else
    364 #  define THREAD_HANDLE(__t) (*(__t))
    365 #endif
    366 
    367 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
    368   return THREAD_HANDLE(__t) == 0;
    369 }
    370 
    371 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
    372                            void *__arg)
    373 {
    374   auto *__data = new __libcpp_beginthreadex_thunk_data;
    375   __data->__func = __func;
    376   __data->__arg = __arg;
    377 
    378 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    379   __t->handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
    380                                                  __libcpp_beginthreadex_thunk,
    381                                                  __data, 0, &__t->id));
    382 #else
    383   *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
    384                                                  __libcpp_beginthreadex_thunk,
    385                                                  __data, 0, nullptr));
    386 #endif
    387 
    388   if (THREAD_HANDLE(__t))
    389     return 0;
    390   return GetLastError();
    391 }
    392 
    393 __libcpp_thread_id __libcpp_thread_get_current_id()
    394 {
    395   return GetCurrentThreadId();
    396 }
    397 
    398 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
    399 {
    400 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    401   return __t->id;
    402 #else
    403   return GetThreadId(*__t);
    404 #endif
    405 }
    406 
    407 int __libcpp_thread_join(__libcpp_thread_t *__t)
    408 {
    409   if (WaitForSingleObjectEx(THREAD_HANDLE(__t), INFINITE, FALSE) == WAIT_FAILED)
    410     return GetLastError();
    411   if (!CloseHandle(THREAD_HANDLE(__t)))
    412     return GetLastError();
    413   return 0;
    414 }
    415 
    416 int __libcpp_thread_detach(__libcpp_thread_t *__t)
    417 {
    418   if (!CloseHandle(THREAD_HANDLE(__t)))
    419     return GetLastError();
    420   return 0;
    421 }
    422 
    423 void __libcpp_thread_yield()
    424 {
    425   SwitchToThread();
    426 }
    427 
    428 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
    429 {
    430   using namespace chrono;
    431   // round-up to the nearest milisecond
    432   milliseconds __ms =
    433       duration_cast<milliseconds>(__ns + chrono::nanoseconds(999999));
    434   // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
    435   Sleep(__ms.count());
    436 }
    437 
    438 // Thread Local Storage
    439 
    440 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    441 namespace
    442 {
    443   struct Node
    444   {
    445     void(_LIBCPP_TLS_DESTRUCTOR_CC* fun)(void*);
    446     Node* next;
    447     DWORD idx;
    448   };
    449   static Node* volatile root = nullptr;
    450 
    451   struct DtorHolder
    452   {
    453     ~DtorHolder()
    454     {
    455       Node* n = (Node*) root;
    456       while (n)
    457       {
    458         n->fun(TlsGetValue(n->idx));
    459         n = n->next;
    460       }
    461     }
    462   };
    463   thread_local DtorHolder dtor_holder;
    464 }
    465 #endif
    466 
    467 extern "C" int __cdecl __tlregdtor(_PVFV func);
    468 int __libcpp_tls_create(__libcpp_tls_key* __key,
    469                         void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
    470 {
    471 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    472   DWORD index = TlsAlloc();
    473   if (index == TLS_OUT_OF_INDEXES)
    474     return GetLastError();
    475   *__key = index;
    476 
    477   if (__at_exit)
    478   {
    479     Node* n = (Node*) malloc(sizeof(Node));
    480     if (!n) return ENOMEM;
    481     n->fun = __at_exit;
    482     n->idx = index;
    483     n->next = root;
    484 
    485     while (true)
    486     {
    487       Node* nroot = (Node*) InterlockedCompareExchangePointer((void* volatile*) &root, n, n->next);
    488       if (nroot == n->next) break;
    489       n->next = nroot;
    490     }
    491   }
    492 #else
    493   DWORD index = FlsAlloc(__at_exit);
    494   if (index == FLS_OUT_OF_INDEXES)
    495     return GetLastError();
    496   *__key = index;
    497 #endif
    498   return 0;
    499 }
    500 
    501 void *__libcpp_tls_get(__libcpp_tls_key __key)
    502 {
    503 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    504   return TlsGetValue(__key);
    505 #else
    506   return FlsGetValue(__key);
    507 #endif
    508 }
    509 
    510 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
    511 {
    512 #ifdef _LIBCPP_MUTEXES_ARE_SHIT
    513   if (!TlsSetValue(__key, __p))
    514 #else
    515   if (!FlsSetValue(__key, __p))
    516 #endif
    517     return GetLastError();
    518   return 0;
    519 }
    520 
    521 _LIBCPP_END_NAMESPACE_STD