diff --git a/stl/inc/mutex b/stl/inc/mutex index eea7d5426a..6c2a7216b5 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -35,8 +35,21 @@ class condition_variable_any; class _Mutex_base { // base class for all mutex types public: - _Mutex_base(int _Flags = 0) noexcept { - _Mtx_init_in_situ(_Mymtx(), _Flags | _Mtx_try); +#if _HAS_CXX20 + constexpr +#endif // _HAS_CXX20 + _Mutex_base(int _Flags = 0) noexcept { +#if _HAS_CXX20 + if (_STD is_constant_evaluated()) { + construct_at(static_cast<_Stl_critical_section_constexpr*>(static_cast(&_Mtx_storage))); + } else +#endif // _HAS_CXX20 + { + // C++20: For /MD, if mutex is created in runtime, it may outlive the module it is allocated in; + // Use usual construction from the STL DLL. + // Pre-C++20: Always use construction from the STL DLL. + _Mtx_init_in_situ(_Mymtx(), _Flags | _Mtx_try); + } } ~_Mutex_base() noexcept { @@ -85,8 +98,7 @@ private: class mutex : public _Mutex_base { // class for mutual exclusion public: - /* constexpr */ mutex() noexcept // TRANSITION, ABI - : _Mutex_base() {} + mutex() noexcept = default; // Implied constexpr if _Mutex_base default constructor is constexpr mutex(const mutex&) = delete; mutex& operator=(const mutex&) = delete; diff --git a/stl/inc/xthreads.h b/stl/inc/xthreads.h index a1b8ee2bfe..d637ac2fbf 100644 --- a/stl/inc/xthreads.h +++ b/stl/inc/xthreads.h @@ -134,6 +134,41 @@ inline int _Check_C_return(int _Res) { // throw exception on failure return _Res; } _STD_END + +class __declspec(novtable) _Stl_critical_section_interface { +public: + virtual void __thiscall _Lock() = 0; + virtual bool __thiscall _Try_lock() = 0; + virtual bool __thiscall _Try_lock_for(unsigned int) = 0; + virtual void __thiscall _Unlock() = 0; + virtual void __thiscall _Destroy() = 0; +}; + +class _Stl_critical_section_constexpr final : public _Stl_critical_section_interface { +public: + void __thiscall _Lock() override { + _Smtx_lock_exclusive(&_Mtx); + } + + bool __thiscall _Try_lock() override { + return _Smtx_try_lock_exclusive(&_Mtx) != 0; + } + + bool __thiscall _Try_lock_for(unsigned int) override { + // STL will call try_lock_for once again if this call will not succeed + return _Stl_critical_section_constexpr::_Try_lock(); + } + + void __thiscall _Unlock() override { + _Smtx_unlock_exclusive(&_Mtx); + } + + void __thiscall _Destroy() override {} + +private: + _Smtx_t _Mtx; +}; + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/stl/src/mutex.cpp b/stl/src/mutex.cpp index 5db8385bec..79ebb3b6fa 100644 --- a/stl/src/mutex.cpp +++ b/stl/src/mutex.cpp @@ -62,7 +62,7 @@ void _Mtx_init_in_situ(_Mtx_t mtx, int type) { // initialize mutex in situ void _Mtx_destroy_in_situ(_Mtx_t mtx) { // destroy mutex in situ _THREAD_ASSERT(mtx->count == 0, "mutex destroyed while busy"); - mtx->_get_cs()->destroy(); + mtx->_get_cs()->_Destroy(); } int _Mtx_init(_Mtx_t* mtx, int type) { // initialize mutex @@ -90,7 +90,7 @@ void _Mtx_destroy(_Mtx_t mtx) { // destroy mutex static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex if ((mtx->type & ~_Mtx_recursive) == _Mtx_plain) { // set the lock if (mtx->thread_id != static_cast(GetCurrentThreadId())) { // not current thread, do lock - mtx->_get_cs()->lock(); + mtx->_get_cs()->_Lock(); mtx->thread_id = static_cast(GetCurrentThreadId()); } ++mtx->count; @@ -100,7 +100,7 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex int res = WAIT_TIMEOUT; if (target == nullptr) { // no target --> plain wait (i.e. infinite timeout) if (mtx->thread_id != static_cast(GetCurrentThreadId())) { - mtx->_get_cs()->lock(); + mtx->_get_cs()->_Lock(); } res = WAIT_OBJECT_0; @@ -108,7 +108,7 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex } else if (target->sec < 0 || target->sec == 0 && target->nsec <= 0) { // target time <= 0 --> plain trylock or timed wait for time that has passed; try to lock with 0 timeout if (mtx->thread_id != static_cast(GetCurrentThreadId())) { // not this thread, lock it - if (mtx->_get_cs()->try_lock()) { + if (mtx->_get_cs()->_Try_lock()) { res = WAIT_OBJECT_0; } else { res = WAIT_TIMEOUT; @@ -122,7 +122,7 @@ static int mtx_do_lock(_Mtx_t mtx, const xtime* target) { // lock mutex xtime_get(&now, TIME_UTC); while (now.sec < target->sec || now.sec == target->sec && now.nsec < target->nsec) { // time has not expired if (mtx->thread_id == static_cast(GetCurrentThreadId()) - || mtx->_get_cs()->try_lock_for(_Xtime_diff_to_millis2(target, &now))) { // stop waiting + || mtx->_get_cs()->_Try_lock_for(_Xtime_diff_to_millis2(target, &now))) { // stop waiting res = WAIT_OBJECT_0; break; } else { @@ -167,7 +167,7 @@ int _Mtx_unlock(_Mtx_t mtx) { // unlock mutex if (--mtx->count == 0) { // leave critical section mtx->thread_id = -1; - mtx->_get_cs()->unlock(); + mtx->_get_cs()->_Unlock(); } return _Thrd_success; // TRANSITION, ABI: always returns _Thrd_success } diff --git a/stl/src/primitives.hpp b/stl/src/primitives.hpp index f5e37f505f..3de5c60cd9 100644 --- a/stl/src/primitives.hpp +++ b/stl/src/primitives.hpp @@ -6,6 +6,7 @@ #include // for __max #include #include +#include #include "awint.hpp" @@ -15,14 +16,8 @@ extern __stl_sync_api_modes_enum __stl_sync_api_impl_mode; namespace Concurrency { namespace details { - class __declspec(novtable) stl_critical_section_interface { - public: - virtual void lock() = 0; - virtual bool try_lock() = 0; - virtual bool try_lock_for(unsigned int) = 0; - virtual void unlock() = 0; - virtual void destroy() = 0; - }; + using stl_critical_section_interface = ::_Stl_critical_section_interface; + class __declspec(novtable) stl_condition_variable_interface { public: @@ -43,24 +38,24 @@ namespace Concurrency { stl_critical_section_vista& operator=(const stl_critical_section_vista&) = delete; ~stl_critical_section_vista() = delete; - void destroy() override { + void _Destroy() override { DeleteCriticalSection(&_M_critical_section); } - void lock() override { + void _Lock() override { EnterCriticalSection(&_M_critical_section); } - bool try_lock() override { + bool _Try_lock() override { return TryEnterCriticalSection(&_M_critical_section) != 0; } - bool try_lock_for(unsigned int) override { + bool _Try_lock_for(unsigned int) override { // STL will call try_lock_for once again if this call will not succeed - return stl_critical_section_vista::try_lock(); + return stl_critical_section_vista::_Try_lock(); } - void unlock() override { + void _Unlock() override { LeaveCriticalSection(&_M_critical_section); } @@ -118,22 +113,22 @@ namespace Concurrency { stl_critical_section_win7(const stl_critical_section_win7&) = delete; stl_critical_section_win7& operator=(const stl_critical_section_win7&) = delete; - void destroy() override {} + void _Destroy() override {} - void lock() override { + void _Lock() override { AcquireSRWLockExclusive(&m_srw_lock); } - bool try_lock() override { - return __crtTryAcquireSRWLockExclusive(&m_srw_lock) != 0; + bool _Try_lock() override { + return TryAcquireSRWLockExclusive(&m_srw_lock) != 0; } - bool try_lock_for(unsigned int) override { + bool _Try_lock_for(unsigned int) override { // STL will call try_lock_for once again if this call will not succeed - return stl_critical_section_win7::try_lock(); + return stl_critical_section_win7::_Try_lock(); } - void unlock() override { + void _Unlock() override { ReleaseSRWLockExclusive(&m_srw_lock); } @@ -193,45 +188,11 @@ namespace Concurrency { } inline void create_stl_critical_section(stl_critical_section_interface* p) { -#ifdef _CRT_WINDOWS new (p) stl_critical_section_win7; -#else - switch (__stl_sync_api_impl_mode) { - case __stl_sync_api_modes_enum::normal: - case __stl_sync_api_modes_enum::win7: - if (are_win7_sync_apis_available()) { - new (p) stl_critical_section_win7; - return; - } - // fall through - case __stl_sync_api_modes_enum::vista: - new (p) stl_critical_section_vista; - return; - default: - abort(); - } -#endif // _CRT_WINDOWS } inline void create_stl_condition_variable(stl_condition_variable_interface* p) { -#ifdef _CRT_WINDOWS new (p) stl_condition_variable_win7; -#else - switch (__stl_sync_api_impl_mode) { - case __stl_sync_api_modes_enum::normal: - case __stl_sync_api_modes_enum::win7: - if (are_win7_sync_apis_available()) { - new (p) stl_condition_variable_win7; - return; - } - // fall through - case __stl_sync_api_modes_enum::vista: - new (p) stl_condition_variable_vista; - return; - default: - abort(); - } -#endif // _CRT_WINDOWS } #if defined _CRT_WINDOWS