[libcxx-commits] [libcxx] [libc++] Improve performance of std::atomic_flag on Windows (PR #163524)
Roger Sanders via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 21 03:12:49 PDT 2025
https://github.com/RogerSanders updated https://github.com/llvm/llvm-project/pull/163524
>From 63ee5dad50b8cb0e20abb8948030bd6218144b3c Mon Sep 17 00:00:00 2001
From: Roger Sanders <roger.sanders at maptek.com.au>
Date: Wed, 15 Oct 2025 19:30:41 +1100
Subject: [PATCH 1/3] [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
---
libcxx/src/atomic.cpp | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/libcxx/src/atomic.cpp b/libcxx/src/atomic.cpp
index b214ba1fd11c0..4b9e53c264787 100644
--- a/libcxx/src/atomic.cpp
+++ b/libcxx/src/atomic.cpp
@@ -41,6 +41,10 @@
// OpenBSD has no indirect syscalls
# define _LIBCPP_FUTEX(...) futex(__VA_ARGS__)
+#elif defined(_WIN32)
+
+# include <windows.h>
+
#else // <- Add other operating systems here
// Baseline needs no new headers
@@ -101,6 +105,37 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo
_umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, nullptr, nullptr);
}
+#elif defined(_WIN32)
+
+static void
+__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) {
+ static auto pWaitOnAddress = reinterpret_cast<BOOL(WINAPI*)(volatile void*, PVOID, SIZE_T, DWORD)>(
+ GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WaitOnAddress"));
+ if (pWaitOnAddress != nullptr) {
+ pWaitOnAddress(const_cast<__cxx_atomic_contention_t*>(__ptr), &__val, sizeof(__val), INFINITE);
+ } else {
+ __libcpp_thread_poll_with_backoff(
+ [=]() -> bool { return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__ptr, memory_order_relaxed), __val); },
+ __libcpp_timed_backoff_policy());
+ }
+}
+
+static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) {
+ if (__notify_one) {
+ static auto pWakeByAddressSingle = reinterpret_cast<void(WINAPI*)(PVOID)>(
+ GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressSingle"));
+ if (pWakeByAddressSingle != nullptr) {
+ pWakeByAddressSingle(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ }
+ } else {
+ static auto pWakeByAddressAll = reinterpret_cast<void(WINAPI*)(PVOID)>(
+ GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressAll"));
+ if (pWakeByAddressAll != nullptr) {
+ pWakeByAddressAll(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ }
+ }
+}
+
#else // <- Add other operating systems here
// Baseline is just a timed backoff
>From 45156287d13a945dd13ab5aeeb211e44597c94ac Mon Sep 17 00:00:00 2001
From: Roger Sanders <roger.sanders at maptek.com.au>
Date: Wed, 15 Oct 2025 20:42:49 +1100
Subject: [PATCH 2/3] [libc++] Fixed naming, added comments.
---
libcxx/src/atomic.cpp | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/libcxx/src/atomic.cpp b/libcxx/src/atomic.cpp
index 4b9e53c264787..4001e48f1ec25 100644
--- a/libcxx/src/atomic.cpp
+++ b/libcxx/src/atomic.cpp
@@ -109,10 +109,11 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo
static void
__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) {
- static auto pWaitOnAddress = reinterpret_cast<BOOL(WINAPI*)(volatile void*, PVOID, SIZE_T, DWORD)>(
+ // WaitOnAddress was added in Windows 8 (build 9200)
+ static auto __pWaitOnAddress = reinterpret_cast<BOOL(WINAPI*)(volatile void*, PVOID, SIZE_T, DWORD)>(
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WaitOnAddress"));
- if (pWaitOnAddress != nullptr) {
- pWaitOnAddress(const_cast<__cxx_atomic_contention_t*>(__ptr), &__val, sizeof(__val), INFINITE);
+ if (__pWaitOnAddress != nullptr) {
+ __pWaitOnAddress(const_cast<__cxx_atomic_contention_t*>(__ptr), &__val, sizeof(__val), INFINITE);
} else {
__libcpp_thread_poll_with_backoff(
[=]() -> bool { return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__ptr, memory_order_relaxed), __val); },
@@ -122,16 +123,18 @@ __libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __pt
static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) {
if (__notify_one) {
- static auto pWakeByAddressSingle = reinterpret_cast<void(WINAPI*)(PVOID)>(
+ // WakeByAddressSingle was added in Windows 8 (build 9200)
+ static auto __pWakeByAddressSingle = reinterpret_cast<void(WINAPI*)(PVOID)>(
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressSingle"));
- if (pWakeByAddressSingle != nullptr) {
- pWakeByAddressSingle(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ if (__pWakeByAddressSingle != nullptr) {
+ __pWakeByAddressSingle(const_cast<__cxx_atomic_contention_t*>(__ptr));
}
} else {
- static auto pWakeByAddressAll = reinterpret_cast<void(WINAPI*)(PVOID)>(
+ // WakeByAddressAll was added in Windows 8 (build 9200)
+ static auto __pWakeByAddressAll = reinterpret_cast<void(WINAPI*)(PVOID)>(
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressAll"));
- if (pWakeByAddressAll != nullptr) {
- pWakeByAddressAll(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ if (__pWakeByAddressAll != nullptr) {
+ __pWakeByAddressAll(const_cast<__cxx_atomic_contention_t*>(__ptr));
}
}
}
>From 49efee9e4878f6a4126cbc10009d3cfdaee867f6 Mon Sep 17 00:00:00 2001
From: Roger Sanders <roger.sanders at maptek.com.au>
Date: Tue, 21 Oct 2025 21:12:35 +1100
Subject: [PATCH 3/3] [libc++] More naming and comment changes as recommended
---
libcxx/src/atomic.cpp | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/libcxx/src/atomic.cpp b/libcxx/src/atomic.cpp
index 4001e48f1ec25..e9cb38b5ef91a 100644
--- a/libcxx/src/atomic.cpp
+++ b/libcxx/src/atomic.cpp
@@ -110,10 +110,10 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo
static void
__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) {
// WaitOnAddress was added in Windows 8 (build 9200)
- static auto __pWaitOnAddress = reinterpret_cast<BOOL(WINAPI*)(volatile void*, PVOID, SIZE_T, DWORD)>(
+ static auto wait_on_address = reinterpret_cast<BOOL(WINAPI*)(volatile void*, PVOID, SIZE_T, DWORD)>(
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WaitOnAddress"));
- if (__pWaitOnAddress != nullptr) {
- __pWaitOnAddress(const_cast<__cxx_atomic_contention_t*>(__ptr), &__val, sizeof(__val), INFINITE);
+ if (wait_on_address != nullptr) {
+ wait_on_address(const_cast<__cxx_atomic_contention_t*>(__ptr), &__val, sizeof(__val), INFINITE);
} else {
__libcpp_thread_poll_with_backoff(
[=]() -> bool { return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__ptr, memory_order_relaxed), __val); },
@@ -124,17 +124,23 @@ __libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __pt
static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) {
if (__notify_one) {
// WakeByAddressSingle was added in Windows 8 (build 9200)
- static auto __pWakeByAddressSingle = reinterpret_cast<void(WINAPI*)(PVOID)>(
+ static auto wake_by_address_single = reinterpret_cast<void(WINAPI*)(PVOID)>(
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressSingle"));
- if (__pWakeByAddressSingle != nullptr) {
- __pWakeByAddressSingle(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ if (wake_by_address_single != nullptr) {
+ wake_by_address_single(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ } else {
+ // The fallback implementation of waking does nothing, as the fallback wait implementation just does polling, so
+ // there's nothing to do here.
}
} else {
// WakeByAddressAll was added in Windows 8 (build 9200)
- static auto __pWakeByAddressAll = reinterpret_cast<void(WINAPI*)(PVOID)>(
+ static auto wake_by_address_all = reinterpret_cast<void(WINAPI*)(PVOID)>(
GetProcAddress(GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"), "WakeByAddressAll"));
- if (__pWakeByAddressAll != nullptr) {
- __pWakeByAddressAll(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ if (wake_by_address_all != nullptr) {
+ wake_by_address_all(const_cast<__cxx_atomic_contention_t*>(__ptr));
+ } else {
+ // The fallback implementation of waking does nothing, as the fallback wait implementation just does polling, so
+ // there's nothing to do here.
}
}
}
More information about the libcxx-commits
mailing list