Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions stl/inc/__msvc_chrono.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,10 +695,10 @@ namespace chrono {
} // namespace chrono

template <class _Rep, class _Period>
_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept(
is_arithmetic_v<_Rep>) {
// Convert duration to xtime, maximum 10 days from now, returns whether clamping occurred.
// If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where
_NODISCARD bool _To_timespec64_sys_10_day_clamped(
_timespec64& _Ts64, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept(is_arithmetic_v<_Rep>) {
// Convert duration to _timespec64 representing system time, maximum 10 days from now, returns whether clamping
// occurred. If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where
// the other side of the DLL boundary overflows int32_t milliseconds.
// Every function calling this one is TRANSITION, ABI
constexpr _CHRONO nanoseconds _Ten_days{_CHRONO hours{24} * 10};
Expand All @@ -712,9 +712,9 @@ _NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duratio
}

const auto _Whole_seconds = _CHRONO duration_cast<_CHRONO seconds>(_Tx0);
_Xt.sec = _Whole_seconds.count();
_Ts64.tv_sec = _Whole_seconds.count();
_Tx0 -= _Whole_seconds;
_Xt.nsec = static_cast<long>(_Tx0.count());
_Ts64.tv_nsec = static_cast<long>(_Tx0.count());
return _Clamped;
}

Expand Down
33 changes: 9 additions & 24 deletions stl/inc/condition_variable
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ public:
}

// TRANSITION, ABI: The standard says that we should use a steady clock,
// but unfortunately our ABI speaks struct xtime, which is relative to the system clock.
_CSTD xtime _Tgt;
const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Rel_time);
const cv_status _Result = _Wait_until(_Lck, &_Tgt);
// but unfortunately our ABI relies on the system clock.
_timespec64 _Tgt;
const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time);
const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt);
if (_Clamped) {
return cv_status::no_timeout;
}
Expand All @@ -139,22 +139,6 @@ public:
return wait_until(_Lck, _To_absolute_time(_Rel_time), _STD move(_Pred));
}

template <class _Lock>
cv_status wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout
return _Wait_until(_Lck, _Abs_time);
}

template <class _Lock, class _Predicate>
bool wait_until(_Lock& _Lck, const xtime* const _Abs_time, _Predicate _Pred) {
// wait for signal with timeout and check predicate
while (!_Pred()) {
if (_Wait_until(_Lck, _Abs_time) == cv_status::timeout) {
return _Pred();
}
}
return true;
}

#if _HAS_CXX20
private:
struct _Cv_any_notify_all {
Expand Down Expand Up @@ -221,9 +205,9 @@ public:

const auto _Rel_time = _Abs_time - _Now;
// TRANSITION, ABI: The standard says that we should use a steady clock,
// but unfortunately our ABI speaks struct xtime, which is relative to the system clock.
_CSTD xtime _Tgt;
(void) _To_xtime_10_day_clamped(_Tgt, _Rel_time);
// but unfortunately our ABI relies on the system clock.
_timespec64 _Tgt;
(void) _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time);
(void) _Cnd_timedwait(_Mycnd(), _Myptr->_Mymtx(), &_Tgt);
_Guard_unlocks_before_locking_outer.unlock();
} // relock
Expand All @@ -247,7 +231,8 @@ private:
}

template <class _Lock>
cv_status _Wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout
cv_status _Wait_until_sys_time(_Lock& _Lck, const _timespec64* const _Abs_time) {
// wait for signal with timeout
const shared_ptr<mutex> _Ptr = _Myptr; // for immunity to *this destruction
unique_lock<mutex> _Guard{*_Ptr};
_Unlock_guard<_Lock> _Unlock_outer{_Lck};
Expand Down
81 changes: 28 additions & 53 deletions stl/inc/mutex
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,6 @@ public:
#endif // _HAS_CXX20
}

_NODISCARD_CTOR_LOCK unique_lock(_Mutex& _Mtx, const xtime* _Abs_time)
: _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // try to lock until _Abs_time
_Owns = _Pmtx->try_lock_until(_Abs_time);
}

