From 6dd559967b366229ba401bde26673bc0ba931615 Mon Sep 17 00:00:00 2001 From: khizmax Date: Fri, 22 May 2015 00:47:02 +0300 Subject: [PATCH] Added simplified form of urcu::batch_retire function Added cds::gc::make_retired_ptr function --- cds/gc/details/retired_ptr.h | 8 ++++++++ cds/intrusive/michael_list_rcu.h | 19 ++++++++++--------- cds/urcu/details/base.h | 1 + cds/urcu/details/gp.h | 4 ++-- cds/urcu/details/gpb.h | 22 ++++++++++++++-------- cds/urcu/details/gpi.h | 22 ++++++++++++++-------- cds/urcu/details/gpt.h | 21 ++++++++++++++------- cds/urcu/details/sig_buffered.h | 20 +++++++++++++------- cds/urcu/details/sig_threaded.h | 17 +++++++++++++---- cds/urcu/general_buffered.h | 7 +++++++ cds/urcu/general_instant.h | 7 +++++++ cds/urcu/general_threaded.h | 7 +++++++ cds/urcu/signal_buffered.h | 7 +++++++ cds/urcu/signal_threaded.h | 7 +++++++ 14 files changed, 124 insertions(+), 45 deletions(-) diff --git a/cds/gc/details/retired_ptr.h b/cds/gc/details/retired_ptr.h index bf3d7da8..ae359441 100644 --- a/cds/gc/details/retired_ptr.h +++ b/cds/gc/details/retired_ptr.h @@ -4,6 +4,7 @@ #define CDSLIB_GC_DETAILS_RETIRED_PTR_H #include +#include //@cond namespace cds { namespace gc { @@ -87,6 +88,13 @@ namespace cds { namespace gc { return !(p1 == p2); } } // namespace details + + template + cds::gc::details::retired_ptr make_retired_ptr( T * p ) + { + return cds::gc::details::retired_ptr( p, cds::details::static_functor::call ); + } + }} // namespace cds::gc //@endcond diff --git a/cds/intrusive/michael_list_rcu.h b/cds/intrusive/michael_list_rcu.h index 8a69ae6c..e41d912c 100644 --- a/cds/intrusive/michael_list_rcu.h +++ b/cds/intrusive/michael_list_rcu.h @@ -168,13 +168,14 @@ namespace cds { namespace intrusive { { assert( !gc::is_locked() ); - node_type * p = pDelChain; - if ( p ) { - while ( p ) { - node_type * pNext = p->m_pDelChain; - dispose_node( p ); - p = pNext; - } + node_type * chain = pDelChain; + if ( chain ) { + auto f = [&chain]() -> cds::urcu::retired_ptr { + node_type * p = chain; + chain = p->m_pDelChain; + return cds::urcu::make_retired_ptr( node_traits::to_value_ptr( p )); + }; + gc::batch_retire(std::ref(f)); } } }; @@ -721,7 +722,7 @@ namespace cds { namespace intrusive { template value_type * get( Q const& key ) { - return get_at( const_cast( m_pHead ), key, key_comparator()); + return get_at( m_pHead, key, key_comparator()); } /// Finds \p key and return the item found @@ -737,7 +738,7 @@ namespace cds { namespace intrusive { value_type * get_with( Q const& key, Less pred ) { CDS_UNUSED( pred ); - return get_at( const_cast( m_pHead ), key, cds::opt::details::make_comparator_from_less()); + return get_at( m_pHead, key, cds::opt::details::make_comparator_from_less()); } /// Clears the list using default disposer diff --git a/cds/urcu/details/base.h b/cds/urcu/details/base.h index 76420833..8c6e726d 100644 --- a/cds/urcu/details/base.h +++ b/cds/urcu/details/base.h @@ -255,6 +255,7 @@ namespace cds { ///@anchor cds_urcu_retired_ptr Retired pointer, i.e. pointer that ready for reclamation typedef cds::gc::details::retired_ptr retired_ptr; + using cds::gc::make_retired_ptr; /// Pointer to function to free (destruct and deallocate) retired pointer of specific type typedef cds::gc::details::free_retired_ptr_func free_retired_ptr_func; diff --git a/cds/urcu/details/gp.h b/cds/urcu/details/gp.h index cd30b98b..3f6dc83f 100644 --- a/cds/urcu/details/gp.h +++ b/cds/urcu/details/gp.h @@ -42,7 +42,7 @@ namespace cds { namespace urcu { namespace details { pRec->m_nAccessControl.store( gp_singleton::instance()->global_control_word(atomics::memory_order_relaxed), atomics::memory_order_relaxed ); atomics::atomic_thread_fence( atomics::memory_order_acquire ); - //CDS_COMPILER_RW_BARRIER; + CDS_COMPILER_RW_BARRIER; } else { pRec->m_nAccessControl.fetch_add( 1, atomics::memory_order_relaxed ); @@ -55,7 +55,7 @@ namespace cds { namespace urcu { namespace details { thread_record * pRec = get_thread_record(); assert( pRec != nullptr ); - //CDS_COMPILER_RW_BARRIER; + CDS_COMPILER_RW_BARRIER; pRec->m_nAccessControl.fetch_sub( 1, atomics::memory_order_release ); } diff --git a/cds/urcu/details/gpb.h b/cds/urcu/details/gpb.h index 229aded8..9441f26b 100644 --- a/cds/urcu/details/gpb.h +++ b/cds/urcu/details/gpb.h @@ -111,14 +111,14 @@ namespace cds { namespace urcu { p.free(); } else { - push_buffer( p ); + push_buffer( std::move(p) ); break; } } } // Return: true - synchronize has been called, false - otherwise - bool push_buffer( epoch_retired_ptr& ep ) + bool push_buffer( epoch_retired_ptr&& ep ) { bool bPushed = m_Buffer.push( ep ); if ( !bPushed || m_Buffer.size() >= capacity() ) { @@ -164,10 +164,8 @@ namespace cds { namespace urcu { */ virtual void retire_ptr( retired_ptr& p ) { - if ( p.m_p ) { - epoch_retired_ptr ep( p, m_nCurEpoch.load( atomics::memory_order_relaxed )); - push_buffer( ep ); - } + if ( p.m_p ) + push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_relaxed ))); } /// Retires the pointer chain [\p itFirst, \p itLast) @@ -176,12 +174,20 @@ namespace cds { namespace urcu { { uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); while ( itFirst != itLast ) { - epoch_retired_ptr ep( *itFirst, nEpoch ); + push_buffer( epoch_retired_ptr( *itFirst, nEpoch )); ++itFirst; - push_buffer( ep ); } } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + void batch_retire( Func e ) + { + uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); + for ( retired_ptr p{ e() }; p.m_p; p = e() ) + push_buffer( epoch_retired_ptr( p, nEpoch )); + } + /// Wait to finish a grace period and then clear the buffer void synchronize() { diff --git a/cds/urcu/details/gpi.h b/cds/urcu/details/gpi.h index 1e5426ba..776a09fc 100644 --- a/cds/urcu/details/gpi.h +++ b/cds/urcu/details/gpi.h @@ -111,11 +111,8 @@ namespace cds { namespace urcu { virtual void retire_ptr( retired_ptr& p ) { synchronize(); - if ( p.m_p ) { - // TSan ignores atomic_thread_fence in synchronize() - //CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( p.m_p ); + if ( p.m_p ) p.free(); - } } /// Retires the pointer chain [\p itFirst, \p itLast) @@ -127,15 +124,24 @@ namespace cds { namespace urcu { while ( itFirst != itLast ) { retired_ptr p( *itFirst ); ++itFirst; - if ( p.m_p ) { - // TSan ignores atomic_thread_fence in synchronize() - //CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( p.m_p ); + if ( p.m_p ) p.free(); - } } } } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + void batch_retire( Func e ) + { + retired_ptr p{ e() }; + if ( p.m_p ) { + synchronize(); + for ( ; p.m_p; p = e() ) + p.free(); + } + } + /// Waits to finish a grace period void synchronize() { diff --git a/cds/urcu/details/gpt.h b/cds/urcu/details/gpt.h index 30bb1ebb..1f594148 100644 --- a/cds/urcu/details/gpt.h +++ b/cds/urcu/details/gpt.h @@ -108,7 +108,7 @@ namespace cds { namespace urcu { } // Return: true - synchronize has been called, false - otherwise - bool push_buffer( epoch_retired_ptr& p ) + bool push_buffer( epoch_retired_ptr&& p ) { bool bPushed = m_Buffer.push( p ); if ( !bPushed || m_Buffer.size() >= capacity() ) { @@ -168,10 +168,8 @@ namespace cds { namespace urcu { */ virtual void retire_ptr( retired_ptr& p ) { - if ( p.m_p ) { - epoch_retired_ptr ep( p, m_nCurEpoch.load( atomics::memory_order_acquire ) ); - push_buffer( ep ); - } + if ( p.m_p ) + push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_acquire ))); } /// Retires the pointer chain [\p itFirst, \p itLast) @@ -180,12 +178,21 @@ namespace cds { namespace urcu { { uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); while ( itFirst != itLast ) { - epoch_retired_ptr p( *itFirst, nEpoch ); + push_buffer( epoch_retired_ptr( *itFirst, nEpoch )); ++itFirst; - push_buffer( p ); } } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + void batch_retire( Func e ) + { + uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); + for ( retired_ptr p{ e() }; p.m_p; p = e() ) + push_buffer( epoch_retired_ptr( p, nEpoch )); + } + + /// Waits to finish a grace period and calls disposing thread void synchronize() { diff --git a/cds/urcu/details/sig_buffered.h b/cds/urcu/details/sig_buffered.h index 874092ea..a938b226 100644 --- a/cds/urcu/details/sig_buffered.h +++ b/cds/urcu/details/sig_buffered.h @@ -114,7 +114,7 @@ namespace cds { namespace urcu { } } - bool push_buffer( epoch_retired_ptr& ep ) + bool push_buffer( epoch_retired_ptr&& ep ) { bool bPushed = m_Buffer.push( ep ); if ( !bPushed || m_Buffer.size() >= capacity() ) { @@ -162,10 +162,8 @@ namespace cds { namespace urcu { */ virtual void retire_ptr( retired_ptr& p ) { - if ( p.m_p ) { - epoch_retired_ptr ep( p, m_nCurEpoch.load( atomics::memory_order_relaxed )); - push_buffer( ep ); - } + if ( p.m_p ) + push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_relaxed ))); } /// Retires the pointer chain [\p itFirst, \p itLast) @@ -174,12 +172,20 @@ namespace cds { namespace urcu { { uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); while ( itFirst != itLast ) { - epoch_retired_ptr ep( *itFirst, nEpoch ); + push_buffer( epoch_retired_ptr( *itFirst, nEpoch )); ++itFirst; - push_buffer( ep ); } } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + void batch_retire( Func e ) + { + uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); + for ( retired_ptr p{ e() }; p.m_p; p = e() ) + push_buffer( epoch_retired_ptr( p, nEpoch )); + } + /// Wait to finish a grace period and then clear the buffer void synchronize() { diff --git a/cds/urcu/details/sig_threaded.h b/cds/urcu/details/sig_threaded.h index ffc8b490..4471183f 100644 --- a/cds/urcu/details/sig_threaded.h +++ b/cds/urcu/details/sig_threaded.h @@ -105,7 +105,7 @@ namespace cds { namespace urcu { {} // Return: true - synchronize has been called, false - otherwise - bool push_buffer( epoch_retired_ptr& p ) + bool push_buffer( epoch_retired_ptr&& p ) { bool bPushed = m_Buffer.push( p ); if ( !bPushed || m_Buffer.size() >= capacity() ) { @@ -169,7 +169,7 @@ namespace cds { namespace urcu { { if ( p.m_p ) { epoch_retired_ptr ep( p, m_nCurEpoch.load( atomics::memory_order_acquire ) ); - push_buffer( ep ); + push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_acquire ))); } } @@ -179,12 +179,21 @@ namespace cds { namespace urcu { { uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); while ( itFirst != itLast ) { - epoch_retired_ptr p( *itFirst, nEpoch ); + push_buffer( epoch_retired_ptr( *itFirst, nEpoch ) ); ++itFirst; - push_buffer( p ); } } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + void batch_retire( Func e ) + { + uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed ); + for ( retired_ptr p{ e() }; p.m_p; p = e() ) + push_buffer( epoch_retired_ptr( p, nEpoch )); + } + + /// Waits to finish a grace period and calls disposing thread void synchronize() { diff --git a/cds/urcu/general_buffered.h b/cds/urcu/general_buffered.h index 110f395f..4f92f03f 100644 --- a/cds/urcu/general_buffered.h +++ b/cds/urcu/general_buffered.h @@ -101,6 +101,13 @@ namespace cds { namespace urcu { rcu_implementation::instance()->batch_retire( itFirst, itLast ); } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + static void batch_retire( Func e ) + { + rcu_implementation::instance()->batch_retire( e ); + } + /// Acquires access lock (so called RCU reader-side lock) /** For safety reasons, it is better to use \ref scoped_lock class for locking/unlocking diff --git a/cds/urcu/general_instant.h b/cds/urcu/general_instant.h index 9097faac..c0566dca 100644 --- a/cds/urcu/general_instant.h +++ b/cds/urcu/general_instant.h @@ -96,6 +96,13 @@ namespace cds { namespace urcu { rcu_implementation::instance()->batch_retire( itFirst, itLast ); } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + static void batch_retire( Func e ) + { + rcu_implementation::instance()->batch_retire( e ); + } + /// Acquires access lock (so called RCU reader-side lock) /** For safety reasons, it is better to use \ref scoped_lock class for locking/unlocking diff --git a/cds/urcu/general_threaded.h b/cds/urcu/general_threaded.h index 54189aff..e0a22ebe 100644 --- a/cds/urcu/general_threaded.h +++ b/cds/urcu/general_threaded.h @@ -107,6 +107,13 @@ namespace cds { namespace urcu { rcu_implementation::instance()->batch_retire( itFirst, itLast ); } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + static void batch_retire( Func e ) + { + rcu_implementation::instance()->batch_retire( e ); + } + /// Acquires access lock (so called RCU reader-side lock) /** For safety reasons, it is better to use \ref scoped_lock class for locking/unlocking diff --git a/cds/urcu/signal_buffered.h b/cds/urcu/signal_buffered.h index c9ffe315..b44f563e 100644 --- a/cds/urcu/signal_buffered.h +++ b/cds/urcu/signal_buffered.h @@ -107,6 +107,13 @@ namespace cds { namespace urcu { rcu_implementation::instance()->batch_retire( itFirst, itLast ); } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + static void batch_retire( Func e ) + { + rcu_implementation::instance()->batch_retire( e ); + } + /// Acquires access lock (so called RCU reader-side lock) /** For safety reasons, it is better to use \ref scoped_lock class for locking/unlocking diff --git a/cds/urcu/signal_threaded.h b/cds/urcu/signal_threaded.h index 24d0795c..51e767c7 100644 --- a/cds/urcu/signal_threaded.h +++ b/cds/urcu/signal_threaded.h @@ -114,6 +114,13 @@ namespace cds { namespace urcu { rcu_implementation::instance()->batch_retire( itFirst, itLast ); } + /// Retires the pointer chain until \p Func returns \p nullptr retired pointer + template + static void batch_retire( Func e ) + { + rcu_implementation::instance()->batch_retire( e ); + } + /// Acquires access lock (so called RCU reader-side lock) /** For safety reasons, it is better to use \ref scoped_lock class for locking/unlocking -- 2.34.1