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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants