Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:35:34

0001 
0002 //          Copyright Oliver Kowalke 2017.
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //    (See accompanying file LICENSE_1_0.txt or copy at
0005 //          http://www.boost.org/LICENSE_1_0.txt)
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                 // add lock to read-set
0044                 if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_relaxed) ) {
0045                     // lock is free, enter critical section
0046                     return;
0047                 }
0048                 // lock was acquired by another thread
0049                 // explicit abort of transaction with abort argument 'lock not free'
0050                 rtm_abort_lock_not_free();
0051             }
0052             // transaction aborted
0053             if ( rtm_status::none != (status & rtm_status::may_retry) ||
0054                  rtm_status::none != (status & rtm_status::memory_conflict) ) {
0055                 // another logical processor conflicted with a memory address that was
0056                 // part or the read-/write-set
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                 // another logical processor has acquired the lock and
0071                 // abort was not caused by a nested transaction
0072                 // wait till lock becomes free again
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                 // transaction aborted due: 
0092                 //  - internal buffer to track transactional state overflowed
0093                 //  - debug exception or breakpoint exception was hit
0094                 //  - abort during execution of nested transactions (max nesting limit exceeded)
0095                 // -> use fallback path
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         // add lock to read-set
0108         if ( spinlock_status::unlocked != splk_.state_.load( std::memory_order_relaxed) ) {
0109             // lock was acquired by another thread
0110             // explicit abort of transaction with abort argument 'lock not free'
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 // BOOST_FIBERS_SPINLOCK_RTM_H