Skip to content

Commit 6d7d0be

Browse files
committed
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. llvm-svn: 291333
1 parent cd71f44 commit 6d7d0be

3 files changed

Lines changed: 263 additions & 9 deletions

File tree

libcxx/include/__config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,8 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
913913
defined(__CloudABI__) || \
914914
defined(__sun__)
915915
# define _LIBCPP_HAS_THREAD_API_PTHREAD
916+
# elif defined(_LIBCPP_WIN32API)
917+
# define _LIBCPP_HAS_THREAD_API_WIN32
916918
# else
917919
# error "No thread API"
918920
# endif // _LIBCPP_HAS_THREAD_API

libcxx/include/__threading_support

Lines changed: 254 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
2525
# include <pthread.h>
2626
# include <sched.h>
27+
#elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
28+
#include <assert.h>
29+
#include <Windows.h>
30+
#include <process.h>
31+
#include <fibersapi.h>
32+
33+
#include <chrono>
2734
#endif
2835

2936
#if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
@@ -58,6 +65,33 @@ typedef pthread_t __libcpp_thread_t;
5865

5966
// Thrad Local Storage
6067
typedef pthread_key_t __libcpp_tls_key;
68+
69+
#define _LIBCPP_TLS_DESTRUCTOR_CC
70+
#else
71+
// Mutex
72+
typedef SRWLOCK __libcpp_mutex_t;
73+
#define _LIBCPP_MUTEX_INITIALIZER SRWLOCK_INIT
74+
75+
typedef CRITICAL_SECTION __libcpp_recursive_mutex_t;
76+
77+
// Condition Variable
78+
typedef CONDITION_VARIABLE __libcpp_condvar_t;
79+
#define _LIBCPP_CONDVAR_INITIALIZER CONDITION_VARIABLE_INIT
80+
81+
// Execute Once
82+
typedef INIT_ONCE __libcpp_exec_once_flag;
83+
#define _LIBCPP_EXEC_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT
84+
85+
// Thread ID
86+
typedef DWORD __libcpp_thread_id;
87+
88+
// Thread
89+
typedef HANDLE __libcpp_thread_t;
90+
91+
// Thread Local Storage
92+
typedef DWORD __libcpp_tls_key;
93+
94+
#define _LIBCPP_TLS_DESTRUCTOR_CC WINAPI
6195
#endif
6296

6397
// Mutex
@@ -144,7 +178,8 @@ void __libcpp_thread_yield();
144178

145179
// Thread local storage
146180
_LIBCPP_THREAD_ABI_VISIBILITY
147-
int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *));
181+
int __libcpp_tls_create(__libcpp_tls_key* __key,
182+
void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*));
148183

149184
_LIBCPP_THREAD_ABI_VISIBILITY
150185
void *__libcpp_tls_get(__libcpp_tls_key __key);
@@ -321,6 +356,224 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
321356
return pthread_setspecific(__key, __p);
322357
}
323358