_NODISCARD_CTOR_LOCK unique_lock(unique_lock&& _Other) noexcept : _Pmtx(_Other._Pmtx), _Owns(_Other._Owns) {
_Other._Pmtx = nullptr;
_Other._Owns = false;
Expand Down Expand Up @@ -264,12 +259,6 @@ public:
return _Owns;
}

_NODISCARD_TRY_CHANGE_STATE bool try_lock_until(const xtime* _Abs_time) {
_Validate();
_Owns = _Pmtx->try_lock_until(_Abs_time);
return _Owns;
}

void unlock() {
if (!_Pmtx || !_Owns) {
_Throw_system_error(errc::operation_not_permitted);
Expand Down Expand Up @@ -690,10 +679,10 @@ public:
}

// TRANSITION, ABI: The standard says that we should use a steady clock,
// but unfortunately our ABI speaks struct xtime, which is relative to the system clock.
_CSTD xtime _Tgt;
const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Rel_time);
const cv_status _Result = wait_until(_Lck, &_Tgt);
// but unfortunately our ABI relies on the system clock.
_timespec64 _Tgt;
const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Rel_time);
const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt);
if (_Clamped) {
return cv_status::no_timeout;
}
Expand All @@ -719,9 +708,9 @@ public:
return cv_status::timeout;
}

_CSTD xtime _Tgt;
(void) _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now);
const cv_status _Result = wait_until(_Lck, &_Tgt);
_timespec64 _Tgt;
(void) _To_timespec64_sys_10_day_clamped(_Tgt, _Abs_time - _Now);
const cv_status _Result = _Wait_until_sys_time(_Lck, &_Tgt);
if (_Result == cv_status::no_timeout) {
return cv_status::no_timeout;
}
Expand All @@ -738,28 +727,6 @@ public:
return _Wait_until1(_Lck, _Abs_time, _Pred);
}

cv_status wait_until(unique_lock<mutex>& _Lck, const xtime* _Abs_time) {
// wait for signal with timeout
if (!_Mtx_current_owns(_Lck.mutex()->_Mymtx())) {
_Throw_Cpp_error(_OPERATION_NOT_PERMITTED);
}

// Nothing to do to comply with LWG-2135 because std::mutex lock/unlock are nothrow
const int _Res = _Cnd_timedwait(_Mycnd(), _Lck.mutex()->_Mymtx(), _Abs_time);

if (_Res == _Thrd_success) {
return cv_status::no_timeout;
} else {
return cv_status::timeout;
}
}

template <class _Predicate>
bool wait_until(unique_lock<mutex>& _Lck, const xtime* _Abs_time, _Predicate _Pred) {
// wait for signal with timeout and check predicate
return _Wait_until1(_Lck, _Abs_time, _Pred);
}

_NODISCARD native_handle_type native_handle() noexcept /* strengthened */ {
return _Mycnd();
}
Expand All @@ -779,11 +746,27 @@ private:
return reinterpret_cast<_Cnd_t>(&_Cnd_storage);
}

cv_status _Wait_until_sys_time(unique_lock<mutex>& _Lck, const _timespec64* _Abs_time) {
// wait for signal with timeout
if (!_Mtx_current_owns(_Lck.mutex()->_Mymtx())) {
_Throw_Cpp_error(_OPERATION_NOT_PERMITTED);
}

// Nothing to do to comply with LWG-2135 because std::mutex lock/unlock are nothrow
const int _Res = _Cnd_timedwait(_Mycnd(), _Lck.mutex()->_Mymtx(), _Abs_time);

if (_Res == _Thrd_success) {
return cv_status::no_timeout;
} else {
return cv_status::timeout;
}
}

template <class _Predicate>
bool _Wait_until1(unique_lock<mutex>& _Lck, const xtime* _Abs_time, _Predicate& _Pred) {
bool _Wait_until1(unique_lock<mutex>& _Lck, const _timespec64* _Abs_time, _Predicate& _Pred) {
// wait for signal with timeout and check predicate
while (!_Pred()) {
if (wait_until(_Lck, _Abs_time) == cv_status::timeout) {
if (_Wait_until_sys_time(_Lck, _Abs_time) == cv_status::timeout) {
return _Pred();
}
}
Expand All @@ -800,9 +783,9 @@ private:
return false;
}

_CSTD xtime _Tgt;
const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now);
if (wait_until(_Lck, &_Tgt) == cv_status::timeout && !_Clamped) {
_timespec64 _Tgt;
const bool _Clamped = _To_timespec64_sys_10_day_clamped(_Tgt, _Abs_time - _Now);
if (_Wait_until_sys_time(_Lck, &_Tgt) == cv_status::timeout && !_Clamped) {
return _Pred();
}
}
Expand Down Expand Up @@ -880,10 +863,6 @@ public:
return _Try_lock_until(_Abs_time);
}

