- private:
- //@cond
- void take( thread_id tid ) CDS_NOEXCEPT
- {
- m_OwnerId = tid;
- }
-
- void free() CDS_NOEXCEPT
- {
- m_OwnerId = OS::c_NullThreadId;
- }
-
- bool is_taken( thread_id tid ) const CDS_NOEXCEPT
- {
- return m_OwnerId == tid;
- }
-
- bool try_taken_lock( thread_id tid ) CDS_NOEXCEPT
- {
- if ( is_taken( tid )) {
- m_spin.fetch_add( 1, atomics::memory_order_relaxed );
- return true;
- }
- return false;
- }
-
- bool try_acquire() CDS_NOEXCEPT
- {
- integral_type nCurrent = 0;
- return m_spin.compare_exchange_weak( nCurrent, 1, atomics::memory_order_acquire, atomics::memory_order_relaxed );
- }
-
- bool try_acquire( unsigned int nTryCount ) CDS_NOEXCEPT_( noexcept( backoff_strategy()() ))
- {
- backoff_strategy bkoff;
-
- while ( nTryCount-- ) {
- if ( try_acquire() )
- return true;
- bkoff();
- }
- return false;
- }
-
- void acquire() CDS_NOEXCEPT_( noexcept( backoff_strategy()() ))
- {
- // TATAS algorithm
- backoff_strategy bkoff;
- while ( !try_acquire() ) {
- while ( m_spin.load( atomics::memory_order_relaxed ) )
- bkoff();
- }
- }
- //@endcond
-
- public:
- /// Default constructor initializes spin to free (unlocked) state
- ReentrantSpinT() CDS_NOEXCEPT
- : m_spin(0)
- , m_OwnerId( OS::c_NullThreadId )
- {}
-
- /// Dummy copy constructor
- /**
- In theory, spin-lock cannot be copied. However, it is not practical.
- Therefore, we provide dummy copy constructor that do no copy in fact. The ctor
- initializes the spin to free (unlocked) state like default ctor.
- */
- ReentrantSpinT(const ReentrantSpinT<Integral, Backoff>& ) CDS_NOEXCEPT
- : m_spin(0)
- , m_OwnerId( OS::c_NullThreadId )
- {}
-
- /// Construct object for specified state
- ReentrantSpinT(bool bLocked) CDS_NOEXCEPT
- : m_spin(0)
- , m_OwnerId( OS::c_NullThreadId )
- {
- if ( bLocked )
- lock();
- }
-
- /// Checks if the spin is locked
- /**
- The spin is locked if lock count > 0 and the current thread is not an owner of the lock.
- Otherwise (i.e. lock count == 0 or the curren thread owns the spin) the spin is unlocked.
- */
- bool is_locked() const CDS_NOEXCEPT
- {
- return !( m_spin.load( atomics::memory_order_relaxed ) == 0 || is_taken( cds::OS::getCurrentThreadId() ));
- }
-
- /// Try to lock the spin-lock (synonym for \ref try_lock)
- bool try_lock() CDS_NOEXCEPT
- {
- thread_id tid = OS::getCurrentThreadId();
- if ( try_taken_lock( tid ) )
- return true;
- if ( try_acquire()) {
- take( tid );
- return true;
- }
- return false;
- }
-
- /// Try to lock the object
- bool try_lock( unsigned int nTryCount ) CDS_NOEXCEPT_( noexcept( try_acquire( nTryCount ) ) )
- {
- thread_id tid = OS::getCurrentThreadId();
- if ( try_taken_lock( tid ) )
- return true;
- if ( try_acquire( nTryCount )) {
- take( tid );
- return true;
- }
- return false;
- }
-
- /// Lock the object waits if it is busy
- void lock() CDS_NOEXCEPT
- {
- thread_id tid = OS::getCurrentThreadId();
- if ( !try_taken_lock( tid ) ) {
- acquire();
- take( tid );
- }
- }
-
- /// Unlock the spin-lock. Return @p true if the current thread is owner of spin-lock @p false otherwise
- bool unlock() CDS_NOEXCEPT
- {
- if ( is_taken( OS::getCurrentThreadId() ) ) {
- integral_type n = m_spin.load( atomics::memory_order_relaxed );
- if ( n > 1 )
- m_spin.store( n - 1, atomics::memory_order_relaxed );
- else {
- free();
- m_spin.store( 0, atomics::memory_order_release );
- }
- return true;
- }
- return false;
- }
-
- /// Change the owner of locked spin-lock. May be called by thread that is owner of the spin-lock
- bool change_owner( OS::ThreadId newOwnerId ) CDS_NOEXCEPT
- {
- if ( is_taken( OS::getCurrentThreadId() ) ) {
- assert( newOwnerId != OS::c_NullThreadId );
- m_OwnerId = newOwnerId;
- return true;
- }
- return false;
- }
- };
-
- /// Recursive spin-lock based on atomic32u_t
- typedef ReentrantSpinT<uint32_t, backoff::LockDefault> ReentrantSpin32;
-
- /// Recursive spin-lock based on atomic64u_t type
- typedef ReentrantSpinT<uint64_t, backoff::LockDefault> ReentrantSpin64;
-
- /// Recursive spin-lock based on atomic32_t type
- typedef ReentrantSpin32 ReentrantSpin;
-
- /// The best (for the current platform) auto spin-lock
- typedef scoped_lock<Spin> AutoSpin;