Home | History | Annotate | Line # | Download | only in win32
      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 #include <__threading_support>
     11 #define NOMINMAX
     12 #define WIN32_LEAN_AND_MEAN
     13 #include <windows.h>
     14 #include <process.h>
     15 #include <fibersapi.h>
     16 
     17 _LIBCPP_BEGIN_NAMESPACE_STD
     18 
     19 static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
     20 static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
     21 
     22 static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
     23               "");
     24 static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
     25               "");
     26 
     27 static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
     28 static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
     29 
     30 static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
     31 static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
     32 
     33 static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
     34 static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
     35 
     36 static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
     37 static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
     38 
     39 static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
     40 static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
     41 
     42 static_assert(sizeof(__libcpp_semaphore_t) == sizeof(HANDLE), "");
     43 static_assert(alignof(__libcpp_semaphore_t) == alignof(HANDLE), "");
     44 
     45 // Mutex
     46 int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
     47 {
     48   InitializeCriticalSection((LPCRITICAL_SECTION)__m);
     49   return 0;
     50 }
     51 
     52 int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
     53 {
     54   EnterCriticalSection((LPCRITICAL_SECTION)__m);
     55   return 0;
     56 }
     57 
     58 bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
     59 {
     60   return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
     61 }
     62 
     63 int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
     64 {
     65   LeaveCriticalSection((LPCRITICAL_SECTION)__m);
     66   return 0;
     67 }
     68 
     69 int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
     70 {
     71   DeleteCriticalSection((LPCRITICAL_SECTION)__m);
     72   return 0;
     73 }
     74 
     75 int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
     76 {
     77   AcquireSRWLockExclusive((PSRWLOCK)__m);
     78   return 0;
     79 }
     80 
     81 bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
     82 {
     83   return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
     84 }
     85 
     86 int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
     87 {
     88   ReleaseSRWLockExclusive((PSRWLOCK)__m);
     89   return 0;
     90 }
     91 
     92 int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
     93 {
     94   static_cast<void>(__m);
     95   return 0;
     96 }
     97 
     98 // Condition Variable
     99 int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
    100 {
    101   WakeConditionVariable((PCONDITION_VARIABLE)__cv);
    102   return 0;
    103 }
    104 
    105 int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
    106 {
    107   WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
    108   return 0;
    109 }
    110 
    111 int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
    112 {
    113   SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0);
    114   return 0;
    115 }
    116 
    117 int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
    118                                __libcpp_timespec_t *__ts)
    119 {
    120   using namespace _VSTD::chrono;
    121 
    122   auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
    123   auto abstime =
    124       system_clock::time_point(duration_cast<system_clock::duration>(duration));
    125   auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
    126 
    127   if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m,
    128                                  timeout_ms.count() > 0 ? timeout_ms.count()
    129                                                         : 0,
    130                                  0))
    131     {
    132       auto __ec = GetLastError();
    133       return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec;
    134     }
    135   return 0;
    136 }
    137 
    138 int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
    139 {
    140   static_cast<void>(__cv);
    141   return 0;
    142 }
    143 
    144 // Execute Once
    145 static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
    146 __libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
    147                                       PVOID *__context)
    148 {
    149   static_cast<void>(__init_once);
    150   static_cast<void>(__context);
    151 
    152   void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
    153   init_routine();
    154   return TRUE;
    155 }
    156 
    157 int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
    158                           void (*__init_routine)(void))
    159 {
    160   if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk,
    161                            reinterpret_cast<void *>(__init_routine), NULL))
    162     return GetLastError();
    163   return 0;
    164 }
    165 
    166 // Thread ID
    167 bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
    168                               __libcpp_thread_id __rhs)
    169 {
    170   return __lhs == __rhs;
    171 }
    172 
    173 bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
    174 {
    175   return __lhs < __rhs;
    176 }
    177 
    178 // Thread
    179 struct __libcpp_beginthreadex_thunk_data
    180 {
    181   void *(*__func)(void *);
    182   void *__arg;
    183 };
    184 
    185 static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
    186 __libcpp_beginthreadex_thunk(void *__raw_data)
    187 {
    188   auto *__data =
    189       static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
    190   auto *__func = __data->__func;
    191   void *__arg = __data->__arg;
    192   delete __data;
    193   return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
    194 }
    195 
    196 bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
    197   return *__t == 0;
    198 }
    199 
    200 int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
    201                            void *__arg)
    202 {
    203   auto *__data = new __libcpp_beginthreadex_thunk_data;
    204   __data->__func = __func;
    205   __data->__arg = __arg;
    206 
    207   *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
    208                                                  __libcpp_beginthreadex_thunk,
    209                                                  __data, 0, nullptr));
    210 
    211   if (*__t)
    212     return 0;
    213   return GetLastError();
    214 }
    215 
    216 __libcpp_thread_id __libcpp_thread_get_current_id()
    217 {
    218   return GetCurrentThreadId();
    219 }
    220 
    221 __libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
    222 {
    223   return GetThreadId(*__t);
    224 }
    225 
    226 int __libcpp_thread_join(__libcpp_thread_t *__t)
    227 {
    228   if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
    229     return GetLastError();
    230   if (!CloseHandle(*__t))
    231     return GetLastError();
    232   return 0;
    233 }
    234 
    235 int __libcpp_thread_detach(__libcpp_thread_t *__t)
    236 {
    237   if (!CloseHandle(*__t))
    238     return GetLastError();
    239   return 0;
    240 }
    241 
    242 void __libcpp_thread_yield()
    243 {
    244   SwitchToThread();
    245 }
    246 
    247 void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
    248 {
    249   // round-up to the nearest millisecond
    250   chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns);
    251   // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
    252   Sleep(__ms.count());
    253 }
    254 
    255 // Thread Local Storage
    256 int __libcpp_tls_create(__libcpp_tls_key* __key,
    257                         void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
    258 {
    259   DWORD index = FlsAlloc(__at_exit);
    260   if (index == FLS_OUT_OF_INDEXES)
    261     return GetLastError();
    262   *__key = index;
    263   return 0;
    264 }
    265 
    266 void *__libcpp_tls_get(__libcpp_tls_key __key)
    267 {
    268   return FlsGetValue(__key);
    269 }
    270 
    271 int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
    272 {
    273   if (!FlsSetValue(__key, __p))
    274     return GetLastError();
    275   return 0;
    276 }
    277 
    278 // Semaphores
    279 bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init)
    280 {
    281   *(PHANDLE)__sem = CreateSemaphoreEx(nullptr, __init, _LIBCPP_SEMAPHORE_MAX,
    282                                       nullptr, 0, SEMAPHORE_ALL_ACCESS);
    283   return *__sem != nullptr;
    284 }
    285 
    286 bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem)
    287 {
    288   CloseHandle(*(PHANDLE)__sem);
    289   return true;
    290 }
    291 
    292 bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem)
    293 {
    294   return ReleaseSemaphore(*(PHANDLE)__sem, 1, nullptr);
    295 }
    296 
    297 bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem)
    298 {
    299   return WaitForSingleObjectEx(*(PHANDLE)__sem, INFINITE, false) ==
    300          WAIT_OBJECT_0;
    301 }
    302 
    303 bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem,
    304                                    chrono::nanoseconds const& __ns)
    305 {
    306   chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns);
    307   return WaitForSingleObjectEx(*(PHANDLE)__sem, __ms.count(), false) ==
    308          WAIT_OBJECT_0;
    309 }
    310 
    311 _LIBCPP_END_NAMESPACE_STD
    312