From: khizmax Date: Tue, 18 Nov 2014 13:19:28 +0000 (+0300) Subject: reimplement guarded_ptr from scratch X-Git-Tag: v2.0.0~72 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=libcds.git;a=commitdiff_plain;h=0065868663643045eedb960ea842c2dbfdd408ce reimplement guarded_ptr from scratch --- diff --git a/cds/container/impl/ellen_bintree_map.h b/cds/container/impl/ellen_bintree_map.h index 654b21ab..16b32a39 100644 --- a/cds/container/impl/ellen_bintree_map.h +++ b/cds/container/impl/ellen_bintree_map.h @@ -111,7 +111,7 @@ namespace cds { namespace container { public: /// Guarded pointer - typedef cds::gc::guarded_ptr< gc, leaf_node, value_type, details::guarded_ptr_cast_set > guarded_ptr; + typedef typename gc::template guarded_ptr< leaf_node, value_type, details::guarded_ptr_cast_set > guarded_ptr; public: /// Default constructor diff --git a/cds/container/impl/ellen_bintree_set.h b/cds/container/impl/ellen_bintree_set.h index 410a70d2..dcd99e53 100644 --- a/cds/container/impl/ellen_bintree_set.h +++ b/cds/container/impl/ellen_bintree_set.h @@ -146,7 +146,7 @@ namespace cds { namespace container { public: /// Guarded pointer - typedef cds::gc::guarded_ptr< gc, leaf_node, value_type, details::guarded_ptr_cast_set > guarded_ptr; + typedef typename gc::template guarded_ptr< leaf_node, value_type, details::guarded_ptr_cast_set > guarded_ptr; public: /// Default constructor diff --git a/cds/container/impl/skip_list_map.h b/cds/container/impl/skip_list_map.h index c565fae4..c84a73f6 100644 --- a/cds/container/impl/skip_list_map.h +++ b/cds/container/impl/skip_list_map.h @@ -3,7 +3,6 @@ #ifndef __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H #define __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H -#include #include namespace cds { namespace container { diff --git a/cds/container/impl/skip_list_set.h b/cds/container/impl/skip_list_set.h index 59082192..9f699af9 100644 --- a/cds/container/impl/skip_list_set.h +++ b/cds/container/impl/skip_list_set.h @@ -4,7 +4,6 @@ #define __CDS_CONTAINER_IMPL_SKIP_LIST_SET_H #include -#include #include namespace cds { namespace container { diff --git a/cds/gc/details/dhp.h b/cds/gc/details/dhp.h index 795ed421..93580a2e 100644 --- a/cds/gc/details/dhp.h +++ b/cds/gc/details/dhp.h @@ -63,15 +63,13 @@ namespace cds { namespace gc { /// Internal guard representation struct guard_data { - typedef retired_ptr_node * handoff_ptr ; ///< trapped value type - typedef void * guarded_ptr ; ///< type of value guarded + typedef void * guarded_ptr; ///< type of value guarded - atomics::atomic pPost ; ///< pointer guarded + atomics::atomic pPost; ///< pointer guarded + atomics::atomic pGlobalNext; ///< next item of global list of allocated guards + atomics::atomic pNextFree; ///< pointer to the next item in global or thread-local free-list - atomics::atomic pGlobalNext ; ///< next item of global list of allocated guards - atomics::atomic pNextFree ; ///< pointer to the next item in global or thread-local free-list - - guard_data * pThreadNext ; ///< next item of thread's local list of guards + guard_data * pThreadNext; ///< next item of thread's local list of guards guard_data() CDS_NOEXCEPT : pPost( nullptr ) @@ -117,7 +115,7 @@ namespace cds { namespace gc { details::guard_data * pGuard = m_GuardAllocator.New(); // Link guard to the list - // m_GuardList is accumulated list and it cannot support concurrent deletion, + // m_GuardList is an accumulating list and it cannot support concurrent deletion, // so, ABA problem is impossible for it details::guard_data * pHead = m_GuardList.load( atomics::memory_order_acquire ); do { @@ -458,33 +456,42 @@ namespace cds { namespace gc { friend class ThreadGC; protected: details::guard_data * m_pGuard ; ///< Pointer to guard data + public: /// Initialize empty guard. CDS_CONSTEXPR guard() CDS_NOEXCEPT : m_pGuard( nullptr ) {} - /// The object is not copy-constructible + /// Ñopy-ctor is disabled guard( guard const& ) = delete; + /// Move-ctor is disabled + guard( guard&& ) = delete; + /// Object destructor, does nothing ~guard() CDS_NOEXCEPT {} + /// Get current guarded pointer + void * get( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT + { + assert( m_pGuard != nullptr ); + return m_pGuard->pPost.load( order ); + } + /// Guards pointer \p p - void set( void * p ) CDS_NOEXCEPT + void set( void * p, atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT { assert( m_pGuard != nullptr ); - m_pGuard->pPost.store( p, atomics::memory_order_release ); - //CDS_COMPILER_RW_BARRIER; + m_pGuard->pPost.store( p, order ); } /// Clears the guard - void clear() CDS_NOEXCEPT + void clear( atomics::memory_order order = atomics::memory_order_relaxed ) CDS_NOEXCEPT { assert( m_pGuard != nullptr ); - m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed ); - CDS_STRICT_DO( CDS_COMPILER_RW_BARRIER ); + m_pGuard->pPost.store( nullptr, order ); } /// Guards pointer \p p @@ -506,7 +513,6 @@ namespace cds { namespace gc { GCC cannot compile code for template versions of ThreasGC::allocGuard/freeGuard, the compiler produces error: ‘cds::gc::dhp::details::guard_data* cds::gc::dhp::details::guard::m_pGuard’ is protected despite the fact that ThreadGC is declared as friend for guard class. - We should not like to declare m_pGuard member as public one. Therefore, we have to add set_guard/get_guard public functions */ /// Set guard data @@ -526,6 +532,18 @@ namespace cds { namespace gc { { return m_pGuard; } + + details::guard_data * release_guard() CDS_NOEXCEPT + { + details::guard_data * p = m_pGuard; + m_pGuard = nullptr; + return p; + } + + bool is_initialized() const + { + return m_pGuard != nullptr; + } }; } // namespace details @@ -886,27 +904,32 @@ namespace cds { namespace gc { public: /// Initializes guard \p g - void allocGuard( Guard& g ) + void allocGuard( dhp::details::guard& g ) { assert( m_pList != nullptr ); - if ( m_pFree ) { - g.m_pGuard = m_pFree; - m_pFree = m_pFree->pNextFree.load(atomics::memory_order_relaxed); - } - else { - g.m_pGuard = m_gc.allocGuard(); - g.m_pGuard->pThreadNext = m_pList; - m_pList = g.m_pGuard; + if ( !g.m_pGuard ) { + if ( m_pFree ) { + g.m_pGuard = m_pFree; + m_pFree = m_pFree->pNextFree.load( atomics::memory_order_relaxed ); + } + else { + g.m_pGuard = m_gc.allocGuard(); + g.m_pGuard->pThreadNext = m_pList; + m_pList = g.m_pGuard; + } } } /// Frees guard \p g - void freeGuard( Guard& g ) + void freeGuard( dhp::details::guard& g ) { assert( m_pList != nullptr ); - g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed ); - g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed ); - m_pFree = g.m_pGuard; + if ( g.m_pGuard ) { + g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed ); + g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed ); + m_pFree = g.m_pGuard; + g.m_pGuard = nullptr; + } } /// Initializes guard array \p arr diff --git a/cds/gc/guarded_ptr.h b/cds/gc/guarded_ptr.h deleted file mode 100644 index 82925e0f..00000000 --- a/cds/gc/guarded_ptr.h +++ /dev/null @@ -1,247 +0,0 @@ -//$$CDS-header$$ - -#ifndef __CDS_GC_GUARDED_PTR_H -#define __CDS_GC_GUARDED_PTR_H - -#include - -namespace cds { namespace gc { - - /// Guarded pointer - /** - A guarded pointer is a pair of the pointer and GC's guard. - Usually, it is used for returning a pointer to the item from an lock-free container. - The guard prevents the pointer to be early disposed (freed) by GC. - After destructing \p %guarded_ptr object the pointer can be automatically disposed (freed) at any time. - - Template arguments: - - \p GC - a garbage collector type like \p cds::gc::HP and any other from cds::gc namespace - - \p GuardedType - a type which the guard stores - - \p ValueType - a value type - - \p Cast - a functor for converting GuardedType* to ValueType*. Default is \p void (no casting). - - For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed. - In such case the \p %guarded_ptr is: - @code - typedef cds::gc::guarded_ptr< cds::gc::HP, foo > intrusive_guarded_ptr; - @endcode - - For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed. - For example: - @code - struct foo { - int const key; - std::string value; - }; - - struct value_accessor { - std::string* operator()( foo* pFoo ) const - { - return &(pFoo->value); - } - }; - - // Guarded ptr - typedef cds::gc::guarded_ptr< cds::gc::HP, Foo, std::string, value_accessor > nonintrusive_guarded_ptr; - @endcode - - Many set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor. - */ - template - class guarded_ptr - { - //TODO: use moce semantics and explicit operator bool! - public: - typedef GC gc; ///< Garbage collector like cds::gc::HP and any other from cds::gc namespace - typedef GuardedType guarded_type; ///< Guarded type - typedef ValueType value_type; ///< Value type - typedef Cast value_cast; ///< Functor for casting \p guarded_type to \p value_type - - private: - //@cond - typename gc::Guard m_guard; - //@endcond - - public: - /// Creates empty guarded pointer - guarded_ptr() CDS_NOEXCEPT - {} - - //@cond - /// Initializes guarded pointer with \p p - guarded_ptr( guarded_type * p ) CDS_NOEXCEPT - { - m_guard.assign( p ); - } - guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT - {} - //@endcond - - /// Move ctor - guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT - { - m_guard.assign( gp.m_guard.get_native() ); - gp.release(); - } - - /// The guarded pointer is not copy-constructible - guarded_ptr( guarded_ptr const& gp ) = delete; - - /// Clears the guarded pointer - /** - \ref release is called if guarded pointer is not \ref empty - */ - ~guarded_ptr() CDS_NOEXCEPT - { - release(); - } - - /// Move-assignment operator - guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT - { - m_guard.assign( gp.m_guard.get_native() ); - gp.release(); - return *this; - } - - /// The guarded pointer is not copy-assignable - guarded_ptr& operator=(guarded_ptr const& gp) = delete; - - /// Returns a pointer to guarded value - value_type * operator ->() const CDS_NOEXCEPT - { - return value_cast()( m_guard.template get() ); - } - - /// Returns a reference to guarded value - value_type& operator *() CDS_NOEXCEPT - { - assert( !empty()); - return *value_cast()( m_guard.template get() ); - } - - /// Returns const reference to guarded value - value_type const& operator *() const CDS_NOEXCEPT - { - assert( !empty()); - return *value_cast()( m_guard.template get() ); - } - - /// Checks if the guarded pointer is \p nullptr - bool empty() const CDS_NOEXCEPT - { - return m_guard.template get() == nullptr; - } - - /// \p bool operator returns !empty() - explicit operator bool() const CDS_NOEXCEPT - { - return !empty(); - } - - /// Clears guarded pointer - /** - If the guarded pointer has been released, the pointer can be disposed (freed) at any time. - Dereferncing the guarded pointer after \p release() is dangerous. - */ - void release() CDS_NOEXCEPT - { - m_guard.clear(); - } - - //@cond - // For internal use only!!! - typename gc::Guard& guard() CDS_NOEXCEPT - { - return m_guard; - } - //@endcond - }; - - - //@cond - // Intrusive specialization - template - class guarded_ptr< GC, T, T, void > - { - public: - typedef GC gc ; ///< Garbage collector like cds::gc::HP - typedef T guarded_type; ///< Guarded type - typedef T value_type ; ///< Value type - - private: - typename gc::Guard m_guard; - - public: - guarded_ptr() CDS_NOEXCEPT - {} - - guarded_ptr( value_type * p ) CDS_NOEXCEPT - { - m_guard.assign( p ); - } - - guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT - { - m_guard.assign( gp.m_guard.get_native() ); - gp.release(); - } - - guarded_ptr( guarded_ptr const& gp ) = delete; - - ~guarded_ptr() CDS_NOEXCEPT - { - release(); - } - - guarded_ptr& operator=(guarded_ptr&& gp) CDS_NOEXCEPT - { - m_guard.assign( gp.m_guard.get_native() ); - gp.release(); - return *this; - } - - guarded_ptr& operator=(guarded_ptr const& gp) = delete; - - value_type * operator ->() const CDS_NOEXCEPT - { - return m_guard.template get(); - } - - value_type& operator *() CDS_NOEXCEPT - { - assert( !empty()); - return *m_guard.template get(); - } - - value_type const& operator *() const CDS_NOEXCEPT - { - assert( !empty()); - return *m_guard.template get(); - } - - bool empty() const CDS_NOEXCEPT - { - return m_guard.template get() == nullptr; - } - - explicit operator bool() const CDS_NOEXCEPT - { - return !empty(); - } - - void release() CDS_NOEXCEPT - { - m_guard.clear(); - } - - typename gc::Guard& guard() CDS_NOEXCEPT - { - return m_guard; - } - }; - //@endcond - -}} // namespace cds::gc - -#endif // #ifndef __CDS_GC_GUARDED_PTR_H diff --git a/cds/gc/impl/dhp_decl.h b/cds/gc/impl/dhp_decl.h index a7fd2def..a0e4d4af 100644 --- a/cds/gc/impl/dhp_decl.h +++ b/cds/gc/impl/dhp_decl.h @@ -88,6 +88,12 @@ namespace cds { namespace gc { Otherwise it detaches the current thread from Dynamic Hazard Pointer GC. */ ~thread_gc() ; // inline in dhp_impl.h + + public: // for internal use only!!! + //@cond + static void alloc_guard( cds::gc::dhp::details::guard& g ); // inline in dhp_impl.h + static void free_guard( cds::gc::dhp::details::guard& g ); // inline in dhp_impl.h + //@endcond }; @@ -107,6 +113,11 @@ namespace cds { namespace gc { typedef dhp::Guard base_class; //@endcond + public: // for internal use only + //@cond + typedef cds::gc::dhp::details::guard native_guard; + //@endcond + public: // Default ctor Guard(); // inline in dhp_impl.h @@ -364,6 +375,190 @@ namespace cds { namespace gc { } }; + /// Guarded pointer + /** + A guarded pointer is a pair of a pointer and GC's guard. + Usually, it is used for returning a pointer to the item from an lock-free container. + The guard prevents the pointer to be early disposed (freed) by GC. + After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time. + + Template arguments: + - \p GuardedType - a type which the guard stores + - \p ValueType - a value type + - \p Cast - a functor for converting GuardedType* to ValueType*. Default is \p void (no casting). + + For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed. + In such case the \p %guarded_ptr is: + @code + typedef cds::gc::DHP::guarded_ptr< foo > intrusive_guarded_ptr; + @endcode + + For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed. + For example: + @code + struct foo { + int const key; + std::string value; + }; + + struct value_accessor { + std::string* operator()( foo* pFoo ) const + { + return &(pFoo->value); + } + }; + + // Guarded ptr + typedef cds::gc::DHP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr; + @endcode + + You don't need use this class directly. + All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor. + */ + template + class guarded_ptr + { + //@cond + struct trivial_cast { + ValueType * operator()( GuardedType * p ) const + { + return p; + } + }; + //@endcond + + public: + typedef GuardedType guarded_type; ///< Guarded type + typedef ValueType value_type; ///< Value type + + /// Functor for casting \p guarded_type to \p value_type + typedef typename std::conditional< std::is_same::value, trivial_cast, Cast >::type value_cast; + + //@cond + typedef cds::gc::dhp::details::guard native_guard; + //@endcond + + private: + //@cond + native_guard m_guard; + //@endcond + + public: + /// Creates empty guarded pointer + guarded_ptr() CDS_NOEXCEPT + {} + + //@cond + /// Initializes guarded pointer with \p p + guarded_ptr( guarded_type * p ) CDS_NOEXCEPT + { + alloc_guard(); + assert( m_guard.is_initialized() ); + m_guard.set( p ); + } + guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT + {} + //@endcond + + /// Move ctor + guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT + { + m_guard.set_guard( gp.m_guard.release_guard() ); + } + + /// The guarded pointer is not copy-constructible + guarded_ptr( guarded_ptr const& gp ) = delete; + + /// Clears the guarded pointer + /** + \ref release is called if guarded pointer is not \ref empty + */ + ~guarded_ptr() CDS_NOEXCEPT + { + free_guard(); + } + + /// Move-assignment operator + guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT + { + free_guard(); + m_guard.set_guard( gp.m_guard.release_guard() ); + return *this; + } + + /// The guarded pointer is not copy-assignable + guarded_ptr& operator=(guarded_ptr const& gp) = delete; + + /// Returns a pointer to guarded value + value_type * operator ->() const CDS_NOEXCEPT + { + assert( !empty() ); + return value_cast()( reinterpret_cast(m_guard.get())); + } + + /// Returns a reference to guarded value + value_type& operator *() CDS_NOEXCEPT + { + assert( !empty()); + return *value_cast()(reinterpret_cast(m_guard.get())); + } + + /// Returns const reference to guarded value + value_type const& operator *() const CDS_NOEXCEPT + { + assert( !empty() ); + return *value_cast()(reinterpret_cast(m_guard.get())); + } + + /// Checks if the guarded pointer is \p nullptr + bool empty() const CDS_NOEXCEPT + { + return !m_guard.is_initialized() || m_guard.get() == nullptr; + } + + /// \p bool operator returns !empty() + explicit operator bool() const CDS_NOEXCEPT + { + return !empty(); + } + + /// Clears guarded pointer + /** + If the guarded pointer has been released, the pointer can be disposed (freed) at any time. + Dereferncing the guarded pointer after \p release() is dangerous. + */ + void release() CDS_NOEXCEPT + { + if ( m_guard.is_initialized() ) + m_guard.clear(); + } + + //@cond + // For internal use only!!! + native_guard& guard() CDS_NOEXCEPT + { + alloc_guard(); + assert( m_guard.is_initialized() ); + return m_guard; + } + //@endcond + + private: + //@cond + void alloc_guard() + { + if ( !m_guard.is_initialized() ) + thread_gc::alloc_guard( m_guard ); + } + + void free_guard() + { + if ( m_guard.is_initialized() ) + thread_gc::free_guard( m_guard ); + } + //@endcond + }; + public: /// Initializes dhp::GarbageCollector singleton /** diff --git a/cds/gc/impl/dhp_impl.h b/cds/gc/impl/dhp_impl.h index f4535bd5..5028d93c 100644 --- a/cds/gc/impl/dhp_impl.h +++ b/cds/gc/impl/dhp_impl.h @@ -23,6 +23,15 @@ namespace cds { namespace gc { cds::threading::Manager::detachThread(); } + inline /*static*/ void DHP::thread_gc::alloc_guard( cds::gc::dhp::details::guard& g ) + { + return cds::threading::getGC().allocGuard(g); + } + inline /*static*/ void DHP::thread_gc::free_guard( cds::gc::dhp::details::guard& g ) + { + cds::threading::getGC().freeGuard(g); + } + inline DHP::Guard::Guard() : Guard::base_class( cds::threading::getGC() ) {} diff --git a/cds/gc/impl/hp_decl.h b/cds/gc/impl/hp_decl.h index 28c3d5b9..72de7d0e 100644 --- a/cds/gc/impl/hp_decl.h +++ b/cds/gc/impl/hp_decl.h @@ -90,6 +90,12 @@ namespace cds { namespace gc { Otherwise it detaches the current thread from Hazard Pointer GC. */ ~thread_gc() ; // inline in hp_impl.h + + public: // for internal use only!!! + //@cond + static cds::gc::hp::details::hp_guard& alloc_guard(); // inline in hp_impl.h + static void free_guard( cds::gc::hp::details::hp_guard& g ); // inline in hp_impl.h + //@endcond }; /// Hazard Pointer guard @@ -362,6 +368,196 @@ namespace cds { namespace gc { } }; + /// Guarded pointer + /** + A guarded pointer is a pair of a pointer and GC's guard. + Usually, it is used for returning a pointer to the item from an lock-free container. + The guard prevents the pointer to be early disposed (freed) by GC. + After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time. + + Template arguments: + - \p GuardedType - a type which the guard stores + - \p ValueType - a value type + - \p Cast - a functor for converting GuardedType* to ValueType*. Default is \p void (no casting). + + For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed. + In such case the \p %guarded_ptr is: + @code + typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr; + @endcode + + For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed. + For example: + @code + struct foo { + int const key; + std::string value; + }; + + struct value_accessor { + std::string* operator()( foo* pFoo ) const + { + return &(pFoo->value); + } + }; + + // Guarded ptr + typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr; + @endcode + + You don't need use this class directly. + All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor. + */ + template + class guarded_ptr + { + //@cond + struct trivial_cast { + ValueType * operator()( GuardedType * p ) const + { + return p; + } + }; + //@endcond + + public: + typedef GuardedType guarded_type; ///< Guarded type + typedef ValueType value_type; ///< Value type + + /// Functor for casting \p guarded_type to \p value_type + typedef typename std::conditional< std::is_same::value, trivial_cast, Cast >::type value_cast; + + //@cond + typedef cds::gc::hp::details::hp_guard native_guard; + //@endcond + + private: + //@cond + native_guard * m_pGuard; + //@endcond + + public: + /// Creates empty guarded pointer + guarded_ptr() CDS_NOEXCEPT + : m_pGuard(nullptr) + {} + + //@cond + /// Initializes guarded pointer with \p p + guarded_ptr( guarded_type * p ) CDS_NOEXCEPT + { + alloc_guard(); + assert( m_pGuard ); + m_pGuard->set(p); + } + guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT + : m_pGuard( nullptr ) + {} + //@endcond + + /// Move ctor + guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT + : m_pGuard( gp.m_pGuard ) + { + gp.m_pGuard = nullptr; + } + + /// The guarded pointer is not copy-constructible + guarded_ptr( guarded_ptr const& gp ) = delete; + + /// Clears the guarded pointer + /** + \ref release is called if guarded pointer is not \ref empty + */ + ~guarded_ptr() CDS_NOEXCEPT + { + free_guard(); + } + + /// Move-assignment operator + guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT + { + free_guard(); + m_pGuard = gp.m_pGuard; + gp.m_pGuard = nullptr; + return *this; + } + + /// The guarded pointer is not copy-assignable + guarded_ptr& operator=(guarded_ptr const& gp) = delete; + + /// Returns a pointer to guarded value + value_type * operator ->() const CDS_NOEXCEPT + { + assert( !empty() ); + return value_cast()( reinterpret_cast(m_pGuard->get())); + } + + /// Returns a reference to guarded value + value_type& operator *() CDS_NOEXCEPT + { + assert( !empty()); + return *value_cast()(reinterpret_cast(m_pGuard->get())); + } + + /// Returns const reference to guarded value + value_type const& operator *() const CDS_NOEXCEPT + { + assert( !empty() ); + return *value_cast()(reinterpret_cast(m_pGuard->get())); + } + + /// Checks if the guarded pointer is \p nullptr + bool empty() const CDS_NOEXCEPT + { + return !m_pGuard || m_pGuard->get() == nullptr; + } + + /// \p bool operator returns !empty() + explicit operator bool() const CDS_NOEXCEPT + { + return !empty(); + } + + /// Clears guarded pointer + /** + If the guarded pointer has been released, the pointer can be disposed (freed) at any time. + Dereferncing the guarded pointer after \p release() is dangerous. + */ + void release() CDS_NOEXCEPT + { + if ( m_pGuard ) + m_pGuard->clear(); + } + + //@cond + // For internal use only!!! + native_guard& guard() CDS_NOEXCEPT + { + alloc_guard(); + assert( m_pGuard ); + return *m_pGuard; + } + //@endcond + + private: + //@cond + void alloc_guard() + { + if ( !m_pGuard ) + m_pGuard = &thread_gc::alloc_guard(); + } + + void free_guard() + { + if ( m_pGuard ) { + thread_gc::free_guard( *m_pGuard ); + m_pGuard = nullptr; + } + } + //@endcond + }; + public: /// \p scan() type enum class scan_type { diff --git a/cds/gc/impl/hp_impl.h b/cds/gc/impl/hp_impl.h index 2b631897..ac395368 100644 --- a/cds/gc/impl/hp_impl.h +++ b/cds/gc/impl/hp_impl.h @@ -24,6 +24,16 @@ namespace cds { namespace gc { cds::threading::Manager::detachThread(); } + inline /*static*/ cds::gc::hp::details::hp_guard& HP::thread_gc::alloc_guard() + { + return cds::threading::getGC().allocGuard(); + } + + inline /*static*/ void HP::thread_gc::free_guard( cds::gc::hp::details::hp_guard& g ) + { + cds::threading::getGC().freeGuard( g ); + } + inline HP::Guard::Guard() : Guard::base_class( cds::threading::getGC() ) {} diff --git a/cds/intrusive/impl/ellen_bintree.h b/cds/intrusive/impl/ellen_bintree.h index 38df2b5b..0b6ec56e 100644 --- a/cds/intrusive/impl/ellen_bintree.h +++ b/cds/intrusive/impl/ellen_bintree.h @@ -8,7 +8,6 @@ #include #include #include -#include namespace cds { namespace intrusive { @@ -119,7 +118,7 @@ namespace cds { namespace intrusive { typedef typename traits::disposer disposer; ///< leaf node disposer typedef typename traits::back_off back_off; ///< back-off strategy - typedef cds::gc::guarded_ptr< gc, value_type > guarded_ptr; ///< Guarded pointer + typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer protected: //@cond @@ -1327,16 +1326,15 @@ namespace cds { namespace intrusive { } template - bool extract_( typename gc::Guard& guard, Q const& key ) + bool extract_( typename guarded_ptr::native_guard& guard, Q const& key ) { - guarded_ptr gp; return erase_( key, node_compare(), []( Q const&, leaf_node const& ) -> bool { return true; }, - [&guard]( value_type& found ) { guard.assign( &found ); } ); + [&guard]( value_type& found ) { guard.set( &found ); } ); } template - bool extract_with_( typename gc::Guard& guard, Q const& key, Less pred ) + bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less pred ) { typedef ellen_bintree::details::compare< key_type, @@ -1347,10 +1345,10 @@ namespace cds { namespace intrusive { return erase_( key, compare_functor(), []( Q const&, leaf_node const& ) -> bool { return true; }, - [&guard]( value_type& found ) { guard.assign( &found ); } ); + [&guard]( value_type& found ) { guard.set( &found ); } ); } - bool extract_max_( typename gc::Guard& gp ) + bool extract_max_( typename guarded_ptr::native_guard& gp ) { update_desc * pOp = nullptr; search_result res; @@ -1396,11 +1394,11 @@ namespace cds { namespace intrusive { --m_ItemCounter; m_Stat.onExtractMaxSuccess(); - gp.assign( node_traits::to_value_ptr( res.pLeaf )); + gp.set( node_traits::to_value_ptr( res.pLeaf )); return true; } - bool extract_min_( typename gc::Guard& gp ) + bool extract_min_( typename guarded_ptr::native_guard& gp ) { update_desc * pOp = nullptr; search_result res; @@ -1446,7 +1444,7 @@ namespace cds { namespace intrusive { --m_ItemCounter; m_Stat.onExtractMinSuccess(); - gp.assign( node_traits::to_value_ptr( res.pLeaf )); + gp.set( node_traits::to_value_ptr( res.pLeaf )); return true; } @@ -1490,15 +1488,15 @@ namespace cds { namespace intrusive { } template - bool get_( typename gc::Guard& guard, Q const& val ) const + bool get_( typename guarded_ptr::native_guard& guard, Q const& val ) const { - return find_( val, [&guard]( value_type& found, Q const& ) { guard.assign( &found ); } ); + return find_( val, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } ); } template - bool get_with_( typename gc::Guard& guard, Q const& val, Less pred ) const + bool get_with_( typename guarded_ptr::native_guard& guard, Q const& val, Less pred ) const { - return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.assign( &found ); } ); + return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } ); } //@endcond diff --git a/cds/intrusive/impl/lazy_list.h b/cds/intrusive/impl/lazy_list.h index 274f77ea..eda3714e 100644 --- a/cds/intrusive/impl/lazy_list.h +++ b/cds/intrusive/impl/lazy_list.h @@ -5,7 +5,6 @@ #include // unique_lock #include -#include namespace cds { namespace intrusive { diff --git a/cds/intrusive/impl/michael_list.h b/cds/intrusive/impl/michael_list.h index 757bc7a3..8c2eadf2 100644 --- a/cds/intrusive/impl/michael_list.h +++ b/cds/intrusive/impl/michael_list.h @@ -4,7 +4,6 @@ #define __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H #include -#include #include namespace cds { namespace intrusive { diff --git a/cds/intrusive/impl/skip_list.h b/cds/intrusive/impl/skip_list.h index 0255a744..86c505e2 100644 --- a/cds/intrusive/impl/skip_list.h +++ b/cds/intrusive/impl/skip_list.h @@ -9,7 +9,6 @@ #include #include #include -#include namespace cds { namespace intrusive { diff --git a/projects/Win/vc12/cds.vcxproj b/projects/Win/vc12/cds.vcxproj index df4d8fb3..2f974617 100644 --- a/projects/Win/vc12/cds.vcxproj +++ b/projects/Win/vc12/cds.vcxproj @@ -739,7 +739,6 @@ - diff --git a/projects/Win/vc12/cds.vcxproj.filters b/projects/Win/vc12/cds.vcxproj.filters index 0cbfe9df..0fcc08e7 100644 --- a/projects/Win/vc12/cds.vcxproj.filters +++ b/projects/Win/vc12/cds.vcxproj.filters @@ -215,9 +215,6 @@ Header Files\cds\details - - Header Files\cds\gc - Header Files\cds\details