359+
#elif defined(_LIBCPP_HAS_THREAD_API_WIN32)
360+
361+
// Mutex
362+
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
363+
{
364+
InitializeCriticalSection(__m);
365+
return 0;
366+
}
367+
368+
int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
369+
{
370+
EnterCriticalSection(__m);
371+
return 0;
372+
}
373+
374+
int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
375+
{
376+
TryEnterCriticalSection(__m);
377+
return 0;
378+
}
379+
380+
int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
381+
{
382+
LeaveCriticalSection(__m);
383+
return 0;
384+
}
385+
386+
int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
387+
{
388+
static_cast<void>(__m);
389+
return 0;
390+
}
391+
392+
int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
393+
{
394+
AcquireSRWLockExclusive(__m);
395+
return 0;
396+
}
397+
398+
int __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
399+
{
400+
TryAcquireSRWLockExclusive(__m);
401+
return 0;
402+
}
403+
404+
int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
405+
{
406+
ReleaseSRWLockExclusive(__m);
407+
return 0;
408+
}
409+
410+
int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
411+
{
412+
static_cast<void>(__m);
413+
return 0;
414+
}
415+
416+
// Condition Variable
417+
int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
418+
{
419+
WakeConditionVariable(__cv);
420+
return 0;
421+
}
422+
423+
int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
424+
{
425+
WakeAllConditionVariable(__cv);
426+
return 0;
427+
}
428+
429+
int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
430+
{
431+
SleepConditionVariableSRW(__cv, __m, INFINITE, 0);
432+
return 0;
433+
}
434+
435+
int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
436+
timespec *__ts)
437+
{
438+
using namespace _VSTD::chrono;
439+
440+
auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
441+
auto abstime =
442+
system_clock::time_point(duration_cast<system_clock::duration>(duration));
443+
auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
444+
445+
if (!SleepConditionVariableSRW(__cv, __m,
446+
timeout_ms.count() > 0 ? timeout_ms.count()
447+
: 0,
448+
0))
449+
return GetLastError();
450+
return 0;
451+
}
452+
453+
int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
454+
{
455+
static_cast<void>(__cv);
456+
return 0;
457+
}
458+
459+
// Execute Once
460+
static inline _LIBCPP_ALWAYS_INLINE BOOL CALLBACK
461+
__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
462+
PVOID *__context)
463+
{
464+
static_cast<void>(__init_once);
465+
static_cast<void>(__context);
466+
467+
void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
468+
init_routine();
469+
return TRUE;
470+
}
471+
472+
int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
473+
void (*__init_routine)(void))
474+
{
475+
if (!InitOnceExecuteOnce(__flag, __libcpp_init_once_execute_once_thunk,
476+
reinterpret_cast<void *>(__init_routine), NULL))
477+
return GetLastError();
478+
return 0;
479+
}
480+
481+
// Thread ID
482+
bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
483+
__libcpp_thread_id __rhs)
484+
{
485+
return __lhs == __rhs;
486+
}
487+
488+
bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
489+
{
490+
return __lhs < __rhs;
491+
}
492+
493+
// Thread
494+
struct __libcpp_beginthreadex_thunk_data
495+
{
496+
void *(*__func)(void *);
497+
void *__arg;
498+
};
499+
500+
static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI
501+
__libcpp_beginthreadex_thunk(void *__data)
502+
{
503+
__libcpp_beginthreadex_thunk_data data =
504+
*reinterpret_cast<__libcpp_beginthreadex_thunk_data *>(__data);
505+
delete reinterpret_cast<__libcpp_beginthreadex_thunk_data *>(__data);
506+
return reinterpret_cast<unsigned int>(data.__func(data.__arg));
507+
}
508+
509+
int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
510+
void *__arg)
511+
{
512+
auto *data = new __libcpp_beginthreadex_thunk_data;
513+
data->__func = __func;
514+
data->__arg = __arg;
515+
516+
*__t = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
517+
__libcpp_beginthreadex_thunk,
518+
data, 0, NULL));
519+
if (*__t)
520+
return 0;
521+
return GetLastError();
522+
}
523+
524+
__libcpp_thread_id __libcpp_thread_get_current_id()
525+
{
526+
return GetCurrentThreadId();
527+
}
528+
529+
__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
530+
{
531+
return GetThreadId(*__t);
532+
}
533+
534+
int __libcpp_thread_join(__libcpp_thread_t *__t)
535+
{
536+
if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
537+
return GetLastError();
538+
if (!CloseHandle(*__t))
539+
return GetLastError();
540+
return 0;
541+
}
542+
543+
int __libcpp_thread_detach(__libcpp_thread_t *__t)
544+
{
545+
if (!CloseHandle(*__t))
546+
return GetLastError();
547+
return 0;
548+
}
549+
550+
void __libcpp_thread_yield()
551+
{
552+
SwitchToThread();
553+
}
554+
555+
// Thread Local Storage
556+
int __libcpp_tls_create(__libcpp_tls_key* __key,
557+
void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
558+
{
559+
*__key = FlsAlloc(__at_exit);
560+
if (*__key == FLS_OUT_OF_INDEXES)
561+
return GetLastError();
562+
return 0;
563+
}
564+
565+
void *__libcpp_tls_get(__libcpp_tls_key __key)
566+
{
567+
return FlsGetValue(__key);
568+
}
569+
570+
int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
571+
{
572+
if (!FlsSetValue(__key, __p))
573+
return GetLastError();
574+
return 0;
575+
}
576+
324577
#endif // _LIBCPP_HAS_THREAD_API_PTHREAD
325578

326579
#endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL

libcxx/include/thread

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ class __thread_specific_ptr
148148
__thread_specific_ptr(const __thread_specific_ptr&);
149149
__thread_specific_ptr& operator=(const __thread_specific_ptr&);
150150

151-
static void __at_thread_exit(void*);
151+
static void _LIBCPP_TLS_DESTRUCTOR_CC __at_thread_exit(void*);
152+
152153
public:
153154
typedef _Tp* pointer;
154155

@@ -164,7 +165,7 @@ public:
164165
};
165166

166167
template <class _Tp>
167-
void
168+
void _LIBCPP_TLS_DESTRUCTOR_CC
168169
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
169170
{
170171
delete static_cast<pointer>(__p);
@@ -173,12 +174,10 @@ __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
173174
template <class _Tp>
174175
__thread_specific_ptr<_Tp>::__thread_specific_ptr()
175176
{
176-
int __ec = __libcpp_tls_create(
177-
&__key_,
178-
&__thread_specific_ptr::__at_thread_exit);
179-
if (__ec)
180-
__throw_system_error(__ec,
181-
"__thread_specific_ptr construction failed");
177+
int __ec =
178+
__libcpp_tls_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
179+
if (__ec)
180+
__throw_system_error(__ec, "__thread_specific_ptr construction failed");
182181
}
183182

184183
template <class _Tp>

0 commit comments

Comments
 (0)