provide Win32 native threading
Add an implementation for the Win32 threading model as a backing API for the internal c++ threading interfaces. This uses the Fls* family for the TLS (which has the support for adding termination callbacks), CRITICAL_SECTIONs for the recursive mutex, and Slim Reader/Writer locks (SRW locks) for non-recursive mutexes. These APIs should all be available on Vista or newer. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@291333 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -913,6 +913,8 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
|
|||||||
defined(__CloudABI__) || \
|
defined(__CloudABI__) || \
|
||||||
defined(__sun__)
|
defined(__sun__)
|
||||||
# define _LIBCPP_HAS_THREAD_API_PTHREAD
|
# define _LIBCPP_HAS_THREAD_API_PTHREAD
|
||||||
|
# elif defined(_LIBCPP_WIN32API)
|
||||||
|
# define _LIBCPP_HAS_THREAD_API_WIN32
|
||||||
# else
|
# else
|
||||||
# error "No thread API"
|
# error "No thread API"
|
||||||
# endif // _LIBCPP_HAS_THREAD_API
|
# endif // _LIBCPP_HAS_THREAD_API
|
||||||
|
|||||||
@@ -24,6 +24,13 @@
|
|||||||
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
# include <sched.h>
|
# include <sched.h>
|
||||||
|
#elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
|
||||||
|
#include <assert.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <fibersapi.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
|
#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
|
||||||
@@ -58,6 +65,33 @@ typedef pthread_t __libcpp_thread_t;
|
|||||||
|
|
||||||
// Thrad Local Storage
|
// Thrad Local Storage
|
||||||
typedef pthread_key_t __libcpp_tls_key;
|
typedef pthread_key_t __libcpp_tls_key;
|
||||||
|
|
||||||
|
#define _LIBCPP_TLS_DESTRUCTOR_CC
|
||||||
|
#else
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
#define _LIBCPP_TLS_DESTRUCTOR_CC WINAPI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Mutex
|
// Mutex
|
||||||
@@ -144,7 +178,8 @@ void __libcpp_thread_yield();
|
|||||||
|
|
||||||
// Thread local storage
|
// Thread local storage
|
||||||
_LIBCPP_THREAD_ABI_VISIBILITY
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
||||||
int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *));
|
int __libcpp_tls_create(__libcpp_tls_key* __key,
|
||||||
|
void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
|
||||||
|
|
||||||
_LIBCPP_THREAD_ABI_VISIBILITY
|
_LIBCPP_THREAD_ABI_VISIBILITY
|
||||||
void *__libcpp_tls_get(__libcpp_tls_key __key);
|
void *__libcpp_tls_get(__libcpp_tls_key __key);
|
||||||
@@ -321,6 +356,224 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
|
|||||||
return pthread_setspecific(__key, __p);
|
return pthread_setspecific(__key, __p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
|
||||||
|
|
||||||
|
// Mutex
|
||||||
|
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
|
||||||
|
{
|
||||||
|
InitializeCriticalSection(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
|
||||||
|
{
|
||||||
|
TryEnterCriticalSection(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
|
||||||
|
{
|
||||||
|
static_cast<void>(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
|
||||||
|
{
|
||||||
|
AcquireSRWLockExclusive(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
|
||||||
|
{
|
||||||
|
TryAcquireSRWLockExclusive(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
|
||||||
|
{
|
||||||
|
ReleaseSRWLockExclusive(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
|
||||||
|
{
|
||||||
|
static_cast<void>(__m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Condition Variable
|
||||||
|
int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
|
||||||
|
{
|
||||||
|
WakeConditionVariable(__cv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
|
||||||
|
{
|
||||||
|
WakeAllConditionVariable(__cv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
|
||||||
|
{
|
||||||
|
SleepConditionVariableSRW(__cv, __m, INFINITE, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
|
||||||
|
timespec *__ts)
|
||||||
|
{
|
||||||
|
using namespace _VSTD::chrono;
|
||||||
|
|
||||||
|
auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
|
||||||
|
auto abstime =
|
||||||
|
system_clock::time_point(duration_cast<system_clock::duration>(duration));
|
||||||
|
auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
|
||||||
|
|
||||||
|
if (!SleepConditionVariableSRW(__cv, __m,
|
||||||
|
timeout_ms.count() > 0 ? timeout_ms.count()
|
||||||
|
: 0,
|
||||||
|
0))
|
||||||
|
return GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
|
||||||
|
{
|
||||||
|
static_cast<void>(__cv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute Once
|
||||||
|
static inline _LIBCPP_ALWAYS_INLINE BOOL CALLBACK
|
||||||
|
__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
|
||||||
|
PVOID *__context)
|
||||||
|
{
|
||||||
|
static_cast<void>(__init_once);
|
||||||
|
static_cast<void>(__context);
|
||||||
|
|
||||||
|
void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
|
||||||
|
init_routine();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
|
||||||
|
void (*__init_routine)(void))
|
||||||
|
{
|
||||||
|
if (!InitOnceExecuteOnce(__flag, __libcpp_init_once_execute_once_thunk,
|
||||||
|
reinterpret_cast<void *>(__init_routine), NULL))
|
||||||
|
return GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread ID
|
||||||
|
bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
|
||||||
|
__libcpp_thread_id __rhs)
|
||||||
|
{
|
||||||
|
return __lhs == __rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
|
||||||
|
{
|
||||||
|
return __lhs < __rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread
|
||||||
|
struct __libcpp_beginthreadex_thunk_data
|
||||||
|
{
|
||||||
|
void *(*__func)(void *);
|
||||||
|
void *__arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI
|
||||||
|
__libcpp_beginthreadex_thunk(void *__data)
|
||||||
|
{
|
||||||
|
__libcpp_beginthreadex_thunk_data data =
|
||||||
|
*reinterpret_cast<__libcpp_beginthreadex_thunk_data *>(__data);
|
||||||
|
delete reinterpret_cast<__libcpp_beginthreadex_thunk_data *>(__data);
|
||||||
|
return reinterpret_cast<unsigned int>(data.__func(data.__arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
|
||||||
|
void *__arg)
|
||||||
|
{
|
||||||
|
auto *data = new __libcpp_beginthreadex_thunk_data;
|
||||||
|
data->__func = __func;
|
||||||
|
data->__arg = __arg;
|
||||||
|
|
||||||
|
*__t = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
|
||||||
|
__libcpp_beginthreadex_thunk,
|
||||||
|
data, 0, NULL));
|
||||||
|
if (*__t)
|
||||||
|
return 0;
|
||||||
|
return GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
__libcpp_thread_id __libcpp_thread_get_current_id()
|
||||||
|
{
|
||||||
|
return GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
|
||||||
|
{
|
||||||
|
return GetThreadId(*__t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_thread_join(__libcpp_thread_t *__t)
|
||||||
|
{
|
||||||
|
if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
|
||||||
|
return GetLastError();
|
||||||
|
if (!CloseHandle(*__t))
|
||||||
|
return GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_thread_detach(__libcpp_thread_t *__t)
|
||||||
|
{
|
||||||
|
if (!CloseHandle(*__t))
|
||||||
|
return GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libcpp_thread_yield()
|
||||||
|
{
|
||||||
|
SwitchToThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread Local Storage
|
||||||
|
int __libcpp_tls_create(__libcpp_tls_key* __key,
|
||||||
|
void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
|
||||||
|
{
|
||||||
|
*__key = FlsAlloc(__at_exit);
|
||||||
|
if (*__key == FLS_OUT_OF_INDEXES)
|
||||||
|
return GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__libcpp_tls_get(__libcpp_tls_key __key)
|
||||||
|
{
|
||||||
|
return FlsGetValue(__key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
|
||||||
|
{
|
||||||
|
if (!FlsSetValue(__key, __p))
|
||||||
|
return GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _LIBCPP_HAS_THREAD_API_PTHREAD
|
#endif // _LIBCPP_HAS_THREAD_API_PTHREAD
|
||||||
|
|
||||||
#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
|
#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ class __thread_specific_ptr
|
|||||||
__thread_specific_ptr(const __thread_specific_ptr&);
|
__thread_specific_ptr(const __thread_specific_ptr&);
|
||||||
__thread_specific_ptr& operator=(const __thread_specific_ptr&);
|
__thread_specific_ptr& operator=(const __thread_specific_ptr&);
|
||||||
|
|
||||||
static void __at_thread_exit(void*);
|
static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef _Tp* pointer;
|
typedef _Tp* pointer;
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
void
|
void _LIBCPP_TLS_DESTRUCTOR_CC
|
||||||
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
|
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
|
||||||
{
|
{
|
||||||
delete static_cast<pointer>(__p);
|
delete static_cast<pointer>(__p);
|
||||||
@@ -173,12 +174,10 @@ __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
|
|||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
__thread_specific_ptr<_Tp>::__thread_specific_ptr()
|
__thread_specific_ptr<_Tp>::__thread_specific_ptr()
|
||||||
{
|
{
|
||||||
int __ec = __libcpp_tls_create(
|
int __ec =
|
||||||
&__key_,
|
__libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
|
||||||
&__thread_specific_ptr::__at_thread_exit);
|
|
||||||
if (__ec)
|
if (__ec)
|
||||||
__throw_system_error(__ec,
|
__throw_system_error(__ec, "__thread_specific_ptr construction failed");
|
||||||
"__thread_specific_ptr construction failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
|
|||||||
Reference in New Issue
Block a user