File indexing completed on 2025-01-30 09:35:34
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_FIBERS_spinlock_ttas_futex_FUTEX_H
0008 #define BOOST_FIBERS_spinlock_ttas_futex_FUTEX_H
0009
0010 #include <algorithm>
0011 #include <atomic>
0012 #include <cmath>
0013 #include <random>
0014 #include <thread>
0015
0016 #include <boost/fiber/detail/config.hpp>
0017 #include <boost/fiber/detail/cpu_relax.hpp>
0018 #include <boost/fiber/detail/futex.hpp>
0019
0020
0021
0022
0023
0024 namespace boost {
0025 namespace fibers {
0026 namespace detail {
0027
0028 class spinlock_ttas_futex {
0029 private:
0030 template< typename FBSplk >
0031 friend class spinlock_rtm;
0032
0033 std::atomic< std::int32_t > value_{ 0 };
0034
0035 public:
0036 spinlock_ttas_futex() = default;
0037
0038 spinlock_ttas_futex( spinlock_ttas_futex const&) = delete;
0039 spinlock_ttas_futex & operator=( spinlock_ttas_futex const&) = delete;
0040
0041 void lock() noexcept {
0042 static thread_local std::minstd_rand generator{ std::random_device{}() };
0043 std::int32_t collisions = 0, retries = 0, expected = 0;
0044
0045 while ( retries++ < BOOST_FIBERS_RETRY_THRESHOLD) {
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 if ( 0 != ( expected = value_.load( std::memory_order_relaxed) ) ) {
0057 #if !defined(BOOST_FIBERS_SPIN_SINGLE_CORE)
0058 if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > retries) {
0059
0060
0061
0062
0063
0064 cpu_relax();
0065 } else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > retries) {
0066
0067
0068
0069
0070 static constexpr std::chrono::microseconds us0{ 0 };
0071 std::this_thread::sleep_for( us0);
0072 } else {
0073
0074
0075
0076 std::this_thread::yield();
0077 }
0078 #else
0079
0080
0081
0082 std::this_thread::yield();
0083 #endif
0084 } else if ( ! value_.compare_exchange_strong( expected, 1, std::memory_order_acquire) ) {
0085
0086
0087
0088 std::uniform_int_distribution< std::int32_t > distribution{
0089 0, static_cast< std::int32_t >( 1) << (std::min)(collisions, static_cast< std::int32_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
0090 const std::int32_t z = distribution( generator);
0091 ++collisions;
0092 for ( std::int32_t i = 0; i < z; ++i) {
0093
0094
0095 cpu_relax();
0096 }
0097 } else {
0098
0099 return;
0100 }
0101 }
0102
0103
0104 if ( 2 != expected) {
0105 expected = value_.exchange( 2, std::memory_order_acquire);
0106 }
0107 while ( 0 != expected) {
0108 futex_wait( & value_, 2);
0109 expected = value_.exchange( 2, std::memory_order_acquire);
0110 }
0111 }
0112
0113 bool try_lock() noexcept {
0114 std::int32_t expected = 0;
0115 return value_.compare_exchange_strong( expected, 1, std::memory_order_acquire);
0116 }
0117
0118 void unlock() noexcept {
0119 if ( 1 != value_.fetch_sub( 1, std::memory_order_acquire) ) {
0120 value_.store( 0, std::memory_order_release);
0121 futex_wake( & value_);
0122 }
0123 }
0124 };
0125
0126 }}}
0127
0128 #endif