Skip to content

Commit 63ee5da

Browse files
author
Roger Sanders
committed
[libc++] Improve performance of std::atomic_flag on Windows
On Windows 8 and above, the WaitOnAddress, WakeByAddressSingle and WakeByAddressAll functions allow efficient implementation of the C++20 wait and notify features of std::atomic_flag. These Windows functions have never been made use of in libc++, leading to very poor performance of these features on Windows platforms, as they are implemented using a spin loop with backoff, rather than using any OS thread signalling whatsoever. This change implements the use of these OS functions where available, falling back to the original implementation on Windows versions prior to 8. Fixes #127221
1 parent 3984d19 commit 63ee5da

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

libcxx/src/atomic.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
// OpenBSD has no indirect syscalls
4242
# define _LIBCPP_FUTEX(...) futex(__VA_ARGS__)
4343

44+
#elif defined(_WIN32)
45+
46+
# include <windows.h>
47+
4448
#else // <- Add other operating systems here
4549

4650
// Baseline needs no new headers
@@ -101,6 +105,37 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo
101105
_umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, nullptr, nullptr);
102106
}
103107

108+
#elif defined(_WIN32)
109+
110+
static void
111+
__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) {
112+
static auto pWaitOnAddress = reinterpret_cast<BOOL(WINAPI*)(volatile void*, PVOID, SIZE_T, DWORD)>(
113+
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WaitOnAddress"));
114+
if (pWaitOnAddress != nullptr) {
115+
pWaitOnAddress(const_cast<__cxx_atomic_contention_t*>(__ptr), &__val, sizeof(__val), INFINITE);
116+
} else {
117+
__libcpp_thread_poll_with_backoff(
118+
[=]() -> bool { return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__ptr, memory_order_relaxed), __val); },
119+
__libcpp_timed_backoff_policy());
120+
}
121+
}
122+
123+
static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) {
124+
if (__notify_one) {
125+
static auto pWakeByAddressSingle = reinterpret_cast<void(WINAPI*)(PVOID)>(
126+
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressSingle"));
127+
if (pWakeByAddressSingle != nullptr) {
128+
pWakeByAddressSingle(const_cast<__cxx_atomic_contention_t*>(__ptr));
129+
}
130+
} else {
131+
static auto pWakeByAddressAll = reinterpret_cast<void(WINAPI*)(PVOID)>(
132+
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressAll"));
133+
if (pWakeByAddressAll != nullptr) {
134+
pWakeByAddressAll(const_cast<__cxx_atomic_contention_t*>(__ptr));
135+
}
136+
}
137+
}
138+
104139
#else // <- Add other operating systems here
105140

106141
// Baseline is just a timed backoff

0 commit comments

Comments
 (0)