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