_NODISCARD_TRY_CHANGE_STATE bool try_lock_until(const xtime* _Abs_time) { // try to lock the mutex with timeout
return _Try_lock_until(_Abs_time);
}

private:
mutex _My_mutex;
condition_variable _My_cond;
Expand Down Expand Up @@ -997,10 +976,6 @@ public:
return _Try_lock_until(_Abs_time);
}

_NODISCARD_TRY_CHANGE_STATE bool try_lock_until(const xtime* _Abs_time) { // try to lock the mutex with timeout
return _Try_lock_until(_Abs_time);
}

private:
mutex _My_mutex;
condition_variable _My_cond;
Expand Down
5 changes: 0 additions & 5 deletions stl/inc/shared_mutex
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,6 @@ public:
return _Try_lock_shared_until(_Abs_time);
}

_NODISCARD_TRY_CHANGE_STATE bool try_lock_shared_until(
const xtime* _Abs_time) { // try to lock non-exclusive until absolute time
return _Try_lock_shared_until(_Abs_time);
}

void unlock_shared() { // unlock non-exclusive
_Read_cnt_t _Local_readers;
bool _Local_writing;
Expand Down
8 changes: 2 additions & 6 deletions stl/inc/thread
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,6 @@ namespace this_thread {
_Thrd_yield();
}

inline void sleep_until(const xtime* _Abs_time) {
_Thrd_sleep(_Abs_time);
}

_EXPORT_STD template <class _Clock, class _Duration>
void sleep_until(const chrono::time_point<_Clock, _Duration>& _Abs_time) {
#if _HAS_CXX20
Expand All @@ -196,8 +192,8 @@ namespace this_thread {
return;
}

_CSTD xtime _Tgt;
(void) _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now);
_timespec64 _Tgt;
(void) _To_timespec64_sys_10_day_clamped(_Tgt, _Abs_time - _Now);
_Thrd_sleep(&_Tgt);
}
}
Expand Down
6 changes: 3 additions & 3 deletions stl/inc/xthreads.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ enum { _Thrd_success, _Thrd_nomem, _Thrd_timedout, _Thrd_busy, _Thrd_error };
// threads
_CRTIMP2_PURE int __cdecl _Thrd_detach(_Thrd_t);
_CRTIMP2_PURE int __cdecl _Thrd_join(_Thrd_t, int*);
_CRTIMP2_PURE void __cdecl _Thrd_sleep(const xtime*);
_CRTIMP2_PURE void __cdecl _Thrd_sleep(const _timespec64*);
_CRTIMP2_PURE void __cdecl _Thrd_yield();
_CRTIMP2_PURE unsigned int __cdecl _Thrd_hardware_concurrency();
_CRTIMP2_PURE _Thrd_id_t __cdecl _Thrd_id();
Expand All @@ -87,7 +87,7 @@ _CRTIMP2_PURE void __cdecl _Mtx_destroy_in_situ(_Mtx_t);
_CRTIMP2_PURE int __cdecl _Mtx_current_owns(_Mtx_t);
_CRTIMP2_PURE int __cdecl _Mtx_lock(_Mtx_t);
_CRTIMP2_PURE int __cdecl _Mtx_trylock(_Mtx_t);
_CRTIMP2_PURE int __cdecl _Mtx_timedlock(_Mtx_t, const xtime*);
_CRTIMP2_PURE int __cdecl _Mtx_timedlock(_Mtx_t, const _timespec64*);
_CRTIMP2_PURE int __cdecl _Mtx_unlock(_Mtx_t); // TRANSITION, ABI: always returns _Thrd_success

