[PATCH] D28220: provide Win32 native threading
compnerd closed this revision. compnerd added a comment. SVN r291333 Comment at: include/__threading_support:29-30 +#include +#define WIN32_LEAN_AND_MEAN +#include +#include majnemer wrote: > EricWF wrote: > > I think we agreed that we cannot use this macro. > Can we do as Reid suggests and not expose users to windows.h? I think that I would rather do that in a follow up. This will require a fair amount of duplication. https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF accepted this revision. EricWF added a comment. This revision is now accepted and ready to land. LGTM. I just successfully built this on Windows. https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include EricWF wrote: > smeenai wrote: > > EricWF wrote: > > > EricWF wrote: > > > > smeenai wrote: > > > > > EricWF wrote: > > > > > > > Can we do as Reid suggests and not expose users to windows.h? > > > > > > > > > > > > I was about to ask the same question. These includes are dragging > > > > > > in the `__deallocate` macro and I would love to avoid that. > > > > > I feel like we would end up with a //lot// of duplication if we went > > > > > down this route, since this is using a fair amount of Windows APIs. > > > > > @rnk suggested having a test for prototype mismatches, but even with > > > > > those checks there could be a high maintenance burden to the > > > > > duplication. > > > > > > > > > > Was the main objection to `WIN32_LEAN_AND_MEAN` that it would be > > > > > problematic for modules? If we're including `windows.h`, it seems > > > > > strictly preferable to include it with `WIN32_LEAN_AND_MEAN` than > > > > > without, since we'll pull in a lot less that way. Including > > > > > `windows.h` without `WIN32_LEAN_AND_MEAN` can also interact with > > > > > other headers badly sometimes, e.g. > > > > > [`winsock2.h`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms737629%28v=vs.85%29.aspx). > > > > It seems that dragging in the `__deallocate` macro is inevitable :-( > > > > > > > > I submitted a patch to work around `__deallocate` here: > > > > https://reviews.llvm.org/D28426 > > > > Was the main objection to WIN32_LEAN_AND_MEAN that it would be > > > > problematic for modules? If we're including windows.h, it seems > > > > strictly preferable to include it with WIN32_LEAN_AND_MEAN than > > > > without, since we'll pull in a lot less that way. Including windows.h > > > > without WIN32_LEAN_AND_MEAN can also interact with other headers badly > > > > sometimes, e.g. winsock2.h. > > > > > > The objection is that it breaks user code. For example: > > > > > > ``` > > > #include > > > #include // Windows.h already included as lean and mean. > > > > > > typedef NonLeanAndMeanSymbol foo; // ERROR NonLeanAndMeanSymbol not > > > defined > > > > > > ``` > > > > > But without the `WIN32_LEAN_AND_MEAN`, we're gonna break > > > > ``` > > #include > > #include > > ``` > > > > (you could fix this by reordering the includes, which would also fix your > > example, or by defining `WIN32_LEAN_AND_MEAN` yourself, but it doesn't seem > > great either) > I would much rather break that code. The fact that `Windows.h` doesn't play > nice with other Windows headers is a problem for Windows not libc++. Although I think avoiding the `Windows.h` include all together would be better (if possible). However I think that can be fixed after committing this. https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include smeenai wrote: > EricWF wrote: > > EricWF wrote: > > > smeenai wrote: > > > > EricWF wrote: > > > > > > Can we do as Reid suggests and not expose users to windows.h? > > > > > > > > > > I was about to ask the same question. These includes are dragging in > > > > > the `__deallocate` macro and I would love to avoid that. > > > > I feel like we would end up with a //lot// of duplication if we went > > > > down this route, since this is using a fair amount of Windows APIs. > > > > @rnk suggested having a test for prototype mismatches, but even with > > > > those checks there could be a high maintenance burden to the > > > > duplication. > > > > > > > > Was the main objection to `WIN32_LEAN_AND_MEAN` that it would be > > > > problematic for modules? If we're including `windows.h`, it seems > > > > strictly preferable to include it with `WIN32_LEAN_AND_MEAN` than > > > > without, since we'll pull in a lot less that way. Including `windows.h` > > > > without `WIN32_LEAN_AND_MEAN` can also interact with other headers > > > > badly sometimes, e.g. > > > > [`winsock2.h`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms737629%28v=vs.85%29.aspx). > > > It seems that dragging in the `__deallocate` macro is inevitable :-( > > > > > > I submitted a patch to work around `__deallocate` here: > > > https://reviews.llvm.org/D28426 > > > Was the main objection to WIN32_LEAN_AND_MEAN that it would be > > > problematic for modules? If we're including windows.h, it seems strictly > > > preferable to include it with WIN32_LEAN_AND_MEAN than without, since > > > we'll pull in a lot less that way. Including windows.h without > > > WIN32_LEAN_AND_MEAN can also interact with other headers badly sometimes, > > > e.g. winsock2.h. > > > > The objection is that it breaks user code. For example: > > > > ``` > > #include > > #include // Windows.h already included as lean and mean. > > > > typedef NonLeanAndMeanSymbol foo; // ERROR NonLeanAndMeanSymbol not defined > > > > ``` > > > But without the `WIN32_LEAN_AND_MEAN`, we're gonna break > > ``` > #include > #include > ``` > > (you could fix this by reordering the includes, which would also fix your > example, or by defining `WIN32_LEAN_AND_MEAN` yourself, but it doesn't seem > great either) I would much rather break that code. The fact that `Windows.h` doesn't play nice with other Windows headers is a problem for Windows not libc++. https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
smeenai added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include EricWF wrote: > EricWF wrote: > > smeenai wrote: > > > EricWF wrote: > > > > > Can we do as Reid suggests and not expose users to windows.h? > > > > > > > > I was about to ask the same question. These includes are dragging in > > > > the `__deallocate` macro and I would love to avoid that. > > > I feel like we would end up with a //lot// of duplication if we went down > > > this route, since this is using a fair amount of Windows APIs. @rnk > > > suggested having a test for prototype mismatches, but even with those > > > checks there could be a high maintenance burden to the duplication. > > > > > > Was the main objection to `WIN32_LEAN_AND_MEAN` that it would be > > > problematic for modules? If we're including `windows.h`, it seems > > > strictly preferable to include it with `WIN32_LEAN_AND_MEAN` than > > > without, since we'll pull in a lot less that way. Including `windows.h` > > > without `WIN32_LEAN_AND_MEAN` can also interact with other headers badly > > > sometimes, e.g. > > > [`winsock2.h`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms737629%28v=vs.85%29.aspx). > > It seems that dragging in the `__deallocate` macro is inevitable :-( > > > > I submitted a patch to work around `__deallocate` here: > > https://reviews.llvm.org/D28426 > > Was the main objection to WIN32_LEAN_AND_MEAN that it would be problematic > > for modules? If we're including windows.h, it seems strictly preferable to > > include it with WIN32_LEAN_AND_MEAN than without, since we'll pull in a lot > > less that way. Including windows.h without WIN32_LEAN_AND_MEAN can also > > interact with other headers badly sometimes, e.g. winsock2.h. > > The objection is that it breaks user code. For example: > > ``` > #include > #include // Windows.h already included as lean and mean. > > typedef NonLeanAndMeanSymbol foo; // ERROR NonLeanAndMeanSymbol not defined > > ``` > But without the `WIN32_LEAN_AND_MEAN`, we're gonna break ``` #include #include ``` (you could fix this by reordering the includes, which would also fix your example, or by defining `WIN32_LEAN_AND_MEAN` yourself, but it doesn't seem great either) https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include EricWF wrote: > smeenai wrote: > > EricWF wrote: > > > > Can we do as Reid suggests and not expose users to windows.h? > > > > > > I was about to ask the same question. These includes are dragging in the > > > `__deallocate` macro and I would love to avoid that. > > I feel like we would end up with a //lot// of duplication if we went down > > this route, since this is using a fair amount of Windows APIs. @rnk > > suggested having a test for prototype mismatches, but even with those > > checks there could be a high maintenance burden to the duplication. > > > > Was the main objection to `WIN32_LEAN_AND_MEAN` that it would be > > problematic for modules? If we're including `windows.h`, it seems strictly > > preferable to include it with `WIN32_LEAN_AND_MEAN` than without, since > > we'll pull in a lot less that way. Including `windows.h` without > > `WIN32_LEAN_AND_MEAN` can also interact with other headers badly sometimes, > > e.g. > > [`winsock2.h`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms737629%28v=vs.85%29.aspx). > It seems that dragging in the `__deallocate` macro is inevitable :-( > > I submitted a patch to work around `__deallocate` here: > https://reviews.llvm.org/D28426 > Was the main objection to WIN32_LEAN_AND_MEAN that it would be problematic > for modules? If we're including windows.h, it seems strictly preferable to > include it with WIN32_LEAN_AND_MEAN than without, since we'll pull in a lot > less that way. Including windows.h without WIN32_LEAN_AND_MEAN can also > interact with other headers badly sometimes, e.g. winsock2.h. The objection is that it breaks user code. For example: ``` #include #include // Windows.h already included as lean and mean. typedef NonLeanAndMeanSymbol foo; // ERROR NonLeanAndMeanSymbol not defined ``` https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include smeenai wrote: > EricWF wrote: > > > Can we do as Reid suggests and not expose users to windows.h? > > > > I was about to ask the same question. These includes are dragging in the > > `__deallocate` macro and I would love to avoid that. > I feel like we would end up with a //lot// of duplication if we went down > this route, since this is using a fair amount of Windows APIs. @rnk suggested > having a test for prototype mismatches, but even with those checks there > could be a high maintenance burden to the duplication. > > Was the main objection to `WIN32_LEAN_AND_MEAN` that it would be problematic > for modules? If we're including `windows.h`, it seems strictly preferable to > include it with `WIN32_LEAN_AND_MEAN` than without, since we'll pull in a lot > less that way. Including `windows.h` without `WIN32_LEAN_AND_MEAN` can also > interact with other headers badly sometimes, e.g. > [`winsock2.h`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms737629%28v=vs.85%29.aspx). It seems that dragging in the `__deallocate` macro is inevitable :-( I submitted a patch to work around `__deallocate` here: https://reviews.llvm.org/D28426 https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
smeenai added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include EricWF wrote: > > Can we do as Reid suggests and not expose users to windows.h? > > I was about to ask the same question. These includes are dragging in the > `__deallocate` macro and I would love to avoid that. I feel like we would end up with a //lot// of duplication if we went down this route, since this is using a fair amount of Windows APIs. @rnk suggested having a test for prototype mismatches, but even with those checks there could be a high maintenance burden to the duplication. Was the main objection to `WIN32_LEAN_AND_MEAN` that it would be problematic for modules? If we're including `windows.h`, it seems strictly preferable to include it with `WIN32_LEAN_AND_MEAN` than without, since we'll pull in a lot less that way. Including `windows.h` without `WIN32_LEAN_AND_MEAN` can also interact with other headers badly sometimes, e.g. [`winsock2.h`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms737629%28v=vs.85%29.aspx). https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd removed rL LLVM as the repository for this revision. compnerd updated this revision to Diff 83469. compnerd marked 2 inline comments as done. compnerd added a comment. remove `WIN32_LEAN_AND_MEAN`, fix decoration, remove inline decorations https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support include/thread Index: include/thread === --- include/thread +++ include/thread @@ -148,7 +148,8 @@ __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,21 +165,19 @@ }; template -void +void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) { delete static_cast(__p); } template __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 Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -24,6 +24,13 @@ #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) # include # include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#include +#include +#include + +#include #endif #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ @@ -58,6 +65,33 @@ // 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 @@ // 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 @@ 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(__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(__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(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + + if (!SleepConditionVariableSRW(__cv, __m, +
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:30 +#define WIN32_LEAN_AND_MEAN +#include +#include > Can we do as Reid suggests and not expose users to windows.h? I was about to ask the same question. These includes are dragging in the `__deallocate` macro and I would love to avoid that. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:580 +int __libcpp_tls_create(__libcpp_tls_key* __key, +void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*)) +{ The `_LIBCPP_TLS_DESTRUCTOR_CC` needs to appear an the initial declaration as well. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
majnemer added inline comments. Comment at: include/__threading_support:29-30 +#include +#define WIN32_LEAN_AND_MEAN +#include +#include EricWF wrote: > I think we agreed that we cannot use this macro. Can we do as Reid suggests and not expose users to windows.h? Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:29 +#include +#define WIN32_LEAN_AND_MEAN +#include I think we agreed that we cannot use this macro. Comment at: include/__threading_support:426 +// Condition Variable +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) DO NOT ANNOTATE THESE DEFINITIONS!! The forward declarations are already properly declared. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added a comment. Just tried the updated patch and I still get one build error: C:\Users\Eric\workspace\libcxx\src\thread.cpp(135,16): error: use of undeclared identifier 'nanosleep' while (nanosleep(, ) == -1 && errno == EINTR) Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd set the repository for this revision to rL LLVM. compnerd updated this revision to Diff 83453. Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support include/thread Index: include/thread === --- include/thread +++ include/thread @@ -148,7 +148,8 @@ __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,21 +165,19 @@ }; template -void +void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) { delete static_cast(__p); } template __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 Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -24,6 +24,14 @@ #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) # include # include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include #endif #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ @@ -58,6 +66,33 @@ // 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 @@ -321,6 +356,249 @@ 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_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + EnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + TryEnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) +{ + LeaveCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + static_cast(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + TryAcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t *__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_t *__m) +{ + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +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(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + + if (!SleepConditionVariableSRW(__cv, __m, + timeout_ms.count() > 0 ? timeout_ms.count() +: 0, + 0)) +return
[PATCH] D28220: provide Win32 native threading
EricWF added a comment. I'm seeing the following build errors on Windows: C:\Users\Eric\workspace\libcxx\include\__threading_support(521,3): warning: cannot delete expression with pointer-to-'void' type 'void *' [-Wdelete-incomplete] delete __data; ^ ~~ C:\Users\Eric\workspace\libcxx\include\__threading_support(530,18): error: assigning to 'void *(*)(void *)' from incompatible type 'void (*)(void *)': different return type ('void *' vs 'void') data->__func = __func; ^~ C:\Users\Eric\workspace\libcxx\include\__threading_support(572,5): error: functions that differ only in their return type cannot be overloaded int __libcpp_thread_yield() ~~~ ^ C:\Users\Eric\workspace\libcxx\include\__threading_support(178,6): note: previous declaration is here void __libcpp_thread_yield(); ^ C:\Users\Eric\workspace\libcxx\include\__threading_support(589,5): error: functions that differ only in their return type cannot be overloaded int __libcpp_tls_get(__libcpp_tls_key __key) ~~~ ^ C:\Users\Eric\workspace\libcxx\include\__threading_support(185,7): note: previous declaration is here void *__libcpp_tls_get(__libcpp_tls_key __key); ~~^ C:\Users\Eric\workspace\libcxx\include\__threading_support(591,10): error: cannot initialize return object of type 'int' with an rvalue of type 'PVOID' (aka 'void *') return FlsGetValue(__key); https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
halyavin added a comment. LGTM. Comment at: include/__threading_support:480 + if (!SleepConditionVariableSRW(__cv, __m, + timeout_ms.count() > 0 ? timeout_ms.count() +: 0, There is still problem with large timeout but let us fix it later. https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd removed rL LLVM as the repository for this revision. compnerd updated this revision to Diff 83432. compnerd added a comment. rebase https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support include/thread Index: include/thread === --- include/thread +++ include/thread @@ -148,7 +148,8 @@ __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,21 +165,19 @@ }; template -void +void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) { delete static_cast(__p); } template __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 Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -24,6 +24,14 @@ #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) # include # include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include #endif #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ @@ -58,6 +66,33 @@ // 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 @@ -321,6 +356,249 @@ 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_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + EnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + TryEnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) +{ + LeaveCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + static_cast(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + TryAcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t *__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_t *__m) +{ + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +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(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + + if (!SleepConditionVariableSRW(__cv, __m, + timeout_ms.count() > 0 ? timeout_ms.count() +: 0, +
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 83430. compnerd marked an inline comment as done. compnerd added a comment. rebase, address negative timeouts, fix thunking for `__libcpp_tls_create` Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support include/thread Index: include/thread === --- include/thread +++ include/thread @@ -148,7 +148,8 @@ __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,21 +165,19 @@ }; template -void +void _LIBCPP_TLS_DESTRUCTOR_CC __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) { delete static_cast(__p); } template __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 Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -47,6 +47,14 @@ defined(_LIBCPP_HAS_THREAD_API_EXTERNAL_PTHREAD) #include #include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include #endif #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) @@ -81,6 +89,33 @@ // 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 @@ -342,6 +377,249 @@ 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_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + EnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + TryEnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) +{ + LeaveCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + static_cast(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + TryAcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t *__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_t *__m) +{ + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +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(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + + if (!SleepConditionVariableSRW(__cv, __m, + timeout_ms.count() > 0 ? timeout_ms.count() +
[PATCH] D28220: provide Win32 native threading
EricWF requested changes to this revision. EricWF added a comment. This revision now requires changes to proceed. This needs to be rebased following the `<__threading_support>` cleanup in r291275. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
halyavin added inline comments. Comment at: include/__threading_support:474 + system_clock::time_point(duration_cast(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + compnerd wrote: > halyavin wrote: > > Since negative timeouts can't be avoided, we must make sure that > > timeout_ms.count() is at least zero. > Good point. I suppose that the assert takes care of that though. Negative timeout_ms.count() is a normal case, we shouldn't fail on assertion. The reason is that program can always be slow enough for current timestamp (system_clock::now()) to pass any fixed point in time (__ts/abstime). Comment at: include/__threading_support:476 + + _LIBCPP_ASSERT(timeout_ms.count() > INFINITE && "timeout duration overflow"); + if (!SleepConditionVariableSRW(__cv, __m, timeout_ms.count(), 0)) compnerd wrote: > halyavin wrote: > > It is >= INFINITE. _LIBCPP_ASSERT has 2 arguments and supports error > > message out of the box. > Shouldnt this be, `timeout_ms.count() > 0` which implicitly ensures that it > is not `INFINITE` (-1)? I just checked in the Windows SDK, INFINITE is defined as `0x` and negative timeouts are legal anyway. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd marked an inline comment as done. compnerd added inline comments. Comment at: include/__threading_support:474 + system_clock::time_point(duration_cast(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + halyavin wrote: > Since negative timeouts can't be avoided, we must make sure that > timeout_ms.count() is at least zero. Good point. I suppose that the assert takes care of that though. Comment at: include/__threading_support:476 + + _LIBCPP_ASSERT(timeout_ms.count() > INFINITE && "timeout duration overflow"); + if (!SleepConditionVariableSRW(__cv, __m, timeout_ms.count(), 0)) halyavin wrote: > It is >= INFINITE. _LIBCPP_ASSERT has 2 arguments and supports error message > out of the box. Shouldnt this be, `timeout_ms.count() > 0` which implicitly ensures that it is not `INFINITE` (-1)? Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
halyavin added inline comments. Comment at: include/__threading_support:474 + system_clock::time_point(duration_cast(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + Since negative timeouts can't be avoided, we must make sure that timeout_ms.count() is at least zero. Comment at: include/__threading_support:476 + + _LIBCPP_ASSERT(timeout_ms.count() > INFINITE && "timeout duration overflow"); + if (!SleepConditionVariableSRW(__cv, __m, timeout_ms.count(), 0)) It is >= INFINITE. _LIBCPP_ASSERT has 2 arguments and supports error message out of the box. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF accepted this revision. EricWF added a comment. This revision is now accepted and ready to land. This LGTM. I'm sure we can flush out any bugs once we get the tests running. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 83182. compnerd marked an inline comment as done. compnerd added a comment. Fix `__libcpp_condvar_timedwait` parameter usage (absolute vs relative time) Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -47,6 +47,15 @@ defined(_LIBCPP_HAS_THREAD_API_EXTERNAL_PTHREAD) #include #include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include <__debug> +#include #endif #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) @@ -81,6 +90,29 @@ // Thrad Local Storage typedef pthread_key_t __libcpp_tls_key; +#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; #endif // Mutex @@ -342,6 +374,247 @@ 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_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + EnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + TryEnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) +{ + LeaveCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + static_cast(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + TryAcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t *__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_t *__m) +{ + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +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(duration)); + auto timeout_ms = duration_cast(abstime - system_clock::now()); + + _LIBCPP_ASSERT(timeout_ms.count() > INFINITE && "timeout duration overflow"); + 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_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter, + PVOID *__context) +{ + static_cast(__init_once); + 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_execute_once_thunk, + 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; +} + +//
[PATCH] D28220: provide Win32 native threading
compnerd marked an inline comment as done. compnerd added inline comments. Comment at: include/__threading_support:458 + __libcpp_mutex_reference&& __m, + timespec* __ts) +{ halyavin wrote: > In posix, pthread_cond_timedwait uses absolute time but we use relative time > here. Good catch. I guess we have to convert the timespec to a relative time before using it. Slightly annoying, but thankfully, we can fallback on chrono :-). Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 83178. compnerd added a comment. Address a number of review comments. Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -47,6 +47,15 @@ defined(_LIBCPP_HAS_THREAD_API_EXTERNAL_PTHREAD) #include #include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include <__debug> +#include #endif #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) @@ -81,6 +90,29 @@ // Thrad Local Storage typedef pthread_key_t __libcpp_tls_key; +#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; #endif // Mutex @@ -342,6 +374,244 @@ 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_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + EnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + TryEnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) +{ + LeaveCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + static_cast(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + TryAcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t *__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_t *__m) +{ + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__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() > INFINITE && "timeout duration overflow"); + 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_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter, + PVOID *__context) +{ + static_cast(__init_once); + 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_execute_once_thunk, + 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; +} + +// Thread +struct __libcpp_beginthreadex_thunk_data +{ + void *(*__func)(void *); + void *__arg; +}; + +static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI
[PATCH] D28220: provide Win32 native threading
compnerd marked 6 inline comments as done. compnerd added inline comments. Comment at: include/__threading_support:527 +static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI +__libcpp_thread_trampoline(void *__data) +{ rnk wrote: > halyavin wrote: > > Trampolines will never be inlined. Should we put them in support *.cpp > > instead? The downside is new public symbols which can't be changed without > > breaking backward compatibility. The upside is that we will have only one > > copy of each trampoline. What do you think? > Considering that libc++ already has a __thread_proxy trampoline, let's just > give it the right CC and get rid of this trampoline. I think I prefer @rnk's solution here. Lets try to use the `__thread_proxy` to hide the thunk. Comment at: include/__threading_support:532 + _VSTD::free(__data); + return reinterpret_cast(data.__func(data.__arg)); +} halyavin wrote: > Should we even try to pass thread exit code, given that sizeof(unsigned int) > < sizeof(void*) on 64-bit system? std::thread doesn't support thread exit > code anyway. Im not sure what the cleanest way to address this is. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated the summary for this revision. compnerd updated this revision to Diff 83174. Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support Index: include/__threading_support === --- include/__threading_support +++ include/__threading_support @@ -47,6 +47,12 @@ defined(_LIBCPP_HAS_THREAD_API_EXTERNAL_PTHREAD) #include #include +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include #endif #if defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) @@ -81,6 +87,29 @@ // Thrad Local Storage typedef pthread_key_t __libcpp_tls_key; +#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; #endif // Mutex @@ -342,6 +371,247 @@ 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_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + EnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + TryEnterCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m) +{ + LeaveCriticalSection(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + static_cast(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + TryAcquireSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t *__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_t *__m) +{ + SleepConditionVariableSRW(__cv, __m, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__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 overflow"); + + 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_execute_once_thunk(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_execute_once_thunk, + 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; +} + +// Thread +struct __libcpp_beginthreadex_thunk_data +{ + void *(*__func)(void *); + void *__arg; +}; + +static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI +__libcpp_beginthreadex_thunk(void *__data) +{ +
[PATCH] D28220: provide Win32 native threading
rnk added inline comments. Comment at: include/__threading_support:44 +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#include kimgr wrote: > EricWF wrote: > > compnerd wrote: > > > EricWF wrote: > > > > Do these definitions have any affect when `` has already > > > > been included? > > > > Also are these definitions required before including the header, or > > > > merely beneficial? If they are required this will make the > > > > `` header a pain to use with modules. > > > > > > > > > > > No, they dont effect it once it has been included. They are beneficial > > > since they reduce the amount of stuff that gets included (including > > > things which, at least when I last checked, can cause clang to choke). > > And can users re-include `` afterwards in the same TU and get > > all of the symbols? > I don't think so. > > We've recently switched to defining these two symbols in our build system, > and I think that's basically the only way to make this work in a project > composed of headers from various authors. I think you're right that libc++ > should not define them. I don't think libc++ should not include windows.h in a public header. I'd rather write our own __threading_support_win.h that re-prototypes everything we need from windows.h, and then we can have some test in libc++ that validates that there are no mismatches when including windows.h before libc++ . If we do this, we should sink as much win32 API usage as possible out of headers to reduce our duplication. It's worth pointing out VS 2015's thread implementation also hides its win32 API usage. Comment at: include/__threading_support:527 +static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI +__libcpp_thread_trampoline(void *__data) +{ halyavin wrote: > Trampolines will never be inlined. Should we put them in support *.cpp > instead? The downside is new public symbols which can't be changed without > breaking backward compatibility. The upside is that we will have only one > copy of each trampoline. What do you think? Considering that libc++ already has a __thread_proxy trampoline, let's just give it the right CC and get rid of this trampoline. Comment at: include/__threading_support:593 +{ + // TODO(compnerd) provide a wrapper for CC adjustment + *__key = FlsAlloc(reinterpret_cast(__at_exit)); Yeah, we need to fix that. We should find a way to make `__thread_specific_ptr::__at_thread_exit(void*)` have the right convention out of the box, rather than thunking. Something like: #define __LIBCPP_TLS_CALLBACK_CC WINAPI .. // else #define __LIBCPP_TLS_CALLBACK_CC ... // static void __LIBCPP_TLS_CALLBACK_CC __at_thread_exit(void*); Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
halyavin added inline comments. Comment at: include/__threading_support:458 + __libcpp_mutex_reference&& __m, + timespec* __ts) +{ In posix, pthread_cond_timedwait uses absolute time but we use relative time here. Comment at: include/__threading_support:460 +{ + using namespace _VSTD::chrono; + auto timeout = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec); We need to include to use types and functions from this namespace. Comment at: include/__threading_support:464 + + _LIBCPP_ASSERT(timeout_ms.count() < _VSTD::numeric_limits::max(), + "timeout duration overflows"); You have done it accidentally right. I realized there is a second problem here - if timeout equals to INFINITE, the thread will wait forever. INFINITE equals to (DWORD)-1, so the strict sign in the assert is required. But for sanity sake _VSTD::numeric_limits::max() should be replaced with INFINITE. Comment at: include/__threading_support:486 +static inline _LIBCPP_ALWAYS_INLINE BOOL CALLBACK +__libcpp_init_once_trampoline(PINIT_ONCE InitOnce, PVOID Parameter, + PVOID *Context) We need underscores for parameters and init_routine. Comment at: include/__threading_support:497 + +int __libcpp_execute_once(__libcpp_exec_once_flag* flag, + void (*init_routine)(void)) Underscores for parameters are missing. Comment at: include/__threading_support:527 +static inline _LIBCPP_ALWAYS_INLINE unsigned int WINAPI +__libcpp_thread_trampoline(void *__data) +{ Trampolines will never be inlined. Should we put them in support *.cpp instead? The downside is new public symbols which can't be changed without breaking backward compatibility. The upside is that we will have only one copy of each trampoline. What do you think? Comment at: include/__threading_support:531 + *(__libcpp_thread_trampoline_data*)__data; + _VSTD::free(__data); + return reinterpret_cast(data.__func(data.__arg)); Do we need #include for free() and malloc() now? Can we use new/delete instead? BTW, What is the purpose of _VSTD? I think it is used to prevent argument-dependent lookup and so is not needed for free and malloc. Comment at: include/__threading_support:532 + _VSTD::free(__data); + return reinterpret_cast(data.__func(data.__arg)); +} Should we even try to pass thread exit code, given that sizeof(unsigned int) < sizeof(void*) on 64-bit system? std::thread doesn't support thread exit code anyway. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 82954. compnerd added a comment. Remove incorrect use of `VC_EXTRALEAN`. Fix signature for `__libcpp_set_thread_specific`. Provide CC adjustment thunks for the thread creation. Add an assertion for sleep timeout truncation. Implement exec-once interfaces. Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support 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(); +
[PATCH] D28220: provide Win32 native threading
halyavin added inline comments. Comment at: include/__threading_support:421 +if (!SleepConditionVariableCS(__cv, __m, + duration_cast(timeout).count())) + return GetLastError(); We can have integer overflow on cast to DWORD here and get unexpectedly small wait for large timeouts. Comment at: include/__threading_support:458 +{ + // TODO(compnerd) provide a wrapper for CC adjustment + *__t = reinterpret_cast(_beginthreadex( For other reviewers: CC means Calling Convention. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
awson added a comment. You don't need #define VC_EXTRA_LEAN since: 1. VC_EXTRA_LEAN is a mistype, only VC_EXTRALEAN has some meaning in Windows ecosystem; 2. VC_EXTRALEAN is used *only* in MFC headers which obviously aren't used in clang codebase. Thus it would be better to remove this altogether, and (perhaps) replace with the relevant #define WIN32_LEAN_AND_MEAN. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
kimgr added a comment. Re Eric's windows.h concern. Comment at: include/__threading_support:44 +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#include EricWF wrote: > compnerd wrote: > > EricWF wrote: > > > Do these definitions have any affect when `` has already been > > > included? > > > Also are these definitions required before including the header, or > > > merely beneficial? If they are required this will make the `` > > > header a pain to use with modules. > > > > > > > > No, they dont effect it once it has been included. They are beneficial > > since they reduce the amount of stuff that gets included (including things > > which, at least when I last checked, can cause clang to choke). > And can users re-include `` afterwards in the same TU and get all > of the symbols? I don't think so. We've recently switched to defining these two symbols in our build system, and I think that's basically the only way to make this work in a project composed of headers from various authors. I think you're right that libc++ should not define them. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added inline comments. Comment at: include/__threading_support:44 +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#include compnerd wrote: > EricWF wrote: > > Do these definitions have any affect when `` has already been > > included? > > Also are these definitions required before including the header, or merely > > beneficial? If they are required this will make the `` header a > > pain to use with modules. > > > > > No, they dont effect it once it has been included. They are beneficial since > they reduce the amount of stuff that gets included (including things which, > at least when I last checked, can cause clang to choke). And can users re-include `` afterwards in the same TU and get all of the symbols? Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd added inline comments. Comment at: include/__threading_support:46 +inline _LIBCPP_INLINE_VISIBILITY +int __libcpp_recursive_mutex_init(__libcpp_mutex_t *__m); + EricWF wrote: > The forward declarations of the `__libcpp_` threading wrapper should be > shared between all API's. Please don't add your own forward declarations for > Windows. Yeah, restructed that. There is now the dependent patch for the type-erased mutex handling. Comment at: include/__threading_support:44 +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#include EricWF wrote: > Do these definitions have any affect when `` has already been > included? > Also are these definitions required before including the header, or merely > beneficial? If they are required this will make the `` header a > pain to use with modules. > > No, they dont effect it once it has been included. They are beneficial since they reduce the amount of stuff that gets included (including things which, at least when I last checked, can cause clang to choke). Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 82846. compnerd added a comment. add more context Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support 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)
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 82843. compnerd added a comment. update for separation of mutex and recursive_mutex. Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support 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
[PATCH] D28220: provide Win32 native threading
smeenai added inline comments. Comment at: include/__threading_support:300-305 +int __libcpp_recursive_mutex_init(__libcpp_mutex_t *__m) +{ + InitializeSRWLock(__m); + return 0; +} + majnemer wrote: > compnerd wrote: > > majnemer wrote: > > > I don't think you can use slim rw locks for recursive locks. I think we > > > will need to use `CRITICAL_SECTION` for those. std::recursive_mutex can't > > > be used with std::condition_variable AFAIK so all you need (I think) is > > > recursive versions of `__libcpp_mutex_...` > > > > > > Recursive locks should be used far less frequently which makes it > > > valuable, IMO, to use slim rw locks for the non-recursive mutex > > > implementation. > > You are absolutely right. That was something that I looked at originally > > and went with the CS. However, the overhead of a tagged struct is 5 or 9 > > bytes (sizeof(void *) + 1) bytes (ignoring padding for MS ABI). Going with > > that should give the benefits of always being able to properly initialize > > the CS instead of the kludge. > Er, isn't the overhead much more than that? IIRC, `CRITICAL_SECTION` is quite > large. You'd be making all the users of `std::mutex` pay for the space of > `std::recursive_mutex`... Yeah, CRITICAL_SECTION is 24 bytes vs 4 bytes for a SRWLOCK. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
smeenai added inline comments. Comment at: include/__threading_support:83 +} __libcpp_mutex_t; +#define _LIBCPP_MUTEX_INITIALIZER {{0}, SRWLOCK_INIT, 0} + Why not a tagged union? Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
majnemer added inline comments. Comment at: include/__threading_support:300-305 +int __libcpp_recursive_mutex_init(__libcpp_mutex_t *__m) +{ + InitializeSRWLock(__m); + return 0; +} + compnerd wrote: > majnemer wrote: > > I don't think you can use slim rw locks for recursive locks. I think we > > will need to use `CRITICAL_SECTION` for those. std::recursive_mutex can't > > be used with std::condition_variable AFAIK so all you need (I think) is > > recursive versions of `__libcpp_mutex_...` > > > > Recursive locks should be used far less frequently which makes it valuable, > > IMO, to use slim rw locks for the non-recursive mutex implementation. > You are absolutely right. That was something that I looked at originally and > went with the CS. However, the overhead of a tagged struct is 5 or 9 bytes > (sizeof(void *) + 1) bytes (ignoring padding for MS ABI). Going with that > should give the benefits of always being able to properly initialize the CS > instead of the kludge. Er, isn't the overhead much more than that? IIRC, `CRITICAL_SECTION` is quite large. You'd be making all the users of `std::mutex` pay for the space of `std::recursive_mutex`... Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
EricWF added a comment. Could you upload this patch with more context? Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 82834. compnerd added a comment. switch between a CRITICAL_SECTION and SRWLOCK Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support 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) @@ -62,6 +73,28 @@ // Thrad Local Storage typedef pthread_key_t __libcpp_tls_key; +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) +// Mutex +typedef struct { + CRITICAL_SECTION __mutex; + SRWLOCK __lock; + unsigned char __use_mutex : 1; + unsigned char __reserved : 7; +} __libcpp_mutex_t; +#define _LIBCPP_MUTEX_INITIALIZER {{0}, SRWLOCK_INIT, 0} + +// 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 // Mutex @@ -267,6 +300,192 @@ pthread_setspecific(__key, __p); } +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) + +// Mutex +_LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_init(__libcpp_mutex_t* __m) +{ + if (__m->__use_mutex) +return 0; + InitializeCriticalSection(&__m->__mutex); + __m->__use_mutex = 1; + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t* __m) +{ + if (__m->__use_mutex) +EnterCriticalSection(&__m->__mutex); + else +AcquireSRWLockExclusive(&__m->__lock); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t* __m) +{ + if (__m->__use_mutex) +return TryEnterCriticalSection(&__m->__mutex); + return TryAcquireSRWLockExclusive(&__m->__lock); +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) +{ + if (__m->__use_mutex) +LeaveCriticalSection(&__m->__mutex); + else +ReleaseSRWLockExclusive(&__m->__lock); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t* __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_t* __m) +{ + if (__m->__use_mutex) +SleepConditionVariableCS(__cv, &__m->__mutex, INFINITE); + else +SleepConditionVariableSRW(__cv, &__m->__lock, INFINITE, 0); + return 0; +} + +_LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, + timespec* __ts) +{ + using namespace _VSTD::chrono; + auto timeout = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec); + if (__m->__use_mutex) { +if (!SleepConditionVariableCS(__cv, &__m->__mutex, + duration_cast(timeout).count())) + return GetLastError(); + } else { +// TODO(compnerd) handle timeouts < 10ms +if (!SleepConditionVariableSRW(__cv, &__m->__lock, + 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); +} +
[PATCH] D28220: provide Win32 native threading
compnerd added inline comments. Comment at: include/__threading_support:300-305 +int __libcpp_recursive_mutex_init(__libcpp_mutex_t *__m) +{ + InitializeSRWLock(__m); + return 0; +} + majnemer wrote: > I don't think you can use slim rw locks for recursive locks. I think we will > need to use `CRITICAL_SECTION` for those. std::recursive_mutex can't be used > with std::condition_variable AFAIK so all you need (I think) is recursive > versions of `__libcpp_mutex_...` > > Recursive locks should be used far less frequently which makes it valuable, > IMO, to use slim rw locks for the non-recursive mutex implementation. You are absolutely right. That was something that I looked at originally and went with the CS. However, the overhead of a tagged struct is 5 or 9 bytes (sizeof(void *) + 1) bytes (ignoring padding for MS ABI). Going with that should give the benefits of always being able to properly initialize the CS instead of the kludge. Comment at: include/__threading_support:355 + // TODO(compnerd) handle spurious timeout + if (!SleepConditionVariableSRW(__cv, __m, + duration_cast(timeout).count(), majnemer wrote: > I don't think it should be `__libcpp_condvar_timedwait'`s problem. > `__libcpp_condvar_timedwait` wraps `pthread_cond_timedwait` on POSIX > platforms and the caller of `__libcpp_condvar_wait` properly handles spurious > wakeups. The caller of `__libcpp_condvar_timedwait` probably should be > audited. SG; seems that there is a single user in condition_variable.cpp Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd updated this revision to Diff 82826. compnerd added a comment. Use SRW locks, rebase for avoid redeclaration of interfaces, remove static initialization check removals. Repository: rL LLVM https://reviews.llvm.org/D28220 Files: include/__config include/__threading_support 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) @@ -62,6 +73,23 @@ // 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 + +// 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 // Mutex @@ -267,6 +295,150 @@ pthread_setspecific(__key, __p); } +#elif defined(_LIBCPP_HAS_THREAD_API_WIN32) + +// Mutex +int __libcpp_recursive_mutex_init(__libcpp_mutex_t *__m) +{ + InitializeSRWLock(__m); + return 0; +} + +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + AcquireSRWLockExclusive(__m); + return 0; +} + +int __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + return TryAcquireSRWLockExclusive(__m); +} + +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + ReleaseSRWLockExclusive(__m); + return 0; +} + +int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) +{ + static_cast(__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 timeout = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec); + // TODO(compnerd) handle timeouts < 10ms + // TODO(compnerd) handle spurious timeout + if (!SleepConditionVariableSRW(__cv, __m, + duration_cast(timeout).count(), + 0)) +return GetLastError(); + return 0; +} + +int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) +{ + static_cast(__cv); + 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 +int __libcpp_thread_create(__libcpp_thread_t *__t, + unsigned int (* WINAPI __func)(void *), void *__arg) +{ + *__t = + reinterpret_cast(_beginthreadex(NULL, 0, __func, __arg, 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 (* WINAPI __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); +} + +void __libcpp_tls_set(__libcpp_tls_key __key, void *__p) +{ + FlsSetValue(__key, __p); +} + #endif // _LIBCPP_HAS_THREAD_API_PTHREAD _LIBCPP_END_NAMESPACE_STD Index: include/__config === --- include/__config +++ include/__config @@ -882,6 +882,8 @@ defined(__CloudABI__) || \ defined(__sun__) # define
[PATCH] D28220: provide Win32 native threading
compnerd marked 3 inline comments as done. compnerd added a comment. The SRW initializers avoid the initializer changes, so its one less set of changes that is necessary. Comment at: include/__threading_support:33 #include <__external_threading> +#elif defined(_WIN32) && defined(_LIBCPP_HAS_THREAD_API_WIN32) +#define WIN32_LEAN_AND_MEAN EricWF wrote: > Isn't checking `_LIBCPP_HAS_THREAD_API_WIN32` enough? No, because the structure of the header is such that it requires redeclarations :-(. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
majnemer added a comment. In https://reviews.llvm.org/D28220#633622, @compnerd wrote: > @majnemer Im using the Fls* APIs since they provide the thread termination > callback, which Tls* doesn't. Good point about the SRW. Those are newer, > but, we can always provide a fallback later. I don't believe they are newer than the condition variable API so all should be fine. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
compnerd added a comment. @majnemer Im using the Fls* APIs since they provide the thread termination callback, which Tls* doesn't. Good point about the SRW. Those are newer, but, we can always provide a fallback later. Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D28220: provide Win32 native threading
majnemer added a comment. slim reader-writer locks are faster than critical sections, I'd recommend your implementation switch to those. Also, why do you use Fls instead of Tls? Repository: rL LLVM https://reviews.llvm.org/D28220 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits