diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt
index 968d98987ec..ac17fb0a55f 100644
--- a/stl/CMakeLists.txt
+++ b/stl/CMakeLists.txt
@@ -559,7 +559,7 @@ function(add_stl_dlls D_SUFFIX REL_OR_DBG)
generate_satellite_def("atomic_wait" "${D_SUFFIX}")
add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${CMAKE_BINARY_DIR}/msvcp_atomic_wait${D_SUFFIX}.def")
- target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib")
+ target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "synchronization.lib")
set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}")
set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_atomic_wait${VCLIBS_SUFFIX}")
diff --git a/stl/inc/xatomic_wait.h b/stl/inc/xatomic_wait.h
index 178f91fa9e8..5058335d974 100644
--- a/stl/inc/xatomic_wait.h
+++ b/stl/inc/xatomic_wait.h
@@ -21,23 +21,9 @@ _STL_DISABLE_CLANG_WARNINGS
extern "C" {
inline constexpr unsigned long __std_atomic_wait_no_timeout = 0xFFFF'FFFF; // Pass as partial timeout
-enum class __std_atomic_api_level : unsigned long {
- __not_set,
- __detecting,
- __has_srwlock,
- __has_wait_on_address,
-};
-
-// This function allows testing the atomic wait support while always using the APIs for a platform with fewer
-// capabilities; it attempts to lock the APIs used to the level `_Requested_api_level`, and returns the actual API level
-// in use. Once the API level has been set by calling this function (or detected by a call to one of the atomic wait
-// functions), it can no longer be changed.
-__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept;
-
// Support for atomic waits.
// The "direct" functions are used when the underlying infrastructure can use WaitOnAddress directly; that is, _Size is
-// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. If WaitOnAddress is not
-// available on the current platform, falls back to a similar solution based on SRWLOCK and CONDITION_VARIABLE.
+// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK.
int __stdcall __std_atomic_wait_direct(
const void* _Storage, void* _Comparand, size_t _Size, unsigned long _Remaining_timeout) noexcept;
void __stdcall __std_atomic_notify_one_direct(const void* _Storage) noexcept;
diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h
index fe1db005f75..57b25daf357 100644
--- a/stl/inc/yvals_core.h
+++ b/stl/inc/yvals_core.h
@@ -1974,7 +1974,6 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error.
#endif // defined(MRTDLL) && !defined(_M_CEE_PURE)
#define _STL_WIN32_WINNT_VISTA 0x0600 // _WIN32_WINNT_VISTA from sdkddkver.h
-#define _STL_WIN32_WINNT_WIN7 0x0601 // _WIN32_WINNT_WIN7 from sdkddkver.h
#define _STL_WIN32_WINNT_WIN8 0x0602 // _WIN32_WINNT_WIN8 from sdkddkver.h
#define _STL_WIN32_WINNT_WIN10 0x0A00 // _WIN32_WINNT_WIN10 from sdkddkver.h
@@ -1983,13 +1982,10 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error.
#if defined(_M_ARM64)
// The first ARM64 Windows was Windows 10
#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN10
-#elif defined(_M_ARM) || defined(_ONECORE) || defined(_CRT_APP)
-// The first ARM or OneCore or App Windows was Windows 8
+#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv
+// The earliest Windows supported by this implementation is Windows 8
#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN8
-#else // ^^^ default to Win8 / default to Win7 vvv
-// The earliest Windows supported by this implementation is Windows 7
-#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN7
-#endif // ^^^ !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_ONECORE) && !defined(_CRT_APP) ^^^
+#endif // ^^^ !defined(_M_ARM64) ^^^
#endif // !defined(_STL_WIN32_WINNT)
#ifdef __cpp_noexcept_function_type
diff --git a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets
index 869f8a1ecd2..0f29c995877 100644
--- a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets
+++ b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets
@@ -70,6 +70,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
diff --git a/stl/src/atomic_wait.cpp b/stl/src/atomic_wait.cpp
index 2ac108c9988..4bafb1a86bb 100644
--- a/stl/src/atomic_wait.cpp
+++ b/stl/src/atomic_wait.cpp
@@ -11,6 +11,8 @@
#include
+#pragma comment(lib, "synchronization")
+
namespace {
constexpr unsigned long long _Atomic_wait_no_deadline = 0xFFFF'FFFF'FFFF'FFFF;
@@ -89,134 +91,13 @@ namespace {
}
#endif // defined(_DEBUG)
}
-
-#ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
-#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8
-#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1
-#else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv
-#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0
-#endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^
-#endif // !defined(_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE)
-
-#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
-
-#pragma comment(lib, "synchronization")
-
-#define __crtWaitOnAddress WaitOnAddress
-#define __crtWakeByAddressSingle WakeByAddressSingle
-#define __crtWakeByAddressAll WakeByAddressAll
-
-#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv
-
- struct _Wait_functions_table {
- _STD atomic _Pfn_WaitOnAddress{nullptr};
- _STD atomic _Pfn_WakeByAddressSingle{nullptr};
- _STD atomic _Pfn_WakeByAddressAll{nullptr};
- _STD atomic<__std_atomic_api_level> _Api_level{__std_atomic_api_level::__not_set};
- };
-
- _Wait_functions_table _Wait_functions;
-
- void _Force_wait_functions_srwlock_only() noexcept {
- auto _Local = _Wait_functions._Api_level.load(_STD memory_order_acquire);
- if (_Local <= __std_atomic_api_level::__detecting) {
- while (!_Wait_functions._Api_level.compare_exchange_weak(
- _Local, __std_atomic_api_level::__has_srwlock, _STD memory_order_acq_rel)) {
- if (_Local > __std_atomic_api_level::__detecting) {
- return;
- }
- }
- }
- }
-
- [[nodiscard]] __std_atomic_api_level _Init_wait_functions(__std_atomic_api_level _Level) {
- while (!_Wait_functions._Api_level.compare_exchange_weak(
- _Level, __std_atomic_api_level::__detecting, _STD memory_order_acq_rel)) {
- if (_Level > __std_atomic_api_level::__detecting) {
- return _Level;
- }
- }
-
- _Level = __std_atomic_api_level::__has_srwlock;
-
- const HMODULE _Sync_module = GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll");
- if (_Sync_module != nullptr) {
- const auto _Wait_on_address =
- reinterpret_cast(GetProcAddress(_Sync_module, "WaitOnAddress"));
- const auto _Wake_by_address_single =
- reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressSingle"));
- const auto _Wake_by_address_all =
- reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressAll"));
-
- if (_Wait_on_address != nullptr && _Wake_by_address_single != nullptr && _Wake_by_address_all != nullptr) {
- _Wait_functions._Pfn_WaitOnAddress.store(_Wait_on_address, _STD memory_order_relaxed);
- _Wait_functions._Pfn_WakeByAddressSingle.store(_Wake_by_address_single, _STD memory_order_relaxed);
- _Wait_functions._Pfn_WakeByAddressAll.store(_Wake_by_address_all, _STD memory_order_relaxed);
- _Level = __std_atomic_api_level::__has_wait_on_address;
- }
- }
-
- // for __has_srwlock, relaxed would have been enough, not distinguishing for consistency
- _Wait_functions._Api_level.store(_Level, _STD memory_order_release);
- return _Level;
- }
-
- [[nodiscard]] __std_atomic_api_level _Acquire_wait_functions() noexcept {
- auto _Level = _Wait_functions._Api_level.load(_STD memory_order_acquire);
- if (_Level <= __std_atomic_api_level::__detecting) {
- _Level = _Init_wait_functions(_Level);
- }
-
- return _Level;
- }
-
- [[nodiscard]] BOOL __crtWaitOnAddress(
- volatile VOID* Address, PVOID CompareAddress, SIZE_T AddressSize, DWORD dwMilliseconds) {
- const auto _Wait_on_address = _Wait_functions._Pfn_WaitOnAddress.load(_STD memory_order_relaxed);
- return _Wait_on_address(Address, CompareAddress, AddressSize, dwMilliseconds);
- }
-
- VOID __crtWakeByAddressSingle(PVOID Address) {
- const auto _Wake_by_address_single = _Wait_functions._Pfn_WakeByAddressSingle.load(_STD memory_order_relaxed);
- _Wake_by_address_single(Address);
- }
-
- VOID __crtWakeByAddressAll(PVOID Address) {
- const auto _Wake_by_address_all = _Wait_functions._Pfn_WakeByAddressAll.load(_STD memory_order_relaxed);
- _Wake_by_address_all(Address);
- }
-
- bool __stdcall _Atomic_wait_are_equal_direct_fallback(
- const void* _Storage, void* _Comparand, size_t _Size, void*) noexcept {
- switch (_Size) {
- case 1:
- return __iso_volatile_load8(static_cast(_Storage)) == *static_cast(_Comparand);
- case 2:
- return __iso_volatile_load16(static_cast(_Storage)) == *static_cast(_Comparand);
- case 4:
- return __iso_volatile_load32(static_cast(_Storage)) == *static_cast(_Comparand);
- case 8:
- return __iso_volatile_load64(static_cast(_Storage))
- == *static_cast(_Comparand);
- default:
- _CSTD abort();
- }
- }
-#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
} // unnamed namespace
extern "C" {
int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _Comparand, const size_t _Size,
const unsigned long _Remaining_timeout) noexcept {
-#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
- if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) {
- return __std_atomic_wait_indirect(
- _Storage, _Comparand, _Size, nullptr, &_Atomic_wait_are_equal_direct_fallback, _Remaining_timeout);
- }
-#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
-
- const auto _Result = __crtWaitOnAddress(
- const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout);
+ const auto _Result =
+ WaitOnAddress(const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout);
if (!_Result) {
_Assume_timeout();
@@ -225,25 +106,11 @@ int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _
}
void __stdcall __std_atomic_notify_one_direct(const void* const _Storage) noexcept {
-#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
- if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) {
- __std_atomic_notify_one_indirect(_Storage);
- return;
- }
-#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE = 0
-
- __crtWakeByAddressSingle(const_cast(_Storage));
+ WakeByAddressSingle(const_cast(_Storage));
}
void __stdcall __std_atomic_notify_all_direct(const void* const _Storage) noexcept {
-#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
- if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) {
- __std_atomic_notify_all_indirect(_Storage);
- return;
- }
-#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
-
- __crtWakeByAddressAll(const_cast(_Storage));
+ WakeByAddressAll(const_cast(_Storage));
}
void __stdcall __std_atomic_notify_one_indirect(const void* const _Storage) noexcept {
@@ -339,25 +206,10 @@ unsigned long __stdcall __std_atomic_wait_get_remaining_timeout(unsigned long lo
return static_cast(_Remaining);
}
-__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept {
-#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
- (void) _Requested_api_level;
+// TRANSITION, ABI: preserved for binary compatibility
+enum class __std_atomic_api_level : unsigned long { __not_set, __detecting, __has_srwlock, __has_wait_on_address };
+__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level) noexcept {
return __std_atomic_api_level::__has_wait_on_address;
-#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv
- switch (_Requested_api_level) {
- case __std_atomic_api_level::__not_set:
- case __std_atomic_api_level::__detecting:
- _CSTD abort();
- case __std_atomic_api_level::__has_srwlock:
- _Force_wait_functions_srwlock_only();
- break;
- case __std_atomic_api_level::__has_wait_on_address:
- default: // future compat: new header using an old DLL will get the highest requested level supported
- break;
- }
-
- return _Acquire_wait_functions();
-#endif // !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
}
#pragma warning(push)
diff --git a/stl/src/awint.hpp b/stl/src/awint.hpp
index da1e26e470a..797801b7a98 100644
--- a/stl/src/awint.hpp
+++ b/stl/src/awint.hpp
@@ -14,17 +14,6 @@
_CRT_BEGIN_C_HEADER
-#if _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8
-
-#define __crtGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) \
- GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime)
-
-#else // ^^^ _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 vvv
-
-_CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept;
-
-#endif // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 ^^^
-
_CRTIMP2 int __cdecl __crtCompareStringA(_In_z_ LPCWSTR _LocaleName, _In_ DWORD _DwCmpFlags,
_In_reads_(_CchCount1) LPCSTR _LpString1, _In_ int _CchCount1, _In_reads_(_CchCount2) LPCSTR _LpString2,
_In_ int _CchCount2, _In_ int _CodePage) noexcept;
diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp
index ef1048cad14..62cf885e54a 100644
--- a/stl/src/ppltasks.cpp
+++ b/stl/src/ppltasks.cpp
@@ -26,12 +26,6 @@ namespace Concurrency {
namespace details {
[[noreturn]] _CRTIMP2 void __cdecl _ReportUnobservedException() {
-#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_CRT_APP) && _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
- if (!IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) {
- std::abort();
- }
-#endif // ^^^ __fastfail conditionally available ^^^
-
__fastfail(FAST_FAIL_INVALID_ARG);
}
diff --git a/stl/src/winapisupp.cpp b/stl/src/winapisupp.cpp
index 747fe070d2a..de6f6ae4d29 100644
--- a/stl/src/winapisupp.cpp
+++ b/stl/src/winapisupp.cpp
@@ -14,10 +14,6 @@ namespace {
// Use this macro for defining the following function pointers
#define DEFINEFUNCTIONPOINTER(fn_name) decltype(&fn_name) __KERNEL32Function_##fn_name = nullptr
-#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
- DEFINEFUNCTIONPOINTER(GetSystemTimePreciseAsFileTime);
-#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
-
DEFINEFUNCTIONPOINTER(GetTempPath2W);
// Use this macro for caching a function pointer from a DLL
@@ -158,15 +154,9 @@ extern "C" _CRTIMP2 BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE con
#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
+// TRANSITION, ABI: preserved for binary compatibility
extern "C" _CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept {
- // use GetSystemTimePreciseAsFileTime if it is available (only on Windows 8+)...
- IFDYNAMICGETCACHEDFUNCTION(GetSystemTimePreciseAsFileTime) {
- pfGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime);
- return;
- }
-
- // ...otherwise use GetSystemTimeAsFileTime.
- GetSystemTimeAsFileTime(lpSystemTimeAsFileTime);
+ GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime);
}
#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
@@ -196,10 +186,6 @@ static int __cdecl initialize_pointers() noexcept {
HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll");
_Analysis_assume_(hKernel32);
-#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
- STOREFUNCTIONPOINTER(hKernel32, GetSystemTimePreciseAsFileTime);
-#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8
-
// Note that GetTempPath2W is defined as of Windows 10 Build 20348 (a server release) or Windows 11,
// but there is no "_WIN32_WINNT_WIN11" constant, so we will always dynamically load it
STOREFUNCTIONPOINTER(hKernel32, GetTempPath2W);
diff --git a/stl/src/xtime.cpp b/stl/src/xtime.cpp
index c59d0fc73af..7499f42e19d 100644
--- a/stl/src/xtime.cpp
+++ b/stl/src/xtime.cpp
@@ -51,7 +51,7 @@ _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks() noexcept {
constexpr long long _Epoch = 0x19DB1DED53E8000LL;
FILETIME ft;
- __crtGetSystemTimePreciseAsFileTime(&ft);
+ GetSystemTimePreciseAsFileTime(&ft);
return ((static_cast(ft.dwHighDateTime)) << 32) + static_cast(ft.dwLowDateTime) - _Epoch;
}
diff --git a/tests/std/test.lst b/tests/std/test.lst
index ba093a6b814..7489fd82a95 100644
--- a/tests/std/test.lst
+++ b/tests/std/test.lst
@@ -542,7 +542,6 @@ tests\P1032R1_miscellaneous_constexpr
tests\P1132R7_out_ptr
tests\P1135R6_atomic_flag_test
tests\P1135R6_atomic_wait
-tests\P1135R6_atomic_wait_win7
tests\P1135R6_barrier
tests\P1135R6_latch
tests\P1135R6_semaphore
diff --git a/tests/std/tests/P1135R6_atomic_wait_win7/env.lst b/tests/std/tests/P1135R6_atomic_wait_win7/env.lst
deleted file mode 100644
index 351a8293d9d..00000000000
--- a/tests/std/tests/P1135R6_atomic_wait_win7/env.lst
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft Corporation.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-RUNALL_INCLUDE ..\usual_20_matrix.lst
diff --git a/tests/std/tests/P1135R6_atomic_wait_win7/test.cpp b/tests/std/tests/P1135R6_atomic_wait_win7/test.cpp
deleted file mode 100644
index d6deabafaaf..00000000000
--- a/tests/std/tests/P1135R6_atomic_wait_win7/test.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-template class Template, class UnderlyingType>
-void test_atomic_wait_func_impl(UnderlyingType& old_value, const UnderlyingType new_value,
- const std::chrono::steady_clock::duration waiting_duration) {
- constexpr int seq_max_size = 10;
- char seq[seq_max_size + 1];
- std::atomic base = seq;
- auto add_seq = [&](char ch) {
- char* p = base.fetch_add(1, std::memory_order_relaxed);
- assert(p - seq < seq_max_size);
- *p = ch;
- };
-
- Template a(old_value);
- a.wait(new_value);
-
- add_seq('1');
-
- std::thread thd([&] {
- std::this_thread::sleep_for(waiting_duration);
- add_seq('2');
- a.notify_all();
- std::this_thread::sleep_for(waiting_duration);
- add_seq('3');
- a.store(old_value);
- a.notify_one();
- std::this_thread::sleep_for(waiting_duration);
- add_seq('4');
- a.store(new_value);
- a.notify_one();
-#ifdef CAN_FAIL_ON_TIMING_ASSUMPTION
- // timing assumption that the main thread evaluates the `wait(old_value)` before this timeout expires
- std::this_thread::sleep_for(waiting_duration);
- add_seq('6');
-#endif
- });
-
- a.wait(old_value);
- const auto loaded = a.load();
- assert(memcmp(&loaded, &new_value, sizeof(UnderlyingType)) == 0);
-
- add_seq('5');
-
- thd.join();
-
- add_seq('\0');
-
-#ifdef CAN_FAIL_ON_TIMING_ASSUMPTION
- assert(strcmp(seq, "123456") == 0);
-#else
- assert(strcmp(seq, "12345") == 0);
-#endif
-}
-
-template
-void test_atomic_wait_func(UnderlyingType old_value, const UnderlyingType new_value,
- const std::chrono::steady_clock::duration waiting_duration) {
- test_atomic_wait_func_impl(old_value, new_value, waiting_duration);
- alignas(std::atomic_ref::required_alignment) UnderlyingType old_value_for_ref = old_value;
- test_atomic_wait_func_impl(old_value_for_ref, new_value, waiting_duration);
-}
-
-template
-void test_atomic_wait_func_ptr(UnderlyingType old_value, const UnderlyingType new_value,
- const std::chrono::steady_clock::duration waiting_duration) {
- test_atomic_wait_func_impl(old_value, new_value, waiting_duration);
-}
-
-
-template class Template, class UnderlyingType>
-void test_notify_all_notifies_all_impl(UnderlyingType& old_value, const UnderlyingType new_value,
- const std::chrono::steady_clock::duration waiting_duration) {
- Template c(old_value);
- const auto waitFn = [&c, old_value] { c.wait(old_value); };
-
- std::thread w1{waitFn};
- std::thread w2{waitFn};
- std::thread w3{waitFn};
-
- std::this_thread::sleep_for(waiting_duration);
- c.store(new_value);
- c.notify_all(); // if this doesn't really notify all, the following joins will deadlock
-
- w1.join();
- w2.join();
- w3.join();
-}
-
-template
-void test_notify_all_notifies_all(UnderlyingType old_value, const UnderlyingType new_value,
- const std::chrono::steady_clock::duration waiting_duration) {
- test_notify_all_notifies_all_impl(old_value, new_value, waiting_duration);
- alignas(std::atomic_ref::required_alignment) UnderlyingType old_value_for_ref = old_value;
- test_notify_all_notifies_all_impl(old_value_for_ref, new_value, waiting_duration);
-}
-
-template
-void test_notify_all_notifies_all_ptr(UnderlyingType old_value, const UnderlyingType new_value,
- const std::chrono::steady_clock::duration waiting_duration) {
- // increased waiting_duration because timing assumption might not hold for atomic smart pointers
- test_notify_all_notifies_all_impl(old_value, new_value, 3 * waiting_duration);
-}
-
-
-template class Template, class UnderlyingType>
-void test_pad_bits_impl(const std::chrono::steady_clock::duration waiting_duration) {
- alignas(std::atomic_ref::required_alignment) UnderlyingType old_value;
- memset(&old_value, 0x66, sizeof(UnderlyingType));
- old_value.set(1);
-
- UnderlyingType same_old_value;
- memset(&same_old_value, 0x99, sizeof(UnderlyingType));
- same_old_value.set(1);
-
- Template c(old_value);
-
- bool trigger = false;
- const auto waitFn = [&c, same_old_value, &trigger] {
- c.wait(same_old_value);
- trigger = true;
- };
-
- std::thread w1{waitFn};
-
- std::this_thread::sleep_for(waiting_duration);
- assert(!trigger);
-
- c.store(old_value);
- c.notify_one();
-
- std::this_thread::sleep_for(waiting_duration);
- assert(!trigger);
-
- UnderlyingType new_value;
- memset(&new_value, 0x99, sizeof(UnderlyingType));
- new_value.set(2);
- c.store(new_value);
- c.notify_one();
-
-#ifdef CAN_FAIL_ON_TIMING_ASSUMPTION
- std::this_thread::sleep_for(waiting_duration);
- assert(trigger);
- w1.join();
-#else // ^^^ CAN_FAIL_ON_TIMING_ASSUMPTION / !CAN_FAIL_ON_TIMING_ASSUMPTION vvv
- w1.join();
- assert(trigger);
-#endif // ^^^ !CAN_FAIL_ON_TIMING_ASSUMPTION ^^^
-}
-
-template
-void test_pad_bits(const std::chrono::steady_clock::duration waiting_duration) {
- test_pad_bits_impl(waiting_duration);
- test_pad_bits_impl(waiting_duration);
-}
-
-struct two_shorts {
- short a;
- short b;
-
- friend bool operator==(two_shorts, two_shorts) = delete;
-};
-
-struct three_chars {
- char a;
- char b;
- char c;
-
- friend bool operator==(three_chars, three_chars) = delete;
-};
-
-struct big_char_like {
- char value;
- char unused[16];
-
- explicit big_char_like(char value_) : value(value_), unused{} {}
-
- friend bool operator==(big_char_like, big_char_like) = delete;
-};
-
-#pragma warning(push)
-#pragma warning(disable : 4324) // structure was padded due to alignment specifier
-template
-struct with_padding_bits {
- alignas(size) char value;
-
- void set(const char value_) {
- value = value_;
- }
-
- friend bool operator==(with_padding_bits, with_padding_bits) = delete;
-};
-#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() {
- // 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);
- }
-
- {
- 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();
- }
-
- { // 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() {
- // 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
- constexpr std::chrono::milliseconds waiting_duration{100};
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func(1, 2, waiting_duration);
- test_atomic_wait_func("1", "2", waiting_duration);
- test_atomic_wait_func(two_shorts{1, 1}, two_shorts{1, 2}, waiting_duration);
- test_atomic_wait_func(three_chars{1, 1, 3}, three_chars{1, 2, 3}, waiting_duration);
- test_atomic_wait_func(big_char_like{'a'}, big_char_like{'b'}, waiting_duration);
-
- test_atomic_wait_func_ptr(std::make_shared('a'), std::make_shared('a'), waiting_duration);
- test_atomic_wait_func_ptr(
- std::weak_ptr{std::make_shared('a')}, std::weak_ptr{std::make_shared('a')}, waiting_duration);
- test_atomic_wait_func_ptr(std::make_shared(0), std::make_shared(0), waiting_duration);
- test_atomic_wait_func_ptr(
- std::weak_ptr{std::make_shared(0)}, std::weak_ptr{std::make_shared(0)}, waiting_duration);
- test_atomic_wait_func_ptr(std::make_shared(1), std::make_shared(1), waiting_duration);
- test_atomic_wait_func_ptr(
- std::weak_ptr{std::make_shared(1)}, std::weak_ptr{std::make_shared(1)}, waiting_duration);
- test_atomic_wait_func_ptr(std::make_shared(), std::make_shared(), waiting_duration);
- test_atomic_wait_func_ptr(
- std::weak_ptr{std::make_shared()}, std::weak_ptr{std::make_shared()}, waiting_duration);
- test_atomic_wait_func_ptr(std::make_shared(2), std::make_shared(2), waiting_duration);
- test_atomic_wait_func_ptr(
- std::weak_ptr{std::make_shared(2)}, std::weak_ptr{std::make_shared(2)}, waiting_duration);
- test_atomic_wait_func_ptr(std::make_shared(), std::make_shared(), waiting_duration);
- test_atomic_wait_func_ptr(
- std::weak_ptr{std::make_shared()}, std::weak_ptr{std::make_shared()}, waiting_duration);
-
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all(1, 2, waiting_duration);
- test_notify_all_notifies_all("1", "2", waiting_duration);
- test_notify_all_notifies_all(two_shorts{1, 1}, two_shorts{1, 2}, waiting_duration);
- test_notify_all_notifies_all(three_chars{1, 1, 3}, three_chars{1, 2, 3}, waiting_duration);
- test_notify_all_notifies_all(big_char_like{'a'}, big_char_like{'b'}, waiting_duration);
-
- test_notify_all_notifies_all_ptr(std::make_shared('a'), std::make_shared('a'), waiting_duration);
- test_notify_all_notifies_all_ptr(
- std::weak_ptr{std::make_shared('a')}, std::weak_ptr{std::make_shared('a')}, waiting_duration);
- test_notify_all_notifies_all_ptr(std::make_shared(0), std::make_shared(0), waiting_duration);
- test_notify_all_notifies_all_ptr(
- std::weak_ptr{std::make_shared(0)}, std::weak_ptr{std::make_shared(0)}, waiting_duration);
- test_notify_all_notifies_all_ptr(std::make_shared(1), std::make_shared(1), waiting_duration);
- test_notify_all_notifies_all_ptr(
- std::weak_ptr{std::make_shared(1)}, std::weak_ptr{std::make_shared(1)}, waiting_duration);
- test_notify_all_notifies_all_ptr(std::make_shared(), std::make_shared(), waiting_duration);
- test_notify_all_notifies_all_ptr(
- std::weak_ptr{std::make_shared()}, std::weak_ptr{std::make_shared()}, waiting_duration);
- test_notify_all_notifies_all_ptr(std::make_shared(2), std::make_shared(2), waiting_duration);
- test_notify_all_notifies_all_ptr(
- std::weak_ptr{std::make_shared(2)}, std::weak_ptr{std::make_shared(2)}, waiting_duration);
- test_notify_all_notifies_all_ptr(std::make_shared(), std::make_shared(), waiting_duration);
- test_notify_all_notifies_all_ptr(
- std::weak_ptr{std::make_shared()}, std::weak_ptr{std::make_shared()}, waiting_duration);
-
-#ifndef __clang__ // TRANSITION, LLVM-46685
- test_pad_bits>(waiting_duration);
- test_pad_bits>(waiting_duration);
- test_pad_bits>(waiting_duration);
-#ifndef _M_ARM
- test_pad_bits>(waiting_duration);
- test_pad_bits>(waiting_duration);
-#endif // ^^^ !ARM ^^^
-#endif // ^^^ no workaround ^^^
-
- test_gh_3602();
-}
-
-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();
-#endif // defined(_M_IX86) || defined(_M_X64) && !defined(_M_ARM64EC)
-}