mirror of
https://github.com/llvm-mirror/libcxx.git
synced 2025-10-24 03:32:35 +08:00
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(__sun__)
|
||||
# define _LIBCPP_HAS_THREAD_API_PTHREAD
|
||||
# elif defined(_LIBCPP_WIN32API)
|
||||
# define _LIBCPP_HAS_THREAD_API_WIN32
|
||||
# else
|
||||
# error "No thread API"
|
||||
# endif // _LIBCPP_HAS_THREAD_API
|
||||
|
@@ -24,6 +24,13 @@
|
||||
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||
# include <pthread.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
|
||||
|
||||
#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
|
||||
@@ -58,6 +65,33 @@ typedef pthread_t __libcpp_thread_t;
|
||||
|
||||
// Thrad Local Storage
|
||||
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
|
||||
|
||||
// Mutex
|
||||
@@ -144,7 +178,8 @@ void __libcpp_thread_yield();
|
||||
|
||||
// Thread local storage
|
||||
_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
|
||||
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);
|
||||
}
|
||||
|
||||
#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_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& operator=(const __thread_specific_ptr&);
|
||||
|
||||
static void __at_thread_exit(void*);
|
||||
static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
|
||||
|
||||
public:
|
||||
typedef _Tp* pointer;
|
||||
|
||||
@@ -164,7 +165,7 @@ public:
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
void
|
||||
void _LIBCPP_TLS_DESTRUCTOR_CC
|
||||
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
|
||||
{
|
||||
delete static_cast<pointer>(__p);
|
||||
@@ -173,12 +174,10 @@ __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
|
||||
template <class _Tp>
|
||||
__thread_specific_ptr<_Tp>::__thread_specific_ptr()
|
||||
{
|
||||
int __ec = __libcpp_tls_create(
|
||||
&__key_,
|
||||
&__thread_specific_ptr::__at_thread_exit);
|
||||
if (__ec)
|
||||
__throw_system_error(__ec,
|
||||
"__thread_specific_ptr construction failed");
|
||||
int __ec =
|
||||
__libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
|
||||
if (__ec)
|
||||
__throw_system_error(__ec, "__thread_specific_ptr construction failed");
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
|
Reference in New Issue
Block a user