From 3009cb06bc760543397a40564cd0bdfb55321912 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Sat, 15 Apr 2023 20:58:53 +0700 Subject: [PATCH 01/13] `std::atomic::wait` should compare control blocks --- stl/inc/memory | 8 ++++---- tests/std/include/test_atomic_wait.hpp | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 658f3e78cdc..b1f240607e3 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -3870,10 +3870,10 @@ protected: _Atomic_ptr_base(remove_extent_t<_Ty>* const _Px, _Ref_count_base* const _Ref) noexcept : _Ptr(_Px), _Repptr(_Ref) {} - void _Wait(remove_extent_t<_Ty>* _Old, memory_order) const noexcept { + void _Wait(remove_extent_t<_Ty>* _Old, _Ref_count_base* const _Old_Rep, memory_order) const noexcept { for (;;) { auto _Rep = _Repptr._Lock_and_load(); - bool _Equal = _Ptr.load(memory_order_relaxed) == _Old; + bool _Equal = _Ptr.load(memory_order_relaxed) == _Old && (_Old == nullptr || _Rep == _Old_Rep); _Repptr._Store_and_unlock(_Rep); if (!_Equal) { break; @@ -3984,7 +3984,7 @@ public: } void wait(shared_ptr<_Ty> _Old, memory_order _Order = memory_order_seq_cst) const noexcept { - this->_Wait(_Old._Ptr, _Order); + this->_Wait(_Old._Ptr, _Old._Rep, _Order); } using _Base::notify_all; @@ -4103,7 +4103,7 @@ public: } void wait(weak_ptr<_Ty> _Old, memory_order _Order = memory_order_seq_cst) const noexcept { - this->_Wait(_Old._Ptr, _Order); + this->_Wait(_Old._Ptr, _Old._Rep, _Order); } using _Base::notify_all; diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index d3c2180f924..eec4ca85afd 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -218,6 +218,29 @@ struct with_padding_bits { }; #pragma warning(pop) +inline void test_gh_3602() { + // GH-3602 std::atomic::wait does not seem to care about control block difference. Is this a bug? + { + auto sp1 = std::make_shared(); + auto holder = [sp1] {}; + auto sp2 = std::make_shared(holder); + std::shared_ptr sp3{sp2, sp1.get()}; + + std::atomic> asp{sp1}; + asp.wait(sp3); + } + { + auto sp1 = std::make_shared(); + auto holder = [sp1] {}; + auto sp2 = std::make_shared(holder); + std::shared_ptr sp3{sp2, sp1.get()}; + std::weak_ptr wp3{sp3}; + + std::atomic> awp{sp1}; + awp.wait(wp3); + } +} + inline void test_atomic_wait() { // wait for all the threads to be waiting; if this value is too small the test might be ineffective but should not // fail due to timing assumptions except where otherwise noted; if it is too large the test will only take longer @@ -308,4 +331,6 @@ inline void test_atomic_wait() { test_pad_bits>(waiting_duration); #endif // ^^^ !ARM ^^^ #endif // __clang__, TRANSITION, LLVM-46685 + + test_gh_3602(); } From d25fc84521b1584ec114f5ce89f55388d79b527d Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Sat, 6 May 2023 12:07:27 +0700 Subject: [PATCH 02/13] add a test case Co-authored-by: Alex Guteniev --- tests/std/include/test_atomic_wait.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index eec4ca85afd..35e75d99c7b 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -239,6 +239,24 @@ inline void test_gh_3602() { std::atomic> awp{sp1}; awp.wait(wp3); } + { + auto sp1 = std::make_shared(); + auto holder = [sp1] {}; + auto sp2 = std::make_shared(holder); + std::shared_ptr sp3{sp2, sp1.get()}; + + std::atomic> asp{sp3}; + + std::thread t([&] { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + asp = sp1; + asp.notify_one(); + }); + + asp.wait(sp3); + + t.join(); + } } inline void test_atomic_wait() { From e1422f6727686ed5c6d885d3b75ef5fd816cd48e Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Sat, 6 May 2023 12:57:52 +0700 Subject: [PATCH 03/13] P1135R6_atomic_wait_vista hangs --- tests/std/include/test_atomic_wait.hpp | 32 ++++++++++--------- tests/std/tests/P1135R6_atomic_wait/test.cpp | 2 +- .../tests/P1135R6_atomic_wait_vista/test.cpp | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index 35e75d99c7b..436c848a014 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -218,7 +218,7 @@ struct with_padding_bits { }; #pragma warning(pop) -inline void test_gh_3602() { +inline void test_gh_3602(__std_atomic_api_level level) { // GH-3602 std::atomic::wait does not seem to care about control block difference. Is this a bug? { auto sp1 = std::make_shared(); @@ -240,26 +240,28 @@ inline void test_gh_3602() { awp.wait(wp3); } { - auto sp1 = std::make_shared(); - auto holder = [sp1] {}; - auto sp2 = std::make_shared(holder); - std::shared_ptr sp3{sp2, sp1.get()}; + if (level == __std_atomic_api_level::__has_wait_on_address) { + auto sp1 = std::make_shared(); + auto holder = [sp1] {}; + auto sp2 = std::make_shared(holder); + std::shared_ptr sp3{sp2, sp1.get()}; - std::atomic> asp{sp3}; + std::atomic> asp{sp3}; - std::thread t([&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - asp = sp1; - asp.notify_one(); - }); + std::thread t([&] { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + asp = sp1; + asp.notify_one(); + }); - asp.wait(sp3); + asp.wait(sp3); - t.join(); + t.join(); + } } } -inline void test_atomic_wait() { +inline void test_atomic_wait(__std_atomic_api_level level) { // wait for all the threads to be waiting; if this value is too small the test might be ineffective but should not // fail due to timing assumptions except where otherwise noted; if it is too large the test will only take longer // than necessary @@ -350,5 +352,5 @@ inline void test_atomic_wait() { #endif // ^^^ !ARM ^^^ #endif // __clang__, TRANSITION, LLVM-46685 - test_gh_3602(); + test_gh_3602(level); } diff --git a/tests/std/tests/P1135R6_atomic_wait/test.cpp b/tests/std/tests/P1135R6_atomic_wait/test.cpp index 7b7e0ea1fde..48fe2ddfb11 100644 --- a/tests/std/tests/P1135R6_atomic_wait/test.cpp +++ b/tests/std/tests/P1135R6_atomic_wait/test.cpp @@ -6,5 +6,5 @@ int main() { assert(__std_atomic_set_api_level(__std_atomic_api_level::__has_wait_on_address) == __std_atomic_api_level::__has_wait_on_address); - test_atomic_wait(); + test_atomic_wait(__std_atomic_api_level::__has_wait_on_address); } diff --git a/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp b/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp index dc1dd27e1b0..3bed62357c9 100644 --- a/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp +++ b/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp @@ -6,6 +6,6 @@ int main() { #if defined(_M_IX86) || defined(_M_X64) && !defined(_M_ARM64EC) assert(__std_atomic_set_api_level(__std_atomic_api_level::__has_srwlock) == __std_atomic_api_level::__has_srwlock); - test_atomic_wait(); + test_atomic_wait(__std_atomic_api_level::__has_srwlock); #endif // defined(_M_IX86) || defined(_M_X64) && !defined(_M_ARM64EC) } From bd5181b21a6db2f2edf86abd0ad4abc39d0349a2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 12 Feb 2024 11:52:33 -0800 Subject: [PATCH 04/13] `_Old_Rep` => `_Old_rep` --- stl/inc/memory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 14bdb459726..a0a320b4aaf 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4000,10 +4000,10 @@ protected: _Atomic_ptr_base(remove_extent_t<_Ty>* const _Px, _Ref_count_base* const _Ref) noexcept : _Ptr(_Px), _Repptr(_Ref) {} - void _Wait(remove_extent_t<_Ty>* _Old, _Ref_count_base* const _Old_Rep, memory_order) const noexcept { + void _Wait(remove_extent_t<_Ty>* _Old, _Ref_count_base* const _Old_rep, memory_order) const noexcept { for (;;) { auto _Rep = _Repptr._Lock_and_load(); - bool _Equal = _Ptr.load(memory_order_relaxed) == _Old && (_Old == nullptr || _Rep == _Old_Rep); + bool _Equal = _Ptr.load(memory_order_relaxed) == _Old && (_Old == nullptr || _Rep == _Old_rep); _Repptr._Store_and_unlock(_Rep); if (!_Equal) { break; From 9aeb9a039d79d9b8f3acb905e7e9a6f8bd088d08 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 12 Feb 2024 11:54:16 -0800 Subject: [PATCH 05/13] `_Old` => `_Old_ptr` for clarity. --- stl/inc/memory | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index a0a320b4aaf..6294e961a80 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4000,15 +4000,15 @@ protected: _Atomic_ptr_base(remove_extent_t<_Ty>* const _Px, _Ref_count_base* const _Ref) noexcept : _Ptr(_Px), _Repptr(_Ref) {} - void _Wait(remove_extent_t<_Ty>* _Old, _Ref_count_base* const _Old_rep, memory_order) const noexcept { + void _Wait(remove_extent_t<_Ty>* _Old_ptr, _Ref_count_base* const _Old_rep, memory_order) const noexcept { for (;;) { auto _Rep = _Repptr._Lock_and_load(); - bool _Equal = _Ptr.load(memory_order_relaxed) == _Old && (_Old == nullptr || _Rep == _Old_rep); + bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && (_Old_ptr == nullptr || _Rep == _Old_rep); _Repptr._Store_and_unlock(_Rep); if (!_Equal) { break; } - __std_atomic_wait_direct(&_Ptr, &_Old, sizeof(_Old), __std_atomic_wait_no_timeout); + __std_atomic_wait_direct(&_Ptr, &_Old_ptr, sizeof(_Old_ptr), __std_atomic_wait_no_timeout); } } From 506e941638d529d59a8d557a932b5314898012b0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 12 Feb 2024 11:56:02 -0800 Subject: [PATCH 06/13] Bugfix: Must share ownership or both be empty, even when owning the null pointer. --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 6294e961a80..2e3f73c60f8 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4003,7 +4003,7 @@ protected: void _Wait(remove_extent_t<_Ty>* _Old_ptr, _Ref_count_base* const _Old_rep, memory_order) const noexcept { for (;;) { auto _Rep = _Repptr._Lock_and_load(); - bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && (_Old_ptr == nullptr || _Rep == _Old_rep); + bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && _Rep == _Old_rep; _Repptr._Store_and_unlock(_Rep); if (!_Equal) { break; From 97167638aa106d453063d0fd4e653f6b1ef32ffd Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 12 Feb 2024 12:17:10 -0800 Subject: [PATCH 07/13] Add `const` to the `level` parameter. --- tests/std/include/test_atomic_wait.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index 31a97437a7b..c879844ff65 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -202,7 +202,7 @@ struct with_padding_bits { }; #pragma warning(pop) -inline void test_gh_3602(__std_atomic_api_level level) { +inline void test_gh_3602(const __std_atomic_api_level level) { // GH-3602 std::atomic::wait does not seem to care about control block difference. Is this a bug? { auto sp1 = std::make_shared(); @@ -245,7 +245,7 @@ inline void test_gh_3602(__std_atomic_api_level level) { } } -inline void test_atomic_wait(__std_atomic_api_level level) { +inline void test_atomic_wait(const __std_atomic_api_level level) { // wait for all the threads to be waiting; if this value is too small the test might be ineffective but should not // fail due to timing assumptions except where otherwise noted; if it is too large the test will only take longer // than necessary From 50943d95d101c64dcdcb209084682758d30a065c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 12 Feb 2024 12:27:41 -0800 Subject: [PATCH 08/13] Drop unnecessary braces. --- tests/std/include/test_atomic_wait.hpp | 29 +++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index c879844ff65..f99a0818507 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -223,25 +223,24 @@ inline void test_gh_3602(const __std_atomic_api_level level) { std::atomic> awp{sp1}; awp.wait(wp3); } - { - if (level == __std_atomic_api_level::__has_wait_on_address) { - auto sp1 = std::make_shared(); - auto holder = [sp1] {}; - auto sp2 = std::make_shared(holder); - std::shared_ptr sp3{sp2, sp1.get()}; - std::atomic> asp{sp3}; + if (level == __std_atomic_api_level::__has_wait_on_address) { + auto sp1 = std::make_shared(); + auto holder = [sp1] {}; + auto sp2 = std::make_shared(holder); + std::shared_ptr sp3{sp2, sp1.get()}; + + std::atomic> asp{sp3}; - std::thread t([&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - asp = sp1; - asp.notify_one(); - }); + std::thread t([&] { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + asp = sp1; + asp.notify_one(); + }); - asp.wait(sp3); + asp.wait(sp3); - t.join(); - } + t.join(); } } From dc0a582c090cca7afd551c7c085b205201e21c11 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 12 Feb 2024 13:03:56 -0800 Subject: [PATCH 09/13] Also test shared_ptrs that own the null pointer. --- tests/std/include/test_atomic_wait.hpp | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index f99a0818507..3ea1b5b5d6f 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -202,6 +202,11 @@ struct with_padding_bits { }; #pragma warning(pop) +template +[[nodiscard]] bool ownership_equal(const T& t, const U& u) { + return !t.owner_before(u) && !u.owner_before(t); +} + inline void test_gh_3602(const __std_atomic_api_level level) { // GH-3602 std::atomic::wait does not seem to care about control block difference. Is this a bug? { @@ -242,6 +247,28 @@ inline void test_gh_3602(const __std_atomic_api_level level) { t.join(); } + + { // Also test shared_ptrs that own the null pointer. + int* const raw = nullptr; + + std::shared_ptr sp_empty; + std::shared_ptr sp_also_empty; + std::shared_ptr sp_original(raw); + std::shared_ptr sp_copy(sp_original); + std::shared_ptr sp_different(raw); + + assert(ownership_equal(sp_empty, sp_also_empty)); + assert(!ownership_equal(sp_original, sp_empty)); + assert(ownership_equal(sp_original, sp_copy)); + assert(!ownership_equal(sp_original, sp_different)); + + std::atomic> asp_empty; + asp_empty.wait(sp_original); + + std::atomic> asp_copy{sp_copy}; + asp_copy.wait(sp_empty); + asp_copy.wait(sp_different); + } } inline void test_atomic_wait(const __std_atomic_api_level level) { From f837e8ae9f13ce78b9dfa4ab31d959ae00e58363 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Tue, 13 Feb 2024 19:26:38 +0700 Subject: [PATCH 10/13] use growing timeout with __std_atomic_wait_direct --- stl/inc/memory | 4 +++- tests/std/include/test_atomic_wait.hpp | 8 ++++---- tests/std/tests/P1135R6_atomic_wait/test.cpp | 2 +- tests/std/tests/P1135R6_atomic_wait_vista/test.cpp | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 2e3f73c60f8..96fea07e1b0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4001,6 +4001,7 @@ protected: : _Ptr(_Px), _Repptr(_Ref) {} void _Wait(remove_extent_t<_Ty>* _Old_ptr, _Ref_count_base* const _Old_rep, memory_order) const noexcept { + unsigned long _Remaining_timeout = 4; for (;;) { auto _Rep = _Repptr._Lock_and_load(); bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && _Rep == _Old_rep; @@ -4008,7 +4009,8 @@ protected: if (!_Equal) { break; } - __std_atomic_wait_direct(&_Ptr, &_Old_ptr, sizeof(_Old_ptr), __std_atomic_wait_no_timeout); + __std_atomic_wait_direct(&_Ptr, &_Old_ptr, sizeof(_Old_ptr), _Remaining_timeout); + _Remaining_timeout *= 2; } } diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index 3ea1b5b5d6f..28f4be97fba 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -207,7 +207,7 @@ template return !t.owner_before(u) && !u.owner_before(t); } -inline void test_gh_3602(const __std_atomic_api_level level) { +inline void test_gh_3602() { // GH-3602 std::atomic::wait does not seem to care about control block difference. Is this a bug? { auto sp1 = std::make_shared(); @@ -229,7 +229,7 @@ inline void test_gh_3602(const __std_atomic_api_level level) { awp.wait(wp3); } - if (level == __std_atomic_api_level::__has_wait_on_address) { + { auto sp1 = std::make_shared(); auto holder = [sp1] {}; auto sp2 = std::make_shared(holder); @@ -271,7 +271,7 @@ inline void test_gh_3602(const __std_atomic_api_level level) { } } -inline void test_atomic_wait(const __std_atomic_api_level level) { +inline void test_atomic_wait() { // wait for all the threads to be waiting; if this value is too small the test might be ineffective but should not // fail due to timing assumptions except where otherwise noted; if it is too large the test will only take longer // than necessary @@ -362,5 +362,5 @@ inline void test_atomic_wait(const __std_atomic_api_level level) { #endif // ^^^ !ARM ^^^ #endif // ^^^ no workaround ^^^ - test_gh_3602(level); + test_gh_3602(); } diff --git a/tests/std/tests/P1135R6_atomic_wait/test.cpp b/tests/std/tests/P1135R6_atomic_wait/test.cpp index bd6b20ef069..2c62d15e1b2 100644 --- a/tests/std/tests/P1135R6_atomic_wait/test.cpp +++ b/tests/std/tests/P1135R6_atomic_wait/test.cpp @@ -59,5 +59,5 @@ void test_incomplete_associated_class_all() { // COMPILE-ONLY int main() { assert(__std_atomic_set_api_level(__std_atomic_api_level::__has_wait_on_address) == __std_atomic_api_level::__has_wait_on_address); - test_atomic_wait(__std_atomic_api_level::__has_wait_on_address); + test_atomic_wait(); } diff --git a/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp b/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp index 3bed62357c9..dc1dd27e1b0 100644 --- a/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp +++ b/tests/std/tests/P1135R6_atomic_wait_vista/test.cpp @@ -6,6 +6,6 @@ int main() { #if defined(_M_IX86) || defined(_M_X64) && !defined(_M_ARM64EC) assert(__std_atomic_set_api_level(__std_atomic_api_level::__has_srwlock) == __std_atomic_api_level::__has_srwlock); - test_atomic_wait(__std_atomic_api_level::__has_srwlock); + test_atomic_wait(); #endif // defined(_M_IX86) || defined(_M_X64) && !defined(_M_ARM64EC) } From 014a8c7f159818623efff1ca7d6d651cb34146df Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Tue, 13 Feb 2024 20:36:06 +0700 Subject: [PATCH 11/13] starting timeout = 16 --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 96fea07e1b0..2eeeb3bfb3e 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4001,7 +4001,7 @@ protected: : _Ptr(_Px), _Repptr(_Ref) {} void _Wait(remove_extent_t<_Ty>* _Old_ptr, _Ref_count_base* const _Old_rep, memory_order) const noexcept { - unsigned long _Remaining_timeout = 4; + unsigned long _Remaining_timeout = 16; for (;;) { auto _Rep = _Repptr._Lock_and_load(); bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && _Rep == _Old_rep; From 07a690319d152240ead4a23f22d05f4d8f52d06a Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Tue, 13 Feb 2024 22:50:25 +0700 Subject: [PATCH 12/13] limit timeout to 1 million milliseconds (~17 minutes) --- stl/inc/memory | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 2eeeb3bfb3e..8d6937ca818 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4002,6 +4002,7 @@ protected: void _Wait(remove_extent_t<_Ty>* _Old_ptr, _Ref_count_base* const _Old_rep, memory_order) const noexcept { unsigned long _Remaining_timeout = 16; + const unsigned long _Max_timeout = 1048576; for (;;) { auto _Rep = _Repptr._Lock_and_load(); bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && _Rep == _Old_rep; @@ -4010,7 +4011,7 @@ protected: break; } __std_atomic_wait_direct(&_Ptr, &_Old_ptr, sizeof(_Old_ptr), _Remaining_timeout); - _Remaining_timeout *= 2; + _Remaining_timeout = (_STD min)(_Max_timeout, _Remaining_timeout * 2); } } From fc399ef668e667315a395106614fa9cb34968f1f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 13 Feb 2024 08:04:24 -0800 Subject: [PATCH 13/13] Comment units. --- stl/inc/memory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 8d6937ca818..1e30aed1760 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4001,8 +4001,8 @@ protected: : _Ptr(_Px), _Repptr(_Ref) {} void _Wait(remove_extent_t<_Ty>* _Old_ptr, _Ref_count_base* const _Old_rep, memory_order) const noexcept { - unsigned long _Remaining_timeout = 16; - const unsigned long _Max_timeout = 1048576; + unsigned long _Remaining_timeout = 16; // milliseconds + const unsigned long _Max_timeout = 1048576; // milliseconds, ~17.5 minutes for (;;) { auto _Rep = _Repptr._Lock_and_load(); bool _Equal = _Ptr.load(memory_order_relaxed) == _Old_ptr && _Rep == _Old_rep;