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