diff --git a/stl/inc/xthreads.h b/stl/inc/xthreads.h index 167c20994a..26302f0aea 100644 --- a/stl/inc/xthreads.h +++ b/stl/inc/xthreads.h @@ -96,19 +96,21 @@ enum { // mutex types _Mtx_recursive = 0x100 }; +#ifdef _CRTBLD _CRTIMP2_PURE _Thrd_result __cdecl _Mtx_init(_Mtx_t*, int); _CRTIMP2_PURE void __cdecl _Mtx_destroy(_Mtx_t); +#endif // _CRTBLD _CRTIMP2_PURE void __cdecl _Mtx_init_in_situ(_Mtx_t, int); _CRTIMP2_PURE void __cdecl _Mtx_destroy_in_situ(_Mtx_t); _CRTIMP2_PURE int __cdecl _Mtx_current_owns(_Mtx_t); _CRTIMP2_PURE _Thrd_result __cdecl _Mtx_lock(_Mtx_t); _CRTIMP2_PURE _Thrd_result __cdecl _Mtx_trylock(_Mtx_t); -_CRTIMP2_PURE _Thrd_result __cdecl _Mtx_timedlock(_Mtx_t, const _timespec64*); _CRTIMP2_PURE _Thrd_result __cdecl _Mtx_unlock(_Mtx_t); // TRANSITION, ABI: Always succeeds -_CRTIMP2_PURE void* __cdecl _Mtx_getconcrtcs(_Mtx_t); +#ifdef _CRTBLD _CRTIMP2_PURE void __cdecl _Mtx_clear_owner(_Mtx_t); _CRTIMP2_PURE void __cdecl _Mtx_reset_owner(_Mtx_t); +#endif // _CRTBLD // shared mutex // these declarations must be in sync with those in sharedmutex.cpp @@ -120,8 +122,10 @@ void __cdecl _Smtx_unlock_exclusive(_Smtx_t*); void __cdecl _Smtx_unlock_shared(_Smtx_t*); // condition variables +#ifdef _CRTBLD _CRTIMP2_PURE _Thrd_result __cdecl _Cnd_init(_Cnd_t*); _CRTIMP2_PURE void __cdecl _Cnd_destroy(_Cnd_t); +#endif // _CRTBLD _CRTIMP2_PURE void __cdecl _Cnd_init_in_situ(_Cnd_t); _CRTIMP2_PURE void __cdecl _Cnd_destroy_in_situ(_Cnd_t); _CRTIMP2_PURE _Thrd_result __cdecl _Cnd_wait(_Cnd_t, _Mtx_t); // TRANSITION, ABI: Always succeeds diff --git a/stl/src/cond.cpp b/stl/src/cond.cpp index 2b5a4f1c0f..01d964ef6f 100644 --- a/stl/src/cond.cpp +++ b/stl/src/cond.cpp @@ -11,6 +11,8 @@ #include "primitives.hpp" +_EXTERN_C + struct _Cnd_internal_imp_t { // condition variable implementation for ConcRT typename std::_Aligned_storage<_Cnd_internal_imp_size, _Cnd_internal_imp_alignment>::type cv; @@ -20,13 +22,13 @@ struct _Cnd_internal_imp_t { // condition variable implementation for ConcRT } }; -void _Cnd_init_in_situ(const _Cnd_t cond) { // initialize condition variable in situ +_CRTIMP2_PURE void __cdecl _Cnd_init_in_situ(const _Cnd_t cond) { // initialize condition variable in situ Concurrency::details::create_stl_condition_variable(cond->_get_cv()); } -void _Cnd_destroy_in_situ(_Cnd_t) {} // destroy condition variable in situ +_CRTIMP2_PURE void __cdecl _Cnd_destroy_in_situ(_Cnd_t) {} // destroy condition variable in situ -_Thrd_result _Cnd_init(_Cnd_t* const pcond) { // initialize +_CRTIMP2_PURE _Thrd_result __cdecl _Cnd_init(_Cnd_t* const pcond) { // initialize *pcond = nullptr; const auto cond = static_cast<_Cnd_t>(_calloc_crt(1, sizeof(_Cnd_internal_imp_t))); @@ -39,14 +41,14 @@ _Thrd_result _Cnd_init(_Cnd_t* const pcond) { // initialize return _Thrd_result::_Success; } -void _Cnd_destroy(const _Cnd_t cond) { // clean up +_CRTIMP2_PURE void __cdecl _Cnd_destroy(const _Cnd_t cond) { // clean up if (cond) { // something to do, do it _Cnd_destroy_in_situ(cond); _free_crt(cond); } } -_Thrd_result _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled +_CRTIMP2_PURE _Thrd_result __cdecl _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled const auto cs = &mtx->_Critical_section; _Mtx_clear_owner(mtx); cond->_get_cv()->wait(cs); @@ -55,7 +57,8 @@ _Thrd_result _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until sign } // wait until signaled or timeout -_Thrd_result _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const _timespec64* const target) { +_CRTIMP2_PURE _Thrd_result __cdecl _Cnd_timedwait( + const _Cnd_t cond, const _Mtx_t mtx, const _timespec64* const target) { _Thrd_result res = _Thrd_result::_Success; const auto cs = &mtx->_Critical_section; if (target == nullptr) { // no target time specified, wait on mutex @@ -77,16 +80,18 @@ _Thrd_result _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const _timespec return res; } -_Thrd_result _Cnd_signal(const _Cnd_t cond) { // release one waiting thread +_CRTIMP2_PURE _Thrd_result __cdecl _Cnd_signal(const _Cnd_t cond) { // release one waiting thread cond->_get_cv()->notify_one(); return _Thrd_result::_Success; // TRANSITION, ABI: Always succeeds } -_Thrd_result _Cnd_broadcast(const _Cnd_t cond) { // release all waiting threads +_CRTIMP2_PURE _Thrd_result __cdecl _Cnd_broadcast(const _Cnd_t cond) { // release all waiting threads cond->_get_cv()->notify_all(); return _Thrd_result::_Success; // TRANSITION, ABI: Always succeeds } +_END_EXTERN_C + /* * This file is derived from software bearing the following * restrictions: diff --git a/stl/src/cthread.cpp b/stl/src/cthread.cpp index 389b8ee9cd..618037bbfd 100644 --- a/stl/src/cthread.cpp +++ b/stl/src/cthread.cpp @@ -42,17 +42,17 @@ namespace { _EXTERN_C // TRANSITION, ABI: _Thrd_exit() is preserved for binary compatibility -[[noreturn]] _CRTIMP2_PURE void _Thrd_exit(int res) { // terminate execution of calling thread +[[noreturn]] _CRTIMP2_PURE void __cdecl _Thrd_exit(int res) { // terminate execution of calling thread _endthreadex(res); } // TRANSITION, ABI: _Thrd_start() is preserved for binary compatibility -_CRTIMP2_PURE _Thrd_result _Thrd_start(_Thrd_t* thr, _Thrd_callback_t func, void* b) { // start a thread +_CRTIMP2_PURE _Thrd_result __cdecl _Thrd_start(_Thrd_t* thr, _Thrd_callback_t func, void* b) { // start a thread thr->_Hnd = reinterpret_cast(_beginthreadex(nullptr, 0, func, b, 0, &thr->_Id)); return thr->_Hnd == nullptr ? _Thrd_result::_Error : _Thrd_result::_Success; } -_Thrd_result _Thrd_join(_Thrd_t thr, int* code) { // returns when thread terminates +_CRTIMP2_PURE _Thrd_result __cdecl _Thrd_join(_Thrd_t thr, int* code) { // returns when thread terminates if (WaitForSingleObjectEx(thr._Hnd, INFINITE, FALSE) == WAIT_FAILED) { return _Thrd_result::_Error; } @@ -68,11 +68,12 @@ _Thrd_result _Thrd_join(_Thrd_t thr, int* code) { // returns when thread termina return CloseHandle(thr._Hnd) ? _Thrd_result::_Success : _Thrd_result::_Error; } -_Thrd_result _Thrd_detach(_Thrd_t thr) { // tell OS to release thread's resources when it terminates +_CRTIMP2_PURE _Thrd_result __cdecl _Thrd_detach(_Thrd_t thr) { + // tell OS to release thread's resources when it terminates return CloseHandle(thr._Hnd) ? _Thrd_result::_Success : _Thrd_result::_Error; } -void _Thrd_sleep(const _timespec64* xt) { // suspend thread until time xt +_CRTIMP2_PURE void __cdecl _Thrd_sleep(const _timespec64* xt) { // suspend thread until time xt _timespec64 now; _Timespec64_get_sys(&now); do { // sleep and check time @@ -81,35 +82,35 @@ void _Thrd_sleep(const _timespec64* xt) { // suspend thread until time xt } while (now.tv_sec < xt->tv_sec || now.tv_sec == xt->tv_sec && now.tv_nsec < xt->tv_nsec); } -void _Thrd_yield() { // surrender remainder of timeslice +_CRTIMP2_PURE void __cdecl _Thrd_yield() { // surrender remainder of timeslice SwitchToThread(); } // TRANSITION, ABI: _Thrd_equal() is preserved for binary compatibility -_CRTIMP2_PURE int _Thrd_equal(_Thrd_t thr0, _Thrd_t thr1) { // return 1 if thr0 and thr1 identify same thread +_CRTIMP2_PURE int __cdecl _Thrd_equal(_Thrd_t thr0, _Thrd_t thr1) { // return 1 if thr0 and thr1 identify same thread return thr0._Id == thr1._Id; } // TRANSITION, ABI: _Thrd_current() is preserved for binary compatibility -_CRTIMP2_PURE _Thrd_t _Thrd_current() { // return _Thrd_t identifying current thread +_CRTIMP2_PURE _Thrd_t __cdecl _Thrd_current() { // return _Thrd_t identifying current thread _Thrd_t result; result._Hnd = nullptr; result._Id = GetCurrentThreadId(); return result; } -_Thrd_id_t _Thrd_id() { // return unique id for current thread +_CRTIMP2_PURE _Thrd_id_t __cdecl _Thrd_id() { // return unique id for current thread return GetCurrentThreadId(); } -unsigned int _Thrd_hardware_concurrency() { // return number of processors +_CRTIMP2_PURE unsigned int __cdecl _Thrd_hardware_concurrency() { // return number of processors SYSTEM_INFO info; GetNativeSystemInfo(&info); return info.dwNumberOfProcessors; } // TRANSITION, ABI: _Thrd_create() is preserved for binary compatibility -_CRTIMP2_PURE _Thrd_result _Thrd_create(_Thrd_t* thr, _Thrd_start_t func, void* d) { // create thread +_CRTIMP2_PURE _Thrd_result __cdecl _Thrd_create(_Thrd_t* thr, _Thrd_start_t func, void* d) { // create thread _Thrd_result res; _Thrd_binder b; int started = 0; diff --git a/stl/src/mutex.cpp b/stl/src/mutex.cpp index ece2ddf18e..ba8c2de344 100644 --- a/stl/src/mutex.cpp +++ b/stl/src/mutex.cpp @@ -13,7 +13,9 @@ #include "primitives.hpp" -extern "C" [[noreturn]] _CRTIMP2_PURE void _Thrd_abort(const char* msg) { // abort on precondition failure +_EXTERN_C + +[[noreturn]] _CRTIMP2_PURE void __cdecl _Thrd_abort(const char* msg) { // abort on precondition failure fputs(msg, stderr); fputc('\n', stderr); abort(); @@ -29,26 +31,26 @@ extern "C" [[noreturn]] _CRTIMP2_PURE void _Thrd_abort(const char* msg) { // abo // TRANSITION, ABI: preserved for binary compatibility enum class __stl_sync_api_modes_enum { normal, win7, vista, concrt }; -extern "C" _CRTIMP2 void __cdecl __set_stl_sync_api_mode(__stl_sync_api_modes_enum) {} +_CRTIMP2 void __cdecl __set_stl_sync_api_mode(__stl_sync_api_modes_enum) {} [[nodiscard]] static PSRWLOCK get_srw_lock(_Mtx_t mtx) { return reinterpret_cast(&mtx->_Critical_section._M_srw_lock); } // TRANSITION, only used when constexpr mutex constructor is not enabled -void _Mtx_init_in_situ(_Mtx_t mtx, int type) { // initialize mutex in situ +_CRTIMP2_PURE void __cdecl _Mtx_init_in_situ(_Mtx_t mtx, int type) { // initialize mutex in situ Concurrency::details::create_stl_critical_section(&mtx->_Critical_section); mtx->_Thread_id = -1; mtx->_Type = type; mtx->_Count = 0; } -void _Mtx_destroy_in_situ(_Mtx_t mtx) { // destroy mutex in situ +_CRTIMP2_PURE void __cdecl _Mtx_destroy_in_situ(_Mtx_t mtx) { // destroy mutex in situ _THREAD_ASSERT(mtx->_Count == 0, "mutex destroyed while busy"); (void) mtx; } -_Thrd_result _Mtx_init(_Mtx_t* mtx, int type) { // initialize mutex +_CRTIMP2_PURE _Thrd_result __cdecl _Mtx_init(_Mtx_t* mtx, int type) { // initialize mutex *mtx = nullptr; _Mtx_t mutex = static_cast<_Mtx_t>(_calloc_crt(1, sizeof(_Mtx_internal_imp_t))); @@ -63,7 +65,7 @@ _Thrd_result _Mtx_init(_Mtx_t* mtx, int type) { // initialize mutex return _Thrd_result::_Success; } -void _Mtx_destroy(_Mtx_t mtx) { // destroy mutex +_CRTIMP2_PURE void __cdecl _Mtx_destroy(_Mtx_t mtx) { // destroy mutex if (mtx) { // something to do, do it _Mtx_destroy_in_situ(mtx); _free_crt(mtx); @@ -71,10 +73,14 @@ void _Mtx_destroy(_Mtx_t mtx) { // destroy mutex } static _Thrd_result mtx_do_lock(_Mtx_t mtx, const _timespec64* target) { // lock mutex + // TRANSITION, ABI: the use of `const _timespec64*` is preserved for `_Mtx_timedlock` + const auto current_thread_id = static_cast(GetCurrentThreadId()); if ((mtx->_Type & ~_Mtx_recursive) == _Mtx_plain) { // set the lock - if (mtx->_Thread_id != static_cast(GetCurrentThreadId())) { // not current thread, do lock + // TRANSITION, ABI: this branch is preserved for `_Thrd_create` + + if (mtx->_Thread_id != current_thread_id) { // not current thread, do lock AcquireSRWLockExclusive(get_srw_lock(mtx)); - mtx->_Thread_id = static_cast(GetCurrentThreadId()); + mtx->_Thread_id = current_thread_id; } ++mtx->_Count; @@ -82,7 +88,7 @@ static _Thrd_result mtx_do_lock(_Mtx_t mtx, const _timespec64* target) { // lock } else { // handle timed or recursive mutex int res = WAIT_TIMEOUT; if (target == nullptr) { // no target --> plain wait (i.e. infinite timeout) - if (mtx->_Thread_id != static_cast(GetCurrentThreadId())) { + if (mtx->_Thread_id != current_thread_id) { AcquireSRWLockExclusive(get_srw_lock(mtx)); } @@ -90,63 +96,56 @@ static _Thrd_result mtx_do_lock(_Mtx_t mtx, const _timespec64* target) { // lock } else if (target->tv_sec < 0 || target->tv_sec == 0 && target->tv_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->_Thread_id != current_thread_id) { // not this thread, lock it if (TryAcquireSRWLockExclusive(get_srw_lock(mtx)) != 0) { res = WAIT_OBJECT_0; - } else { - res = WAIT_TIMEOUT; } } else { res = WAIT_OBJECT_0; } } else { // check timeout + // TRANSITION, ABI: this branch is preserved for `_Mtx_timedlock` _timespec64 now; _Timespec64_get_sys(&now); while (now.tv_sec < target->tv_sec || now.tv_sec == target->tv_sec && now.tv_nsec < target->tv_nsec) { // time has not expired - if (mtx->_Thread_id == static_cast(GetCurrentThreadId()) + if (mtx->_Thread_id == current_thread_id || TryAcquireSRWLockExclusive(get_srw_lock(mtx)) != 0) { // stop waiting res = WAIT_OBJECT_0; break; - } else { - res = WAIT_TIMEOUT; } _Timespec64_get_sys(&now); } } - if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) { + if (res == WAIT_OBJECT_0) { if (1 < ++mtx->_Count) { // check count if ((mtx->_Type & _Mtx_recursive) != _Mtx_recursive) { // not recursive, fixup count --mtx->_Count; res = WAIT_TIMEOUT; } } else { - mtx->_Thread_id = static_cast(GetCurrentThreadId()); + mtx->_Thread_id = current_thread_id; } } - switch (res) { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: + if (res == WAIT_OBJECT_0) { return _Thrd_result::_Success; + } - case WAIT_TIMEOUT: - if (target == nullptr || (target->tv_sec == 0 && target->tv_nsec == 0)) { - return _Thrd_result::_Busy; - } else { - return _Thrd_result::_Timedout; - } + // res is WAIT_TIMEOUT here - default: - return _Thrd_result::_Error; + if (target == nullptr || (target->tv_sec == 0 && target->tv_nsec == 0)) { + return _Thrd_result::_Busy; } + + return _Thrd_result::_Timedout; } } -_Thrd_result _Mtx_unlock(_Mtx_t mtx) { // unlock mutex +_CRTIMP2_PURE _Thrd_result __cdecl _Mtx_unlock(_Mtx_t mtx) { // unlock mutex _THREAD_ASSERT( 1 <= mtx->_Count && mtx->_Thread_id == static_cast(GetCurrentThreadId()), "unlock of unowned mutex"); @@ -160,11 +159,11 @@ _Thrd_result _Mtx_unlock(_Mtx_t mtx) { // unlock mutex return _Thrd_result::_Success; // TRANSITION, ABI: Always succeeds } -_Thrd_result _Mtx_lock(_Mtx_t mtx) { // lock mutex +_CRTIMP2_PURE _Thrd_result __cdecl _Mtx_lock(_Mtx_t mtx) { // lock mutex return mtx_do_lock(mtx, nullptr); } -_Thrd_result _Mtx_trylock(_Mtx_t mtx) { // attempt to lock try_mutex +_CRTIMP2_PURE _Thrd_result __cdecl _Mtx_trylock(_Mtx_t mtx) { // attempt to lock try_mutex _timespec64 xt; _THREAD_ASSERT((mtx->_Type & (_Mtx_try | _Mtx_timed)) != 0, "trylock not supported by mutex"); xt.tv_sec = 0; @@ -172,7 +171,8 @@ _Thrd_result _Mtx_trylock(_Mtx_t mtx) { // attempt to lock try_mutex return mtx_do_lock(mtx, &xt); } -_Thrd_result _Mtx_timedlock(_Mtx_t mtx, const _timespec64* xt) { // attempt to lock timed mutex +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE _Thrd_result __cdecl _Mtx_timedlock(_Mtx_t mtx, const _timespec64* xt) { // attempt to lock timed mutex _Thrd_result res; _THREAD_ASSERT((mtx->_Type & _Mtx_timed) != 0, "timedlock not supported by mutex"); @@ -180,24 +180,27 @@ _Thrd_result _Mtx_timedlock(_Mtx_t mtx, const _timespec64* xt) { // attempt to l return res == _Thrd_result::_Busy ? _Thrd_result::_Timedout : res; } -int _Mtx_current_owns(_Mtx_t mtx) { // test if current thread owns mutex +_CRTIMP2_PURE int __cdecl _Mtx_current_owns(_Mtx_t mtx) { // test if current thread owns mutex return mtx->_Count != 0 && mtx->_Thread_id == static_cast(GetCurrentThreadId()); } -void* _Mtx_getconcrtcs(_Mtx_t mtx) { // get internal cs impl +// TRANSITION, ABI: preserved for binary compatibility +_CRTIMP2_PURE void* __cdecl _Mtx_getconcrtcs(_Mtx_t mtx) { // get internal cs impl return &mtx->_Critical_section; } -void _Mtx_clear_owner(_Mtx_t mtx) { // set owner to nobody +_CRTIMP2_PURE void __cdecl _Mtx_clear_owner(_Mtx_t mtx) { // set owner to nobody mtx->_Thread_id = -1; --mtx->_Count; } -void _Mtx_reset_owner(_Mtx_t mtx) { // set owner to current thread +_CRTIMP2_PURE void __cdecl _Mtx_reset_owner(_Mtx_t mtx) { // set owner to current thread mtx->_Thread_id = static_cast(GetCurrentThreadId()); ++mtx->_Count; } +_END_EXTERN_C + /* * This file is derived from software bearing the following * restrictions: diff --git a/stl/src/xnotify.cpp b/stl/src/xnotify.cpp index 64a513855d..9d44df6875 100644 --- a/stl/src/xnotify.cpp +++ b/stl/src/xnotify.cpp @@ -32,8 +32,9 @@ _EXTERN_C void _Lock_at_thread_exit_mutex(); void _Unlock_at_thread_exit_mutex(); -void _Cnd_register_at_thread_exit( - _Cnd_t cnd, _Mtx_t mtx, int* p) { // register condition variable and mutex for cleanup at thread exit +_CRTIMP2_PURE void __cdecl _Cnd_register_at_thread_exit(_Cnd_t cnd, _Mtx_t mtx, int* p) { + // register condition variable and mutex for cleanup at thread exit + // find block with available space _At_thread_exit_block* block = &_Thread_exit_data; @@ -62,7 +63,9 @@ void _Cnd_register_at_thread_exit( _Unlock_at_thread_exit_mutex(); } -void _Cnd_unregister_at_thread_exit(_Mtx_t mtx) { // unregister condition variable/mutex for cleanup at thread exit +_CRTIMP2_PURE void __cdecl _Cnd_unregister_at_thread_exit(_Mtx_t mtx) { + // unregister condition variable/mutex for cleanup at thread exit + // find condition variables waiting for this thread to exit _At_thread_exit_block* block = &_Thread_exit_data; @@ -80,7 +83,9 @@ void _Cnd_unregister_at_thread_exit(_Mtx_t mtx) { // unregister condition variab _Unlock_at_thread_exit_mutex(); } -void _Cnd_do_broadcast_at_thread_exit() { // notify condition variables waiting for this thread to exit +_CRTIMP2_PURE void __cdecl _Cnd_do_broadcast_at_thread_exit() { + // notify condition variables waiting for this thread to exit + // find condition variables waiting for this thread to exit _At_thread_exit_block* block = &_Thread_exit_data; const unsigned int currentThreadId = _Thrd_id();