_CRTIMP2_PURE void* __cdecl _Mtx_getconcrtcs(_Mtx_t);
Expand All @@ -110,7 +110,7 @@ _CRTIMP2_PURE void __cdecl _Cnd_destroy(_Cnd_t);
_CRTIMP2_PURE void __cdecl _Cnd_init_in_situ(_Cnd_t);
_CRTIMP2_PURE void __cdecl _Cnd_destroy_in_situ(_Cnd_t);
_CRTIMP2_PURE int __cdecl _Cnd_wait(_Cnd_t, _Mtx_t); // TRANSITION, ABI: Always returns _Thrd_success
_CRTIMP2_PURE int __cdecl _Cnd_timedwait(_Cnd_t, _Mtx_t, const xtime*);
_CRTIMP2_PURE int __cdecl _Cnd_timedwait(_Cnd_t, _Mtx_t, const _timespec64*);
_CRTIMP2_PURE int __cdecl _Cnd_broadcast(_Cnd_t); // TRANSITION, ABI: Always returns _Thrd_success
_CRTIMP2_PURE int __cdecl _Cnd_signal(_Cnd_t); // TRANSITION, ABI: Always returns _Thrd_success
_CRTIMP2_PURE void __cdecl _Cnd_register_at_thread_exit(_Cnd_t, _Mtx_t, int*);
Expand Down
9 changes: 2 additions & 7 deletions stl/inc/xtimec.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@ _STL_DISABLE_CLANG_WARNINGS

_EXTERN_C

struct xtime { // store time with nanosecond resolution
__time64_t sec;
long nsec;
};

_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const xtime*, const xtime*);
_CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const _timespec64*, const _timespec64*);
_CRTIMP2_PURE long long __cdecl _Xtime_get_ticks();

#ifdef _CRTBLD
// Used by several src files, but not dllexported.
void _Xtime_get2(xtime*);
void _Timespec64_get_sys(_timespec64*);
#endif // _CRTBLD

_CRTIMP2_PURE long long __cdecl _Query_perf_counter();
Expand Down
9 changes: 5 additions & 4 deletions stl/src/cond.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,20 @@ int _Cnd_wait(const _Cnd_t cond, const _Mtx_t mtx) { // wait until signaled
return _Thrd_success; // TRANSITION, ABI: Always returns _Thrd_success
}

int _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const xtime* const target) { // wait until signaled or timeout
// wait until signaled or timeout
int _Cnd_timedwait(const _Cnd_t cond, const _Mtx_t mtx, const _timespec64* const target) {
int res = _Thrd_success;
const auto cs = static_cast<Concurrency::details::stl_critical_section_interface*>(_Mtx_getconcrtcs(mtx));
if (target == nullptr) { // no target time specified, wait on mutex
_Mtx_clear_owner(mtx);
cond->_get_cv()->wait(cs);
_Mtx_reset_owner(mtx);
} else { // target time specified, wait for it
xtime now;
_Xtime_get2(&now);
_timespec64 now;
_Timespec64_get_sys(&now);
_Mtx_clear_owner(mtx);
if (!cond->_get_cv()->wait_for(cs, _Xtime_diff_to_millis2(target, &now))) { // report timeout
_Xtime_get2(&now);
_Timespec64_get_sys(&now);
if (_Xtime_diff_to_millis2(target, &now) == 0) {
res = _Thrd_timedout;
}
Expand Down
10 changes: 5 additions & 5 deletions stl/src/cthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ int _Thrd_detach(_Thrd_t thr) { // tell OS to release thread's resources when it
return CloseHandle(thr._Hnd) ? _Thrd_success : _Thrd_error;
}

void _Thrd_sleep(const xtime* xt) { // suspend thread until time xt
xtime now;
_Xtime_get2(&now);
void _Thrd_sleep(const _timespec64* xt) { // suspend thread until time xt
_timespec64 now;
_Timespec64_get_sys(&now);
do { // sleep and check time
Sleep(_Xtime_diff_to_millis2(xt, &now));
_Xtime_get2(&now);
} while (now.sec < xt->sec || now.sec == xt->sec && now.nsec < xt->nsec);
_Timespec64_get_sys(&now);
} 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
Expand Down
Loading