[libcxx-commits] [libcxx] [libc++] refactor poll_with_backoff (PR #173184)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Dec 21 02:56:30 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Hui (huixie90)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/173184.diff
4 Files Affected:
- (modified) libcxx/include/__atomic/atomic_sync.h (+7-7)
- (modified) libcxx/include/__thread/poll_with_backoff.h (+27-8)
- (modified) libcxx/include/__thread/timed_backoff_policy.h (+3-2)
- (modified) libcxx/include/semaphore (+2-1)
``````````diff
diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h
index d0119ab5d35ec..ff96be1c2dcad 100644
--- a/libcxx/include/__atomic/atomic_sync.h
+++ b/libcxx/include/__atomic/atomic_sync.h
@@ -161,7 +161,7 @@ struct __atomic_wait_backoff_impl {
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
using __value_type _LIBCPP_NODEBUG = typename __waitable_traits::__value_type;
- _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
+ _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::microseconds(4)) {
auto __contention_address = const_cast<const void*>(
static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a_)));
@@ -169,18 +169,18 @@ struct __atomic_wait_backoff_impl {
if constexpr (__has_native_atomic_wait<__value_type>) {
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
if (__poll_(__atomic_value))
- return true;
+ return __backoff_results::__poll_success;
std::__atomic_wait_native<sizeof(__value_type)>(__contention_address, std::addressof(__atomic_value));
} else {
__cxx_contention_t __monitor_val = std::__atomic_monitor_global(__contention_address);
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
if (__poll_(__atomic_value))
- return true;
+ return __backoff_results::__poll_success;
std::__atomic_wait_global_table(__contention_address, __monitor_val);
}
} else {
} // poll
- return false;
+ return __backoff_results::__continue_poll;
}
};
@@ -215,16 +215,16 @@ struct __atomic_wait_backoff_impl {
return __poll_(__current_val);
}
- _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
+ _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::microseconds(4)) {
auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
__cxx_contention_t __monitor_val;
if (__update_monitor_val_and_poll(__contention_address, __monitor_val))
- return true;
+ return __backoff_results::__poll_success;
std::__libcpp_atomic_wait(__contention_address, __monitor_val);
} else {
} // poll
- return false;
+ return __backoff_results::__continue_poll;
}
};
diff --git a/libcxx/include/__thread/poll_with_backoff.h b/libcxx/include/__thread/poll_with_backoff.h
index b42b1285c13c8..e007e7746ca52 100644
--- a/libcxx/include/__thread/poll_with_backoff.h
+++ b/libcxx/include/__thread/poll_with_backoff.h
@@ -22,33 +22,50 @@ _LIBCPP_BEGIN_NAMESPACE_STD
static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64;
+enum class __backoff_results : unsigned char {
+ __continue_poll = 1,
+ __poll_success = 2,
+ __timeout = 3,
+ __backoff_failure = 4,
+};
+
+enum class __poll_with_backoff_results : unsigned char {
+ __poll_success = static_cast<unsigned char>(__backoff_results::__poll_success),
+ __timeout = static_cast<unsigned char>(__backoff_results::__timeout),
+ __backoff_failure = static_cast<unsigned char>(__backoff_results::__backoff_failure),
+};
+
// Polls a thread for a condition given by a predicate, and backs off based on a backoff policy
// before polling again.
//
// - __poll is the "test function" that should return true if polling succeeded, and false if it failed.
//
// - __backoff is the "backoff policy", which is called with the duration since we started polling. It should
-// return false in order to resume polling, and true if polling should stop entirely for some reason.
+// return __backoff_results::__continue_poll in order to resume polling, and other appropriate __backoff_results
+// if polling should stop entirely for some reason.
// In general, backoff policies sleep for some time before returning control to the polling loop.
//
// - __max_elapsed is the maximum duration to try polling for. If the maximum duration is exceeded,
-// the polling loop will return false to report a timeout.
+// the polling loop will return __poll_with_backoff_results::__timeout to report a timeout.
+
template <class _Poll, class _Backoff>
-_LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_poll_with_backoff(
+_LIBCPP_HIDE_FROM_ABI __poll_with_backoff_results __libcpp_thread_poll_with_backoff(
_Poll&& __poll, _Backoff&& __backoff, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero()) {
auto const __start = chrono::high_resolution_clock::now();
for (int __count = 0;;) {
if (__poll())
- return true; // __poll completion means success
+ return __poll_with_backoff_results::__poll_success;
if (__count < __libcpp_polling_count) {
__count += 1;
continue;
}
chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start;
if (__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed)
- return false; // timeout failure
- if (__backoff(__elapsed))
- return false; // __backoff completion means failure
+ return __poll_with_backoff_results::__timeout;
+ if (auto __backoff_res = __backoff(__elapsed); __backoff_res == __backoff_results::__continue_poll)
+ continue;
+ else
+ return static_cast<__poll_with_backoff_results>(__backoff_res);
}
}
@@ -59,7 +76,9 @@ _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_poll_with_backoff(
// so this should most likely only be used on single-threaded systems where there
// are no other threads to compete with.
struct __spinning_backoff_policy {
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(chrono::nanoseconds const&) const { return false; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __backoff_results operator()(chrono::nanoseconds const&) const {
+ return __backoff_results::__continue_poll;
+ }
};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__thread/timed_backoff_policy.h b/libcxx/include/__thread/timed_backoff_policy.h
index 35a72eb61f77e..01fe2dd045e58 100644
--- a/libcxx/include/__thread/timed_backoff_policy.h
+++ b/libcxx/include/__thread/timed_backoff_policy.h
@@ -11,6 +11,7 @@
#define _LIBCPP___THREAD_TIMED_BACKOFF_POLICY_H
#include <__config>
+#include <__thread/poll_with_backoff.h>
#if _LIBCPP_HAS_THREADS
@@ -24,7 +25,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
struct __libcpp_timed_backoff_policy {
- _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
+ _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::milliseconds(128))
__libcpp_thread_sleep_for(chrono::milliseconds(8));
else if (__elapsed > chrono::microseconds(64))
@@ -33,7 +34,7 @@ struct __libcpp_timed_backoff_policy {
__libcpp_thread_yield();
else {
} // poll
- return false;
+ return __backoff_results::__continue_poll;
}
};
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 1f19d50e32af7..7c1637356bfe5 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -108,7 +108,8 @@ public:
if (__rel_time == chrono::duration<_Rep, _Period>::zero())
return try_acquire();
auto const __poll_fn = [this]() { return try_acquire(); };
- return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time);
+ return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time) ==
+ __poll_with_backoff_results::__poll_success;
}
_LIBCPP_HIDE_FROM_ABI bool try_acquire() {
auto __old = __a_.load(memory_order_relaxed);
``````````
</details>
https://github.com/llvm/llvm-project/pull/173184
More information about the libcxx-commits
mailing list