Skip to content

Conversation

@huixie90
Copy link
Member

No description provided.

@huixie90 huixie90 requested a review from a team as a code owner December 21, 2025 10:55
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Dec 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 21, 2025

@llvm/pr-subscribers-libcxx

Author: Hui (huixie90)

Changes

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 --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); 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

2 participants