Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -882,6 +882,8 @@ defined(__CloudABI__) || \ defined(__sun__) # define _LIBCPP_HAS_THREAD_API_PTHREAD +# elif defined(_WIN32) +# define _LIBCPP_HAS_THREAD_API_WIN32 # else # error "No thread API" # endif // _LIBCPP_HAS_THREAD_API Index: include/__threading_support =================================================================== --- include/__threading_support +++ include/__threading_support @@ -32,9 +32,20 @@ #include <__external_threading> #else +#if !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && \ + !defined(_LIBCPP_HAS_THREAD_API_WIN32) +#error "unknown threading model" +#endif + #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) #include #include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#include +#include +#include #endif #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) @@ -64,6 +75,25 @@ // Thrad Local Storage typedef pthread_key_t __libcpp_tls_key; +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +// Mutex +typedef SRWLOCK __libcpp_mutex_t; +#define _LIBCPP_MUTEX_INITIALIZER SRWLOCK_INIT + +typedef CRITICAL_SECTION __libcpp_recursive_mutex_t; + +// Condition Variable +typedef CONDITION_VARIABLE __libcpp_condvar_t; +#define _LIBCPP_CONDVAR_INITIALIZER CONDITION_VARIABLE_INIT + +// Thread ID +typedef DWORD __libcpp_thread_id; + +// Thread +typedef HANDLE __libcpp_thread_t; + +// Thread Local Storage +typedef DWORD __libcpp_tls_key; #endif struct __libcpp_mutex_reference { @@ -306,6 +336,192 @@ pthread_setspecific(__key, __p); } +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) + +// Mutex +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m) +{ + InitializeCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_reference&& __m) +{ + if (__m.__recursive) + EnterCriticalSection(__m); + else + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_reference&& __m) +{ + if (__m.__recursive) + return TryEnterCriticalSection(__m); + return TryAcquireSRWLockExclusive(__m); +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_reference&& __m) +{ + if (__m.__recursive) + LeaveCriticalSection(__m); + else + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_reference&& __m) +{ + static_cast(__m); + return 0; +} + +// Condition Variable +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) +{ + WakeConditionVariable(__cv); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) +{ + WakeAllConditionVariable(__cv); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, + __libcpp_mutex_reference&& __m) +{ + if (__m.__recursive) + SleepConditionVariableCS(__cv, __m, INFINITE); + else + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, + __libcpp_mutex_reference&& __m, + timespec* __ts) +{ + using namespace _VSTD::chrono; + auto timeout = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec); + + // TODO(compnerd) handle timeouts < 10ms + if (__m.__recursive) { + if (!SleepConditionVariableCS(__cv, __m, + duration_cast(timeout).count())) + return GetLastError(); + } else { + if (!SleepConditionVariableSRW(__cv, __m, + duration_cast(timeout).count(), + 0)) + return GetLastError(); + } + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) +{ + static_cast(__cv); + return 0; +} + +// Thread ID +_LIBCPP_ALWAYS_INLINE +bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs, + __libcpp_thread_id __rhs) +{ + return __lhs == __rhs; +} + +_LIBCPP_ALWAYS_INLINE +bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs) +{ + return __lhs < __rhs; +} + +// Thread +_LIBCPP_ALWAYS_INLINE +int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), + void* __arg) +{ + // TODO(compnerd) provide a wrapper for CC adjustment + *__t = reinterpret_cast(_beginthreadex( + NULL, 0, (unsigned int(WINAPI*)(void*))__func, __arg, 0, NULL)); + if (*__t) + return 0; + return GetLastError(); +} + +_LIBCPP_ALWAYS_INLINE +__libcpp_thread_id __libcpp_thread_get_current_id() +{ + return GetCurrentThreadId(); +} + +_LIBCPP_ALWAYS_INLINE +__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) +{ + return GetThreadId(*__t); +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_thread_join(__libcpp_thread_t* __t) +{ + if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED) + return GetLastError(); + if (!CloseHandle(*__t)) + return GetLastError(); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_thread_detach(__libcpp_thread_t* __t) +{ + if (!CloseHandle(*__t)) + return GetLastError(); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +void __libcpp_thread_yield() +{ + SwitchToThread(); +} + +// Thread Local Storage +_LIBCPP_ALWAYS_INLINE +int __libcpp_tls_create(__libcpp_tls_key* __key, void (*__at_exit)(void*)) +{ + // TODO(compnerd) provide a wrapper for CC adjustment + *__key = FlsAlloc((void(WINAPI*)(void*))__at_exit); + if (*__key == FLS_OUT_OF_INDEXES) + return GetLastError(); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +void* __libcpp_tls_get(__libcpp_tls_key __key) +{ + return FlsGetValue(__key); +} + +_LIBCPP_ALWAYS_INLINE +void __libcpp_tls_set(__libcpp_tls_key __key, void* __p) +{ + FlsSetValue(__key, __p); +} + #endif // _LIBCPP_HAS_THREAD_API_PTHREAD _LIBCPP_END_NAMESPACE_STD