Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -892,6 +892,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 @@ -43,10 +43,21 @@ #include <__external_threading> #else +#if !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && \ + !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL_PTHREAD) && \ + !defined(_LIBCPP_HAS_THREAD_API_WIN32) +#error "unknown threading model" +#endif + #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) || \ defined(_LIBCPP_HAS_THREAD_API_EXTERNAL_PTHREAD) #include #include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#include +#include #endif #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) @@ -81,6 +92,29 @@ // 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 + +// Execute once +typedef INIT_ONCE __libcpp_exec_once_flag; +#define _LIBCPP_EXEC_ONCE_INITIALIZER INIT_ONCE_STATIC_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 { @@ -347,6 +381,236 @@ return 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); + auto timeout_ms = duration_cast(timeout); + + _LIBCPP_ASSERT(timeout_ms.count() < _VSTD::numeric_limits::max(), + "timeout duration overflows"); + + if (__m.__recursive) { + if (!SleepConditionVariableCS(__cv, __m, timeout_ms.count())) + return GetLastError(); + } else { + if (!SleepConditionVariableSRW(__cv, __m, timeout_ms.count(), 0)) + return GetLastError(); + } + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) +{ + static_cast(__cv); + return 0; +} + +// Execute once +static inline _LIBCPP_ALWAYS_INLINE BOOL CALLBACK +__libcpp_init_once_trampoline(PINIT_ONCE InitOnce, PVOID Parameter, + PVOID *Context) +{ + static_cast(InitOnce); + static_cast(Context); + + void (*init_routine)(void) = reinterpret_cast(Parameter); + init_routine(); + return TRUE; +} + +int __libcpp_execute_once(__libcpp_exec_once_flag* flag, + void (*init_routine)(void)) +{ + if (!InitOnceExecuteOnce(flag, __libcpp_init_once_trampoline, + reinterpret_cast(init_routine), NULL)) + return GetLastError(); + 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; +} + +struct __libcpp_thread_trampoline_data +{ + void* (*__func)(void*); + void* __arg; +}; + +static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI +__libcpp_thread_trampoline(void *__data) +{ + __libcpp_thread_trampoline_data data = + *(__libcpp_thread_trampoline_data*)__data; + _VSTD::free(__data); + return reinterpret_cast(data.__func(data.__arg)); +} + +// Thread +_LIBCPP_ALWAYS_INLINE +int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), + void* __arg) +{ + __libcpp_thread_trampoline_data* data = + reinterpret_cast<__libcpp_thread_trampoline_data*>(_VSTD::malloc(sizeof(*data))); + data->__func = __func; + data->__arg = __arg; + + *__t = reinterpret_cast(_beginthreadex(NULL, 0, + __libcpp_thread_trampoline, + data, 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(reinterpret_cast(__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 +int __libcpp_tls_set(__libcpp_tls_key __key, void* __p) +{ + if (!FlsSetValue(__key, __p)) + return GetLastError(); + return 0; +} + #endif // _LIBCPP_HAS_THREAD_API_PTHREAD _LIBCPP_END_NAMESPACE_STD