diff options
Diffstat (limited to 'boost/fiber/detail/spinlock_rtm.hpp')
-rw-r--r-- | boost/fiber/detail/spinlock_rtm.hpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/boost/fiber/detail/spinlock_rtm.hpp b/boost/fiber/detail/spinlock_rtm.hpp new file mode 100644 index 0000000000..5cc4a5e9af --- /dev/null +++ b/boost/fiber/detail/spinlock_rtm.hpp @@ -0,0 +1,126 @@ + +// Copyright Oliver Kowalke 2017. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_FIBERS_SPINLOCK_RTM_H +#define BOOST_FIBERS_SPINLOCK_RTM_H + +#include <atomic> +#include <chrono> +#include <cmath> +#include <random> +#include <thread> + +#include <boost/fiber/detail/config.hpp> +#include <boost/fiber/detail/cpu_relax.hpp> +#include <boost/fiber/detail/rtm.hpp> +#include <boost/fiber/detail/spinlock_status.hpp> + +namespace boost { +namespace fibers { +namespace detail { + +template< typename FBSplk > +class spinlock_rtm { +private: + FBSplk splk_{}; + +public: + spinlock_rtm() = default; + + spinlock_rtm( spinlock_rtm const&) = delete; + spinlock_rtm & operator=( spinlock_rtm const&) = delete; + + void lock() noexcept { + static thread_local std::minstd_rand generator{ std::random_device{}() }; + std::size_t collisions = 0 ; + for ( std::size_t retries = 0; retries < BOOST_FIBERS_RETRY_THRESHOLD; ++retries) { + std::uint32_t status; + if ( rtm_status::success == ( status = rtm_begin() ) ) { + // add lock to read-set + if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_relaxed) ) { + // lock is free, enter critical section + return; + } + // lock was acquired by another thread + // explicit abort of transaction with abort argument 'lock not free' + rtm_abort_lock_not_free(); + } + // transaction aborted + if ( rtm_status::none != (status & rtm_status::may_retry) || + rtm_status::none != (status & rtm_status::memory_conflict) ) { + // another logical processor conflicted with a memory address that was + // part or the read-/write-set + if ( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD > collisions) { + std::uniform_int_distribution< std::size_t > distribution{ + 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) }; + const std::size_t z = distribution( generator); + ++collisions; + for ( std::size_t i = 0; i < z; ++i) { + cpu_relax(); + } + } else { + std::this_thread::yield(); + } + } else if ( rtm_status::none != (status & rtm_status::explicit_abort) && + rtm_status::none == (status & rtm_status::nested_abort) ) { + // another logical processor has acquired the lock and + // abort was not caused by a nested transaction + // wait till lock becomes free again + std::size_t count = 0; + while ( spinlock_status::locked == splk_.state_.load( std::memory_order_relaxed) ) { + if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > count) { + ++count; + cpu_relax(); + } else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > count) { + ++count; + static constexpr std::chrono::microseconds us0{ 0 }; + std::this_thread::sleep_for( us0); +#if 0 + using namespace std::chrono_literals; + std::this_thread::sleep_for( 0ms); +#endif + } else { + std::this_thread::yield(); + } + } + } else { + // transaction aborted due: + // - internal buffer to track transactional state overflowed + // - debug exception or breakpoint exception was hit + // - abort during execution of nested transactions (max nesting limit exceeded) + // -> use fallback path + break; + } + } + splk_.lock(); + } + + bool try_lock() noexcept { + if ( rtm_status::success != rtm_begin() ) { + return false; + } + + // add lock to read-set + if ( spinlock_status::unlocked != splk_.state_.load( std::memory_order_relaxed) ) { + // lock was acquired by another thread + // explicit abort of transaction with abort argument 'lock not free' + rtm_abort_lock_not_free(); + } + return true; + } + + void unlock() noexcept { + if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_acquire) ) { + rtm_end(); + } else { + splk_.unlock(); + } + } +}; + +}}} + +#endif // BOOST_FIBERS_SPINLOCK_RTM_H |