#ifndef __CDS_GC_DHP_H
#define __CDS_GC_DHP_H
-#include <cds/gc/dhp/dhp_decl.h>
-#include <cds/gc/dhp/dhp_impl.h>
+#include <cds/gc/impl/dhp_decl.h>
+#include <cds/gc/impl/dhp_impl.h>
#include <cds/details/lib.h>
#endif // #ifndef __CDS_GC_DHP_H
+++ /dev/null
-//$$CDS-header$$
-
-#ifndef __CDS_GC_DHP_DHP_DECL_H
-#define __CDS_GC_DHP_DHP_DECL_H
-
-#include <cds/gc/details/dhp.h>
-#include <cds/details/marked_ptr.h>
-#include <cds/details/static_functor.h>
-
-namespace cds { namespace gc {
-
- /// Dynamic Hazard Pointer garbage collector
- /** @ingroup cds_garbage_collector
- @headerfile cds/gc/dhp.h
- This class is a wrapper for Dynamic Hazard Pointer garbage collector internal implementation.
-
- See \ref cds_how_to_use "How to use" section for details of garbage collector applying.
- */
- class DHP
- {
- public:
- /// Native guarded pointer type
- typedef void * guarded_pointer;
-
- /// Atomic reference
- /**
- @headerfile cds/gc/dhp.h
- */
- template <typename T> using atomic_ref = atomics::atomic<T *>;
-
- /// Atomic type
- /**
- @headerfile cds/gc/dhp.h
- */
- template <typename T> using atomic_type = atomics::atomic<T>;
-
- /// Atomic marked pointer
- /**
- @headerfile cds/gc/dhp.h
- */
- template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
-
- /// Thread GC implementation for internal usage
- typedef dhp::ThreadGC thread_gc_impl;
-
- /// Wrapper for dhp::ThreadGC class
- /**
- @headerfile cds/gc/dhp.h
- This class performs automatically attaching/detaching Dynamic Hazard Pointer GC
- for the current thread.
- */
- class thread_gc: public thread_gc_impl
- {
- //@cond
- bool m_bPersistent;
- //@endcond
- public:
- /// Constructor
- /**
- The constructor attaches the current thread to the Dynamic Hazard Pointer GC
- if it is not yet attached.
- The \p bPersistent parameter specifies attachment persistence:
- - \p true - the class destructor will not detach the thread from Dynamic Hazard Pointer GC.
- - \p false (default) - the class destructor will detach the thread from Dynamic Hazard Pointer GC.
- */
- thread_gc(
- bool bPersistent = false
- ) ; // inline in dhp_impl.h
-
- /// Destructor
- /**
- If the object has been created in persistent mode, the destructor does nothing.
- Otherwise it detaches the current thread from Dynamic Hazard Pointer GC.
- */
- ~thread_gc() ; // inline in dhp_impl.h
- };
-
-
- /// Dynamic Hazard Pointer guard
- /**
- @headerfile cds/gc/dhp.h
- This class is a wrapper for dhp::Guard.
- */
- class Guard: public dhp::Guard
- {
- //@cond
- typedef dhp::Guard base_class;
- //@endcond
-
- public:
- //@cond
- Guard() ; // inline in dhp_impl.h
- //@endcond
-
- /// Protects a pointer of type <tt> atomic<T*> </tt>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store it
- to the HP slot repeatedly until the guard's value equals \p toGuard
- */
- template <typename T>
- T protect( atomics::atomic<T> const& toGuard )
- {
- T pCur = toGuard.load(atomics::memory_order_relaxed);
- T pRet;
- do {
- pRet = assign( pCur );
- pCur = toGuard.load(atomics::memory_order_acquire);
- } while ( pRet != pCur );
- return pCur;
- }
-
- /// Protects a converted pointer of type <tt> atomic<T*> </tt>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store result of \p f functor
- to the HP slot repeatedly until the guard's value equals \p toGuard.
-
- The function is useful for intrusive containers when \p toGuard is a node pointer
- that should be converted to a pointer to the value type before guarding.
- The parameter \p f of type Func is a functor that makes this conversion:
- \code
- struct functor {
- value_type * operator()( T * p );
- };
- \endcode
- Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
- */
- template <typename T, class Func>
- T protect( atomics::atomic<T> const& toGuard, Func f )
- {
- T pCur = toGuard.load(atomics::memory_order_relaxed);
- T pRet;
- do {
- pRet = pCur;
- assign( f( pCur ) );
- pCur = toGuard.load(atomics::memory_order_acquire);
- } while ( pRet != pCur );
- return pCur;
- }
-
- /// Store \p p to the guard
- /**
- The function equals to a simple assignment, no loop is performed.
- Can be used for a pointer that cannot be changed concurrently.
- */
- template <typename T>
- T * assign( T * p )
- {
- return base_class::operator =(p);
- }
-
- //@cond
- std::nullptr_t assign( std::nullptr_t )
- {
- return base_class::operator =(nullptr);
- }
- //@endcond
-
- /// Store marked pointer \p p to the guard
- /**
- The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
- Can be used for a marked pointer that cannot be changed concurrently.
- */
- template <typename T, int BITMASK>
- T * assign( cds::details::marked_ptr<T, BITMASK> p )
- {
- return base_class::operator =( p.ptr() );
- }
-
- /// Copy from \p src guard to \p this guard
- void copy( Guard const& src )
- {
- assign( src.get_native() );
- }
-
- /// Clear value of the guard
- void clear()
- {
- base_class::clear();
- }
-
- /// Get the value currently protected (relaxed read)
- template <typename T>
- T * get() const
- {
- return reinterpret_cast<T *>( get_native() );
- }
-
- /// Get native guarded pointer stored
- guarded_pointer get_native() const
- {
- return base_class::get_guard()->pPost.load(atomics::memory_order_relaxed);
- }
-
- };
-
- /// Array of Dynamic Hazard Pointer guards
- /**
- @headerfile cds/gc/dhp.h
- This class is a wrapper for dhp::GuardArray template.
- Template parameter \p Count defines the size of DHP array.
- */
- template <size_t Count>
- class GuardArray: public dhp::GuardArray<Count>
- {
- //@cond
- typedef dhp::GuardArray<Count> base_class;
- //@endcond
- public:
- /// Rebind array for other size \p COUNT2
- template <size_t OtherCount>
- struct rebind {
- typedef GuardArray<OtherCount> other ; ///< rebinding result
- };
-
- public:
- //@cond
- GuardArray() ; // inline in dhp_impl.h
- //@endcond
-
- /// Protects a pointer of type \p atomic<T*>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store it
- to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
- */
- template <typename T>
- T protect(size_t nIndex, atomics::atomic<T> const& toGuard )
- {
- T pRet;
- do {
- pRet = assign( nIndex, toGuard.load(atomics::memory_order_relaxed) );
- } while ( pRet != toGuard.load(atomics::memory_order_acquire));
-
- return pRet;
- }
-
- /// Protects a pointer of type \p atomic<T*>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store it
- to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
-
- The function is useful for intrusive containers when \p toGuard is a node pointer
- that should be converted to a pointer to the value type before guarding.
- The parameter \p f of type Func is a functor that makes this conversion:
- \code
- struct functor {
- value_type * operator()( T * p );
- };
- \endcode
- Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
- */
- template <typename T, class Func>
- T protect(size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
- {
- T pRet;
- do {
- assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_relaxed) ));
- } while ( pRet != toGuard.load(atomics::memory_order_acquire));
-
- return pRet;
- }
-
- /// Store \p to the slot \p nIndex
- /**
- The function equals to a simple assignment, no loop is performed.
- */
- template <typename T>
- T * assign( size_t nIndex, T * p )
- {
- base_class::set(nIndex, p);
- return p;
- }
-
- /// Store marked pointer \p p to the guard
- /**
- The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
- Can be used for a marked pointer that cannot be changed concurrently.
- */
- template <typename T, int Bitmask>
- T * assign( size_t nIndex, cds::details::marked_ptr<T, Bitmask> p )
- {
- return assign( nIndex, p.ptr() );
- }
-
- /// Copy guarded value from \p src guard to slot at index \p nIndex
- void copy( size_t nIndex, Guard const& src )
- {
- assign( nIndex, src.get_native() );
- }
-
- /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
- void copy( size_t nDestIndex, size_t nSrcIndex )
- {
- assign( nDestIndex, get_native( nSrcIndex ));
- }
-
- /// Clear value of the slot \p nIndex
- void clear( size_t nIndex)
- {
- base_class::clear( nIndex );
- }
-
- /// Get current value of slot \p nIndex
- template <typename T>
- T * get( size_t nIndex) const
- {
- return reinterpret_cast<T *>( get_native( nIndex ) );
- }
-
- /// Get native guarded pointer stored
- guarded_pointer get_native( size_t nIndex ) const
- {
- return base_class::operator[](nIndex).get_guard()->pPost.load(atomics::memory_order_relaxed);
- }
-
- /// Capacity of the guard array
- static CDS_CONSTEXPR size_t capacity()
- {
- return Count;
- }
- };
-
- public:
- /// Initializes dhp::GarbageCollector singleton
- /**
- The constructor calls GarbageCollector::Construct with passed parameters.
- See dhp::GarbageCollector::Construct for explanation of parameters meaning.
- */
- DHP(
- size_t nLiberateThreshold = 1024
- , size_t nInitialThreadGuardCount = 8
- )
- {
- dhp::GarbageCollector::Construct(
- nLiberateThreshold,
- nInitialThreadGuardCount
- );
- }
-
- /// Terminates dhp::GarbageCollector singleton
- /**
- The destructor calls \code dhp::GarbageCollector::Destruct() \endcode
- */
- ~DHP()
- {
- dhp::GarbageCollector::Destruct();
- }
-
- /// Checks if count of hazard pointer is no less than \p nCountNeeded
- /**
- The function always returns \p true since the guard count is unlimited for
- DHP garbage collector.
- */
- static bool check_available_guards( size_t nCountNeeded, bool /*bRaiseException*/ = true )
- {
- CDS_UNUSED( nCountNeeded );
- return true;
- }
-
- /// Retire pointer \p p with function \p pFunc
- /**
- The function places pointer \p p to array of pointers ready for removing.
- (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
- Deleting the pointer is the function \p pFunc call.
- */
- template <typename T>
- static void retire( T * p, void (* pFunc)(T *) )
- {
- dhp::GarbageCollector::instance().retirePtr( p, pFunc );
- }
-
- /// Retire pointer \p p with functor of type \p Disposer
- /**
- The function places pointer \p p to array of pointers ready for removing.
- (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
-
- See gc::HP::retire for \p Disposer requirements.
- */
- template <class Disposer, typename T>
- static void retire( T * p )
- {
- retire( p, cds::details::static_functor<Disposer, T>::call );
- }
-
- /// Checks if Dynamic Hazard Pointer GC is constructed and may be used
- static bool isUsed()
- {
- return dhp::GarbageCollector::isUsed();
- }
-
- /// Forced GC cycle call for current thread
- /**
- Usually, this function should not be called directly.
- */
- static void scan() ; // inline in dhp_impl.h
-
- /// Synonym for \ref scan()
- static void force_dispose()
- {
- scan();
- }
- };
-
-}} // namespace cds::gc
-
-#endif // #ifndef __CDS_GC_DHP_DHP_DECL_H
+++ /dev/null
-//$$CDS-header$$
-
-#ifndef __CDS_GC_DHP_DHP_IMPL_H
-#define __CDS_GC_DHP_DHP_IMPL_H
-
-#include <cds/threading/model.h>
-
-//@cond
-namespace cds { namespace gc {
-
- inline DHP::thread_gc::thread_gc(
- bool bPersistent
- )
- : m_bPersistent( bPersistent )
- {
- if ( !cds::threading::Manager::isThreadAttached() )
- cds::threading::Manager::attachThread();
- }
-
- inline DHP::thread_gc::~thread_gc()
- {
- if ( !m_bPersistent )
- cds::threading::Manager::detachThread();
- }
-
- inline DHP::Guard::Guard()
- : Guard::base_class( cds::threading::getGC<DHP>() )
- {}
-
- template <size_t COUNT>
- inline DHP::GuardArray<COUNT>::GuardArray()
- : GuardArray::base_class( cds::threading::getGC<DHP>() )
- {}
-
- inline void DHP::scan()
- {
- cds::threading::getGC<DHP>().scan();
- }
-
-}} // namespace cds::gc
-//@endcond
-
-#endif // #ifndef __CDS_GC_DHP_DHP_IMPL_H
#ifndef __CDS_GC_HP_H
#define __CDS_GC_HP_H
-#include <cds/gc/hp/hp_decl.h>
-#include <cds/gc/hp/hp_impl.h>
+#include <cds/gc/impl/hp_decl.h>
+#include <cds/gc/impl/hp_impl.h>
#include <cds/details/lib.h>
#endif // #ifndef __CDS_GC_HP_H
+++ /dev/null
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HP_HP_DECL_H
-#define __CDS_GC_HP_HP_DECL_H
-
-#include <stdexcept> // overflow_error
-#include <cds/gc/details/hp.h>
-#include <cds/details/marked_ptr.h>
-
-namespace cds { namespace gc {
- /// @defgroup cds_garbage_collector Garbage collectors
-
- /// Hazard Pointer garbage collector
- /** @ingroup cds_garbage_collector
- @headerfile cds/gc/hp.h
-
- This class realizes a wrapper for Hazard Pointer garbage collector internal implementation.
-
- Sources:
- - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
- - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
- - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
-
- See \ref cds_how_to_use "How to use" section for details of garbage collector applying.
- */
- class HP
- {
- public:
- /// Native guarded pointer type
- typedef gc::hp::hazard_pointer guarded_pointer;
-
- /// Atomic reference
- /**
- @headerfile cds/gc/hp.h
- */
- template <typename T> using atomic_ref = atomics::atomic<T *>;
-
- /// Atomic marked pointer
- /**
- @headerfile cds/gc/hp.h
- */
- template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
-
- /// Atomic type
- /**
- @headerfile cds/gc/hp.h
- */
- template <typename T> using atomic_type = atomics::atomic<T>;
-
- /// Thread GC implementation for internal usage
- typedef hp::ThreadGC thread_gc_impl;
-
- /// Wrapper for hp::ThreadGC class
- /**
- @headerfile cds/gc/hp.h
- This class performs automatically attaching/detaching Hazard Pointer GC
- for the current thread.
- */
- class thread_gc: public thread_gc_impl
- {
- //@cond
- bool m_bPersistent;
- //@endcond
- public:
-
- /// Constructor
- /**
- The constructor attaches the current thread to the Hazard Pointer GC
- if it is not yet attached.
- The \p bPersistent parameter specifies attachment persistence:
- - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
- - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
- */
- thread_gc(
- bool bPersistent = false
- ) ; //inline in hp_impl.h
-
- /// Destructor
- /**
- If the object has been created in persistent mode, the destructor does nothing.
- Otherwise it detaches the current thread from Hazard Pointer GC.
- */
- ~thread_gc() ; // inline in hp_impl.h
- };
-
- /// Hazard Pointer guard
- /**
- @headerfile cds/gc/hp.h
- This class is a wrapper for \p hp::guard.
- */
- class Guard : public hp::guard
- {
- //@cond
- typedef hp::guard base_class;
- //@endcond
-
- public:
- //@cond
- Guard() ; // inline in hp_impl.h
- //@endcond
-
- /// Protects a pointer of type \p atomic<T*>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store it
- to the HP slot repeatedly until the guard's value equals \p toGuard
- */
- template <typename T>
- T protect( atomics::atomic<T> const& toGuard )
- {
- T pCur = toGuard.load(atomics::memory_order_relaxed);
- T pRet;
- do {
- pRet = assign( pCur );
- pCur = toGuard.load(atomics::memory_order_acquire);
- } while ( pRet != pCur );
- return pCur;
- }
-
- /// Protects a converted pointer of type \p atomic<T*>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store result of \p f functor
- to the HP slot repeatedly until the guard's value equals \p toGuard.
-
- The function is useful for intrusive containers when \p toGuard is a node pointer
- that should be converted to a pointer to the value type before protecting.
- The parameter \p f of type Func is a functor that makes this conversion:
- \code
- struct functor {
- value_type * operator()( T * p );
- };
- \endcode
- Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
- */
- template <typename T, class Func>
- T protect( atomics::atomic<T> const& toGuard, Func f )
- {
- T pCur = toGuard.load(atomics::memory_order_relaxed);
- T pRet;
- do {
- pRet = pCur;
- assign( f( pCur ) );
- pCur = toGuard.load(atomics::memory_order_acquire);
- } while ( pRet != pCur );
- return pCur;
- }
-
- /// Store \p p to the guard
- /**
- The function equals to a simple assignment the value \p p to guard, no loop is performed.
- Can be used for a pointer that cannot be changed concurrently
- */
- template <typename T>
- T * assign( T * p )
- {
- return base_class::operator =(p);
- }
-
- //@cond
- std::nullptr_t assign( std::nullptr_t )
- {
- return base_class::operator =(nullptr);
- }
- //@endcond
-
- /// Copy from \p src guard to \p this guard
- void copy( Guard const& src )
- {
- assign( src.get_native() );
- }
-
- /// Store marked pointer \p p to the guard
- /**
- The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
- Can be used for a marked pointer that cannot be changed concurrently.
- */
- template <typename T, int BITMASK>
- T * assign( cds::details::marked_ptr<T, BITMASK> p )
- {
- return base_class::operator =( p.ptr() );
- }
-
- /// Clear value of the guard
- void clear()
- {
- assign( nullptr );
- }
-
- /// Get the value currently protected
- template <typename T>
- T * get() const
- {
- return reinterpret_cast<T *>( get_native() );
- }
-
- /// Get native hazard pointer stored
- guarded_pointer get_native() const
- {
- return base_class::get();
- }
- };
-
- /// Array of Hazard Pointer guards
- /**
- @headerfile cds/gc/hp.h
- This class is a wrapper for \p hp::array template.
- Template parameter \p Count defines the size of HP array.
- */
- template <size_t Count>
- class GuardArray : public hp::array<Count>
- {
- //@cond
- typedef hp::array<Count> base_class;
- //@endcond
- public:
- /// Rebind array for other size \p Count2
- template <size_t Count2>
- struct rebind {
- typedef GuardArray<Count2> other ; ///< rebinding result
- };
-
- public:
- //@cond
- GuardArray() ; // inline in hp_impl.h
- //@endcond
- /// Protects a pointer of type \p atomic<T*>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store it
- to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
- */
- template <typename T>
- T protect(size_t nIndex, atomics::atomic<T> const& toGuard )
- {
- T pRet;
- do {
- pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
- } while ( pRet != toGuard.load(atomics::memory_order_relaxed));
-
- return pRet;
- }
-
- /// Protects a pointer of type \p atomic<T*>
- /**
- Return the value of \p toGuard
-
- The function tries to load \p toGuard and to store it
- to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
-
- The function is useful for intrusive containers when \p toGuard is a node pointer
- that should be converted to a pointer to the value type before guarding.
- The parameter \p f of type Func is a functor that makes this conversion:
- \code
- struct functor {
- value_type * operator()( T * p );
- };
- \endcode
- Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
- */
- template <typename T, class Func>
- T protect(size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
- {
- T pRet;
- do {
- assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
- } while ( pRet != toGuard.load(atomics::memory_order_relaxed));
-
- return pRet;
- }
-
- /// Store \p to the slot \p nIndex
- /**
- The function equals to a simple assignment, no loop is performed.
- */
- template <typename T>
- T * assign( size_t nIndex, T * p )
- {
- base_class::set(nIndex, p);
- return p;
- }
-
- /// Store marked pointer \p p to the guard
- /**
- The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
- Can be used for a marked pointer that cannot be changed concurrently.
- */
- template <typename T, int BITMASK>
- T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
- {
- return assign( nIndex, p.ptr() );
- }
-
- /// Copy guarded value from \p src guard to slot at index \p nIndex
- void copy( size_t nIndex, Guard const& src )
- {
- assign( nIndex, src.get_native() );
- }
-
- /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
- void copy( size_t nDestIndex, size_t nSrcIndex )
- {
- assign( nDestIndex, get_native( nSrcIndex ));
- }
-
- /// Clear value of the slot \p nIndex
- void clear( size_t nIndex)
- {
- base_class::clear( nIndex );
- }
-
- /// Get current value of slot \p nIndex
- template <typename T>
- T * get( size_t nIndex) const
- {
- return reinterpret_cast<T *>( get_native( nIndex ) );
- }
-
- /// Get native hazard pointer stored
- guarded_pointer get_native( size_t nIndex ) const
- {
- return base_class::operator[](nIndex).get();
- }
-
- /// Capacity of the guard array
- static CDS_CONSTEXPR size_t capacity()
- {
- return Count;
- }
- };
-
- public:
- /// Initializes hp::GarbageCollector singleton
- /**
- The constructor initializes GC singleton with passed parameters.
- If GC instance is not exist then the function creates the instance.
- Otherwise it does nothing.
-
- The Michael's HP reclamation schema depends of three parameters:
- - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
- the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
- uses maximum of the hazard pointer count for CDS library.
- - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
- - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
- <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
- */
- HP(
- size_t nHazardPtrCount = 0, ///< Hazard pointer count per thread
- size_t nMaxThreadCount = 0, ///< Max count of simultaneous working thread in your application
- size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
- hp::scan_type nScanType = hp::inplace ///< Scan type (see \ref hp::scan_type enum)
- )
- {
- hp::GarbageCollector::Construct(
- nHazardPtrCount,
- nMaxThreadCount,
- nMaxRetiredPtrCount,
- nScanType
- );
- }
-
- /// Terminates GC singleton
- /**
- The destructor calls \code hp::GarbageCollector::Destruct( true ) \endcode
- */
- ~HP()
- {
- hp::GarbageCollector::Destruct( true );
- }
-
- /// Checks if count of hazard pointer is no less than \p nCountNeeded
- /**
- If \p bRaiseException is \p true (that is the default), the function raises
- an \p std::overflow_error exception "Too few hazard pointers"
- if \p nCountNeeded is more than the count of hazard pointer per thread.
- */
- static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
- {
- if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
- if ( bRaiseException )
- throw std::overflow_error( "Too few hazard pointers" );
- return false;
- }
- return true;
- }
-
- /// Returns max Hazard Pointer count
- size_t max_hazard_count() const
- {
- return hp::GarbageCollector::instance().getHazardPointerCount();
- }
-
- /// Returns max count of thread
- size_t max_thread_count() const
- {
- return hp::GarbageCollector::instance().getMaxThreadCount();
- }
-
- /// Returns capacity of retired pointer array
- size_t retired_array_capacity() const
- {
- return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
- }
-
- /// Retire pointer \p p with function \p pFunc
- /**
- The function places pointer \p p to array of pointers ready for removing.
- (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
- Deleting the pointer is the function \p pFunc call.
- */
- template <typename T>
- static void retire( T * p, void (* pFunc)(T *) ) ; // inline in hp_impl.h
-
- /// Retire pointer \p p with functor of type \p Disposer
- /**
- The function places pointer \p p to array of pointers ready for removing.
- (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
-
- Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
- \code
- template <typename T>
- struct disposer {
- void operator()( T * p ) ; // disposing operator
- };
- \endcode
- Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
- - it should be stateless functor
- - it should be default-constructible
- - the result of functor call with argument \p p should not depend on where the functor will be called.
-
- \par Examples:
- Operator \p delete functor:
- \code
- template <typename T>
- struct disposer {
- void operator ()( T * p ) {
- delete p;
- }
- };
-
- // How to call GC::retire method
- int * p = new int;
-
- // ... use p in lock-free manner
-
- cds::gc::HP::retire<disposer>( p ) ; // place p to retired pointer array of HP GC
- \endcode
-
- Functor based on \p std::allocator :
- \code
- template <typename ALLOC = std::allocator<int> >
- struct disposer {
- template <typename T>
- void operator()( T * p ) {
- typedef typename ALLOC::templare rebind<T>::other alloc_t;
- alloc_t a;
- a.destroy( p );
- a.deallocate( p, 1 );
- }
- };
- \endcode
- */
- template <class Disposer, typename T>
- static void retire( T * p ) ; // inline in hp_impl.h
-
- /// Get current scan strategy
- hp::scan_type getScanType() const
- {
- return hp::GarbageCollector::instance().getScanType();
- }
-
- /// Set current scan strategy
- void setScanType(
- hp::scan_type nScanType ///< new scan strategy
- )
- {
- hp::GarbageCollector::instance().setScanType( nScanType );
- }
-
- /// Checks if Hazard Pointer GC is constructed and may be used
- static bool isUsed()
- {
- return hp::GarbageCollector::isUsed();
- }
-
-
- /// Forced GC cycle call for current thread
- /**
- Usually, this function should not be called directly.
- */
- static void scan() ; // inline in hp_impl.h
-
- /// Synonym for \ref scan()
- static void force_dispose()
- {
- scan();
- }
- };
-}} // namespace cds::gc
-
-#endif // #ifndef __CDS_GC_HP_HP_DECL_H
+++ /dev/null
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HP_HP_IMPL_H
-#define __CDS_GC_HP_HP_IMPL_H
-
-#include <cds/threading/model.h>
-#include <cds/details/static_functor.h>
-
-//@cond
-namespace cds { namespace gc {
-
- inline HP::thread_gc::thread_gc(
- bool bPersistent
- )
- : m_bPersistent( bPersistent )
- {
- if ( !threading::Manager::isThreadAttached() )
- threading::Manager::attachThread();
- }
-
- inline HP::thread_gc::~thread_gc()
- {
- if ( !m_bPersistent )
- cds::threading::Manager::detachThread();
- }
-
- inline HP::Guard::Guard()
- : Guard::base_class( cds::threading::getGC<HP>() )
- {}
-
- template <size_t COUNT>
- inline HP::GuardArray<COUNT>::GuardArray()
- : GuardArray::base_class( cds::threading::getGC<HP>() )
- {}
-
- template <typename T>
- inline void HP::retire( T * p, void (* pFunc)(T *) )
- {
- cds::threading::getGC<HP>().retirePtr( p, pFunc );
- }
-
- template <class Disposer, typename T>
- inline void HP::retire( T * p )
- {
- cds::threading::getGC<HP>().retirePtr( p, cds::details::static_functor<Disposer, T>::call );
- }
-
- inline void HP::scan()
- {
- cds::threading::getGC<HP>().scan();
- }
-
-
-}} // namespace cds::gc
-//@endcond
-
-#endif // #ifndef __CDS_GC_HP_HP_IMPL_H
--- /dev/null
+//$$CDS-header$$
+
+#ifndef __CDS_GC_DHP_DHP_DECL_H
+#define __CDS_GC_DHP_DHP_DECL_H
+
+#include <cds/gc/details/dhp.h>
+#include <cds/details/marked_ptr.h>
+#include <cds/details/static_functor.h>
+
+namespace cds { namespace gc {
+
+ /// Dynamic Hazard Pointer garbage collector
+ /** @ingroup cds_garbage_collector
+ @headerfile cds/gc/dhp.h
+
+ Implementation of Dynamic Hazard Pointer garbage collector.
+
+ Sources:
+ - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
+ - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
+ - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
+
+ Dynamic Hazard Pointers SMR (safe memory reclamation) provides an unbounded number of hazard pointer per thread
+ despite of classic Hazard Pointer SMR in which the count of the hazard pointef per thread is limited.
+
+ See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
+ */
+ class DHP
+ {
+ public:
+ /// Native guarded pointer type
+ /**
+ @headerfile cds/gc/dhp.h
+ */
+ typedef void * guarded_pointer;
+
+ /// Atomic reference
+ /**
+ @headerfile cds/gc/dhp.h
+ */
+ template <typename T> using atomic_ref = atomics::atomic<T *>;
+
+ /// Atomic type
+ /**
+ @headerfile cds/gc/dhp.h
+ */
+ template <typename T> using atomic_type = atomics::atomic<T>;
+
+ /// Atomic marked pointer
+ /**
+ @headerfile cds/gc/dhp.h
+ */
+ template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
+
+ /// Thread GC implementation for internal usage
+ /**
+ @headerfile cds/gc/dhp.h
+ */
+ typedef dhp::ThreadGC thread_gc_impl;
+
+ /// Thread-level garbage collector
+ /**
+ @headerfile cds/gc/dhp.h
+ This class performs automatically attaching/detaching Dynamic Hazard Pointer GC
+ for the current thread.
+ */
+ class thread_gc: public thread_gc_impl
+ {
+ //@cond
+ bool m_bPersistent;
+ //@endcond
+ public:
+ /// Constructor
+ /**
+ The constructor attaches the current thread to the Dynamic Hazard Pointer GC
+ if it is not yet attached.
+ The \p bPersistent parameter specifies attachment persistence:
+ - \p true - the class destructor will not detach the thread from Dynamic Hazard Pointer GC.
+ - \p false (default) - the class destructor will detach the thread from Dynamic Hazard Pointer GC.
+ */
+ thread_gc(
+ bool bPersistent = false
+ ) ; // inline in dhp_impl.h
+
+ /// Destructor
+ /**
+ If the object has been created in persistent mode, the destructor does nothing.
+ Otherwise it detaches the current thread from Dynamic Hazard Pointer GC.
+ */
+ ~thread_gc() ; // inline in dhp_impl.h
+ };
+
+
+ /// Dynamic Hazard Pointer guard
+ /**
+ @headerfile cds/gc/dhp.h
+
+ A guard is the hazard pointer.
+ Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer
+
+ A \p %Guard object is not copy- and move-constructible
+ and not copy- and move-assignable.
+ */
+ class Guard: public dhp::Guard
+ {
+ //@cond
+ typedef dhp::Guard base_class;
+ //@endcond
+
+ public:
+ // Default ctor
+ Guard() CDS_NOEXCEPT; // inline in dhp_impl.h
+
+ //@cond
+ Guard( Guard const& ) = delete;
+ Guard( Guard&& s ) = delete;
+ Guard& operator=(Guard const&) = delete;
+ Guard& operator=(Guard&&) = delete;
+ //@endcond
+
+ /// Protects a pointer of type <tt> atomic<T*> </tt>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store it
+ to the HP slot repeatedly until the guard's value equals \p toGuard
+ */
+ template <typename T>
+ T protect( atomics::atomic<T> const& toGuard ) CDS_NOEXCEPT
+ {
+ T pCur = toGuard.load(atomics::memory_order_relaxed);
+ T pRet;
+ do {
+ pRet = assign( pCur );
+ pCur = toGuard.load(atomics::memory_order_acquire);
+ } while ( pRet != pCur );
+ return pCur;
+ }
+
+ /// Protects a converted pointer of type <tt> atomic<T*> </tt>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store result of \p f functor
+ to the HP slot repeatedly until the guard's value equals \p toGuard.
+
+ The function is useful for intrusive containers when \p toGuard is a node pointer
+ that should be converted to a pointer to the value type before guarding.
+ The parameter \p f of type Func is a functor that makes this conversion:
+ \code
+ struct functor {
+ value_type * operator()( T * p );
+ };
+ \endcode
+ Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
+ */
+ template <typename T, class Func>
+ T protect( atomics::atomic<T> const& toGuard, Func f ) CDS_NOEXCEPT_( f( toGuard.load( atomics::memory_order_relaxed )))
+ {
+ T pCur = toGuard.load(atomics::memory_order_relaxed);
+ T pRet;
+ do {
+ pRet = pCur;
+ assign( f( pCur ) );
+ pCur = toGuard.load(atomics::memory_order_acquire);
+ } while ( pRet != pCur );
+ return pCur;
+ }
+
+ /// Store \p p to the guard
+ /**
+ The function is just an assignment, no loop is performed.
+ Can be used for a pointer that cannot be changed concurrently
+ or for already guarded pointer.
+ */
+ template <typename T>
+ T * assign( T * p ) CDS_NOEXCEPT
+ {
+ return base_class::operator =(p);
+ }
+
+ //@cond
+ std::nullptr_t assign( std::nullptr_t ) CDS_NOEXCEPT
+ {
+ return base_class::operator =(nullptr);
+ }
+ //@endcond
+
+ /// Store marked pointer \p p to the guard
+ /**
+ The function is just an assignment of <tt>p.ptr()</tt>, no loop is performed.
+ Can be used for a marked pointer that cannot be changed concurrently
+ or for already guarded pointer.
+ */
+ template <typename T, int BITMASK>
+ T * assign( cds::details::marked_ptr<T, BITMASK> p ) CDS_NOEXCEPT
+ {
+ return base_class::operator =( p.ptr() );
+ }
+
+ /// Copy from \p src guard to \p this guard
+ void copy( Guard const& src ) CDS_NOEXCEPT
+ {
+ assign( src.get_native() );
+ }
+
+ /// Clears value of the guard
+ void clear() CDS_NOEXCEPT
+ {
+ base_class::clear();
+ }
+
+ /// Gets the value currently protected (relaxed read)
+ template <typename T>
+ T * get() const CDS_NOEXCEPT
+ {
+ return reinterpret_cast<T *>( get_native() );
+ }
+
+ /// Gets native guarded pointer stored
+ guarded_pointer get_native() const CDS_NOEXCEPT
+ {
+ return base_class::get_guard()->pPost.load(atomics::memory_order_relaxed);
+ }
+ };
+
+ /// Array of Dynamic Hazard Pointer guards
+ /**
+ @headerfile cds/gc/dhp.h
+ The class is intended for allocating an array of hazard pointer guards.
+ Template parameter \p Count defines the size of the array.
+
+ A \p %GuardArray object is not copy- and move-constructible
+ and not copy- and move-assignable.
+ */
+ template <size_t Count>
+ class GuardArray: public dhp::GuardArray<Count>
+ {
+ //@cond
+ typedef dhp::GuardArray<Count> base_class;
+ //@endcond
+ public:
+ /// Rebind array for other size \p OtherCount
+ template <size_t OtherCount>
+ struct rebind {
+ typedef GuardArray<OtherCount> other ; ///< rebinding result
+ };
+
+ public:
+ // Default ctor
+ GuardArray() CDS_NOEXCEPT; // inline in dhp_impl.h
+
+ //@cond
+ GuardArray( GuardArray const& ) = delete;
+ GuardArray( GuardArray&& ) = delete;
+ GuardArray& operator=(GuardArray const&) = delete;
+ GuardArray& operator-(GuardArray&&) = delete;
+ //@endcond
+
+ /// Protects a pointer of type \p atomic<T*>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store it
+ to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
+ */
+ template <typename T>
+ T protect( size_t nIndex, atomics::atomic<T> const& toGuard ) CDS_NOEXCEPT
+ {
+ T pRet;
+ do {
+ pRet = assign( nIndex, toGuard.load(atomics::memory_order_relaxed) );
+ } while ( pRet != toGuard.load(atomics::memory_order_acquire));
+
+ return pRet;
+ }
+
+ /// Protects a pointer of type \p atomic<T*>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store it
+ to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
+
+ The function is useful for intrusive containers when \p toGuard is a node pointer
+ that should be converted to a pointer to the value type before guarding.
+ The parameter \p f of type Func is a functor to make that conversion:
+ \code
+ struct functor {
+ value_type * operator()( T * p );
+ };
+ \endcode
+ Actually, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
+ */
+ template <typename T, class Func>
+ T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f ) CDS_NOEXCEPT_( f( toGuard.load( atomics::memory_order_relaxed )))
+ {
+ T pRet;
+ do {
+ assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_relaxed) ));
+ } while ( pRet != toGuard.load(atomics::memory_order_acquire));
+
+ return pRet;
+ }
+
+ /// Store \p p to the slot \p nIndex
+ /**
+ The function is just an assignment, no loop is performed.
+ */
+ template <typename T>
+ T * assign( size_t nIndex, T * p ) CDS_NOEXCEPT
+ {
+ base_class::set(nIndex, p);
+ return p;
+ }
+
+ /// Store marked pointer \p p to the guard
+ /**
+ The function is just an assignment of <tt>p.ptr()</tt>, no loop is performed.
+ Can be used for a marked pointer that cannot be changed concurrently
+ or for already guarded pointer.
+ */
+ template <typename T, int Bitmask>
+ T * assign( size_t nIndex, cds::details::marked_ptr<T, Bitmask> p ) CDS_NOEXCEPT
+ {
+ return assign( nIndex, p.ptr() );
+ }
+
+ /// Copy guarded value from \p src guard to slot at index \p nIndex
+ void copy( size_t nIndex, Guard const& src ) CDS_NOEXCEPT
+ {
+ assign( nIndex, src.get_native() );
+ }
+
+ /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
+ void copy( size_t nDestIndex, size_t nSrcIndex ) CDS_NOEXCEPT
+ {
+ assign( nDestIndex, get_native( nSrcIndex ));
+ }
+
+ /// Clear value of the slot \p nIndex
+ void clear( size_t nIndex ) CDS_NOEXCEPT
+ {
+ base_class::clear( nIndex );
+ }
+
+ /// Get current value of slot \p nIndex
+ template <typename T>
+ T * get( size_t nIndex ) const CDS_NOEXCEPT
+ {
+ return reinterpret_cast<T *>( get_native( nIndex ) );
+ }
+
+ /// Get native guarded pointer stored
+ guarded_pointer get_native( size_t nIndex ) const CDS_NOEXCEPT
+ {
+ return base_class::operator[](nIndex).get_guard()->pPost.load(atomics::memory_order_relaxed);
+ }
+
+ /// Capacity of the guard array
+ static CDS_CONSTEXPR size_t capacity() CDS_NOEXCEPT
+ {
+ return Count;
+ }
+ };
+
+ public:
+ /// Initializes dhp::GarbageCollector singleton
+ /**
+ The constructor calls GarbageCollector::Construct with passed parameters.
+ See dhp::GarbageCollector::Construct for explanation of parameters meaning.
+ */
+ DHP(
+ size_t nLiberateThreshold = 1024
+ , size_t nInitialThreadGuardCount = 8
+ )
+ {
+ dhp::GarbageCollector::Construct(
+ nLiberateThreshold,
+ nInitialThreadGuardCount
+ );
+ }
+
+ /// Terminates dhp::GarbageCollector singleton
+ /**
+ The destructor calls \code dhp::GarbageCollector::Destruct() \endcode
+ */
+ ~DHP()
+ {
+ dhp::GarbageCollector::Destruct();
+ }
+
+ /// Checks if count of hazard pointer is no less than \p nCountNeeded
+ /**
+ The function always returns \p true since the guard count is unlimited for
+ DHP garbage collector.
+ */
+ static CDS_CONSTEXPR bool check_available_guards( size_t nCountNeeded, bool /*bRaiseException*/ = true )
+ {
+ CDS_UNUSED( nCountNeeded );
+ return true;
+ }
+
+ /// Retire pointer \p p with function \p pFunc
+ /**
+ The function places pointer \p p to array of pointers ready for removing.
+ (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
+ Deleting the pointer is the function \p pFunc call.
+ */
+ template <typename T>
+ static void retire( T * p, void (* pFunc)(T *) )
+ {
+ dhp::GarbageCollector::instance().retirePtr( p, pFunc );
+ }
+
+ /// Retire pointer \p p with functor of type \p Disposer
+ /**
+ The function places pointer \p p to array of pointers ready for removing.
+ (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
+
+ See gc::HP::retire for \p Disposer requirements.
+ */
+ template <class Disposer, typename T>
+ static void retire( T * p )
+ {
+ retire( p, cds::details::static_functor<Disposer, T>::call );
+ }
+
+ /// Checks if Dynamic Hazard Pointer GC is constructed and may be used
+ static bool isUsed()
+ {
+ return dhp::GarbageCollector::isUsed();
+ }
+
+ /// Forced GC cycle call for current thread
+ /**
+ Usually, this function should not be called directly.
+ */
+ static void scan() ; // inline in dhp_impl.h
+
+ /// Synonym for \ref scan()
+ static void force_dispose()
+ {
+ scan();
+ }
+ };
+
+}} // namespace cds::gc
+
+#endif // #ifndef __CDS_GC_DHP_DHP_DECL_H
--- /dev/null
+//$$CDS-header$$
+
+#ifndef __CDS_GC_DHP_DHP_IMPL_H
+#define __CDS_GC_DHP_DHP_IMPL_H
+
+#include <cds/threading/model.h>
+
+//@cond
+namespace cds { namespace gc {
+
+ inline DHP::thread_gc::thread_gc(
+ bool bPersistent
+ )
+ : m_bPersistent( bPersistent )
+ {
+ if ( !cds::threading::Manager::isThreadAttached() )
+ cds::threading::Manager::attachThread();
+ }
+
+ inline DHP::thread_gc::~thread_gc()
+ {
+ if ( !m_bPersistent )
+ cds::threading::Manager::detachThread();
+ }
+
+ inline DHP::Guard::Guard() CDS_NOEXCEPT
+ : Guard::base_class( cds::threading::getGC<DHP>() )
+ {}
+
+ template <size_t COUNT>
+ inline DHP::GuardArray<COUNT>::GuardArray() CDS_NOEXCEPT
+ : GuardArray::base_class( cds::threading::getGC<DHP>() )
+ {}
+
+ inline void DHP::scan()
+ {
+ cds::threading::getGC<DHP>().scan();
+ }
+
+}} // namespace cds::gc
+//@endcond
+
+#endif // #ifndef __CDS_GC_DHP_DHP_IMPL_H
--- /dev/null
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HP_HP_DECL_H
+#define __CDS_GC_HP_HP_DECL_H
+
+#include <stdexcept> // overflow_error
+#include <cds/gc/details/hp.h>
+#include <cds/details/marked_ptr.h>
+
+namespace cds { namespace gc {
+ /// @defgroup cds_garbage_collector Garbage collectors
+
+ /// Hazard Pointer garbage collector
+ /** @ingroup cds_garbage_collector
+ @headerfile cds/gc/hp.h
+
+ Implementation of classic Hazard Pointer garbage collector.
+
+ Sources:
+ - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
+ - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
+ - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
+
+ See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
+ */
+ class HP
+ {
+ public:
+ /// Native guarded pointer type
+ /**
+ @headerfile cds/gc/hp.h
+ */
+ typedef gc::hp::hazard_pointer guarded_pointer;
+
+ /// Atomic reference
+ /**
+ @headerfile cds/gc/hp.h
+ */
+ template <typename T> using atomic_ref = atomics::atomic<T *>;
+
+ /// Atomic marked pointer
+ /**
+ @headerfile cds/gc/hp.h
+ */
+ template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
+
+ /// Atomic type
+ /**
+ @headerfile cds/gc/hp.h
+ */
+ template <typename T> using atomic_type = atomics::atomic<T>;
+
+ /// Thread GC implementation for internal usage
+ /**
+ @headerfile cds/gc/hp.h
+ */
+ typedef hp::ThreadGC thread_gc_impl;
+
+ /// Wrapper for hp::ThreadGC class
+ /**
+ @headerfile cds/gc/hp.h
+ This class performs automatically attaching/detaching Hazard Pointer GC
+ for the current thread.
+ */
+ class thread_gc: public thread_gc_impl
+ {
+ //@cond
+ bool m_bPersistent;
+ //@endcond
+ public:
+
+ /// Constructor
+ /**
+ The constructor attaches the current thread to the Hazard Pointer GC
+ if it is not yet attached.
+ The \p bPersistent parameter specifies attachment persistence:
+ - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
+ - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
+ */
+ thread_gc(
+ bool bPersistent = false
+ ) ; //inline in hp_impl.h
+
+ /// Destructor
+ /**
+ If the object has been created in persistent mode, the destructor does nothing.
+ Otherwise it detaches the current thread from Hazard Pointer GC.
+ */
+ ~thread_gc() ; // inline in hp_impl.h
+ };
+
+ /// Hazard Pointer guard
+ /**
+ @headerfile cds/gc/hp.h
+
+ A guard is the hazard pointer.
+ Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer
+
+ A \p %Guard object is not copy- and move-constructible
+ and not copy- and move-assignable.
+ */
+ class Guard : public hp::guard
+ {
+ //@cond
+ typedef hp::guard base_class;
+ //@endcond
+
+ public:
+ /// Default ctor
+ Guard() CDS_NOEXCEPT; // inline in hp_impl.h
+
+ //@cond
+ Guard( Guard const& ) = delete;
+ Guard( Guard&& s ) = delete;
+ Guard& operator=(Guard const&) = delete;
+ Guard& operator=(Guard&&) = delete;
+ //@endcond
+
+ /// Protects a pointer of type \p atomic<T*>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store it
+ to the HP slot repeatedly until the guard's value equals \p toGuard
+ */
+ template <typename T>
+ T protect( atomics::atomic<T> const& toGuard ) CDS_NOEXCEPT
+ {
+ T pCur = toGuard.load(atomics::memory_order_relaxed);
+ T pRet;
+ do {
+ pRet = assign( pCur );
+ pCur = toGuard.load(atomics::memory_order_acquire);
+ } while ( pRet != pCur );
+ return pCur;
+ }
+
+ /// Protects a converted pointer of type \p atomic<T*>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store result of \p f functor
+ to the HP slot repeatedly until the guard's value equals \p toGuard.
+
+ The function is useful for intrusive containers when \p toGuard is a node pointer
+ that should be converted to a pointer to the value type before protecting.
+ The parameter \p f of type Func is a functor that makes this conversion:
+ \code
+ struct functor {
+ value_type * operator()( T * p );
+ };
+ \endcode
+ Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
+ */
+ template <typename T, class Func>
+ T protect( atomics::atomic<T> const& toGuard, Func f ) CDS_NOEXCEPT_( f( toGuard.load( atomics::memory_order_relaxed ) ) )
+ {
+ T pCur = toGuard.load(atomics::memory_order_relaxed);
+ T pRet;
+ do {
+ pRet = pCur;
+ assign( f( pCur ) );
+ pCur = toGuard.load(atomics::memory_order_acquire);
+ } while ( pRet != pCur );
+ return pCur;
+ }
+
+ /// Store \p p to the guard
+ /**
+ The function equals to a simple assignment the value \p p to guard, no loop is performed.
+ Can be used for a pointer that cannot be changed concurrently
+ */
+ template <typename T>
+ T * assign( T * p ) CDS_NOEXCEPT
+ {
+ return base_class::operator =(p);
+ }
+
+ //@cond
+ std::nullptr_t assign( std::nullptr_t ) CDS_NOEXCEPT
+ {
+ return base_class::operator =(nullptr);
+ }
+ //@endcond
+
+ /// Copy from \p src guard to \p this guard
+ void copy( Guard const& src ) CDS_NOEXCEPT
+ {
+ assign( src.get_native() );
+ }
+
+ /// Store marked pointer \p p to the guard
+ /**
+ The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
+ Can be used for a marked pointer that cannot be changed concurrently.
+ */
+ template <typename T, int BITMASK>
+ T * assign( cds::details::marked_ptr<T, BITMASK> p ) CDS_NOEXCEPT
+ {
+ return base_class::operator =( p.ptr() );
+ }
+
+ /// Clear value of the guard
+ void clear() CDS_NOEXCEPT
+ {
+ assign( nullptr );
+ }
+
+ /// Get the value currently protected
+ template <typename T>
+ T * get() const CDS_NOEXCEPT
+ {
+ return reinterpret_cast<T *>( get_native() );
+ }
+
+ /// Get native hazard pointer stored
+ guarded_pointer get_native() const CDS_NOEXCEPT
+ {
+ return base_class::get();
+ }
+ };
+
+ /// Array of Hazard Pointer guards
+ /**
+ @headerfile cds/gc/hp.h
+ The class is intended for allocating an array of hazard pointer guards.
+ Template parameter \p Count defines the size of the array.
+
+ A \p %GuardArray object is not copy- and move-constructible
+ and not copy- and move-assignable.
+ */
+ template <size_t Count>
+ class GuardArray : public hp::array<Count>
+ {
+ //@cond
+ typedef hp::array<Count> base_class;
+ //@endcond
+ public:
+ /// Rebind array for other size \p Count2
+ template <size_t Count2>
+ struct rebind {
+ typedef GuardArray<Count2> other ; ///< rebinding result
+ };
+
+ public:
+ /// Default ctor
+ GuardArray() CDS_NOEXCEPT; // inline in hp_impl.h
+
+ //@cond
+ GuardArray( GuardArray const& ) = delete;
+ GuardArray( GuardArray&& ) = delete;
+ GuardArray& operator=(GuardArray const&) = delete;
+ GuardArray& operator-(GuardArray&&) = delete;
+ //@endcond
+
+ /// Protects a pointer of type \p atomic<T*>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store it
+ to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
+ */
+ template <typename T>
+ T protect( size_t nIndex, atomics::atomic<T> const& toGuard ) CDS_NOEXCEPT
+ {
+ T pRet;
+ do {
+ pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
+ } while ( pRet != toGuard.load(atomics::memory_order_relaxed));
+
+ return pRet;
+ }
+
+ /// Protects a pointer of type \p atomic<T*>
+ /**
+ Return the value of \p toGuard
+
+ The function tries to load \p toGuard and to store it
+ to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
+
+ The function is useful for intrusive containers when \p toGuard is a node pointer
+ that should be converted to a pointer to the value type before guarding.
+ The parameter \p f of type Func is a functor that makes this conversion:
+ \code
+ struct functor {
+ value_type * operator()( T * p );
+ };
+ \endcode
+ Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
+ */
+ template <typename T, class Func>
+ T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f ) CDS_NOEXCEPT_( f( toGuard.load( atomics::memory_order_acquire )))
+ {
+ T pRet;
+ do {
+ assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
+ } while ( pRet != toGuard.load(atomics::memory_order_relaxed));
+
+ return pRet;
+ }
+
+ /// Store \p to the slot \p nIndex
+ /**
+ The function equals to a simple assignment, no loop is performed.
+ */
+ template <typename T>
+ T * assign( size_t nIndex, T * p ) CDS_NOEXCEPT
+ {
+ base_class::set(nIndex, p);
+ return p;
+ }
+
+ /// Store marked pointer \p p to the guard
+ /**
+ The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
+ Can be used for a marked pointer that cannot be changed concurrently.
+ */
+ template <typename T, int BITMASK>
+ T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p ) CDS_NOEXCEPT
+ {
+ return assign( nIndex, p.ptr() );
+ }
+
+ /// Copy guarded value from \p src guard to slot at index \p nIndex
+ void copy( size_t nIndex, Guard const& src ) CDS_NOEXCEPT
+ {
+ assign( nIndex, src.get_native() );
+ }
+
+ /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
+ void copy( size_t nDestIndex, size_t nSrcIndex ) CDS_NOEXCEPT
+ {
+ assign( nDestIndex, get_native( nSrcIndex ));
+ }
+
+ /// Clear value of the slot \p nIndex
+ void clear( size_t nIndex ) CDS_NOEXCEPT
+ {
+ base_class::clear( nIndex );
+ }
+
+ /// Get current value of slot \p nIndex
+ template <typename T>
+ T * get( size_t nIndex ) const CDS_NOEXCEPT
+ {
+ return reinterpret_cast<T *>( get_native( nIndex ) );
+ }
+
+ /// Get native hazard pointer stored
+ guarded_pointer get_native( size_t nIndex ) const CDS_NOEXCEPT
+ {
+ return base_class::operator[](nIndex).get();
+ }
+
+ /// Capacity of the guard array
+ static CDS_CONSTEXPR size_t capacity() CDS_NOEXCEPT
+ {
+ return Count;
+ }
+ };
+
+ public:
+ /// Initializes hp::GarbageCollector singleton
+ /**
+ The constructor initializes GC singleton with passed parameters.
+ If GC instance is not exist then the function creates the instance.
+ Otherwise it does nothing.
+
+ The Michael's HP reclamation schema depends of three parameters:
+ - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
+ the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
+ uses maximum of the hazard pointer count for CDS library.
+ - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
+ - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
+ <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
+ */
+ HP(
+ size_t nHazardPtrCount = 0, ///< Hazard pointer count per thread
+ size_t nMaxThreadCount = 0, ///< Max count of simultaneous working thread in your application
+ size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
+ hp::scan_type nScanType = hp::inplace ///< Scan type (see \ref hp::scan_type enum)
+ )
+ {
+ hp::GarbageCollector::Construct(
+ nHazardPtrCount,
+ nMaxThreadCount,
+ nMaxRetiredPtrCount,
+ nScanType
+ );
+ }
+
+ /// Terminates GC singleton
+ /**
+ The destructor calls \code hp::GarbageCollector::Destruct( true ) \endcode
+ */
+ ~HP()
+ {
+ hp::GarbageCollector::Destruct( true );
+ }
+
+ /// Checks if count of hazard pointer is no less than \p nCountNeeded
+ /**
+ If \p bRaiseException is \p true (that is the default), the function raises
+ an \p std::overflow_error exception "Too few hazard pointers"
+ if \p nCountNeeded is more than the count of hazard pointer per thread.
+ */
+ static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
+ {
+ if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
+ if ( bRaiseException )
+ throw std::overflow_error( "Too few hazard pointers" );
+ return false;
+ }
+ return true;
+ }
+
+ /// Returns max Hazard Pointer count
+ size_t max_hazard_count() const
+ {
+ return hp::GarbageCollector::instance().getHazardPointerCount();
+ }
+
+ /// Returns max count of thread
+ size_t max_thread_count() const
+ {
+ return hp::GarbageCollector::instance().getMaxThreadCount();
+ }
+
+ /// Returns capacity of retired pointer array
+ size_t retired_array_capacity() const
+ {
+ return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
+ }
+
+ /// Retire pointer \p p with function \p pFunc
+ /**
+ The function places pointer \p p to array of pointers ready for removing.
+ (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
+ Deleting the pointer is the function \p pFunc call.
+ */
+ template <typename T>
+ static void retire( T * p, void (* pFunc)(T *) ) ; // inline in hp_impl.h
+
+ /// Retire pointer \p p with functor of type \p Disposer
+ /**
+ The function places pointer \p p to array of pointers ready for removing.
+ (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
+
+ Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
+ \code
+ template <typename T>
+ struct disposer {
+ void operator()( T * p ) ; // disposing operator
+ };
+ \endcode
+ Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
+ - it should be stateless functor
+ - it should be default-constructible
+ - the result of functor call with argument \p p should not depend on where the functor will be called.
+
+ \par Examples:
+ Operator \p delete functor:
+ \code
+ template <typename T>
+ struct disposer {
+ void operator ()( T * p ) {
+ delete p;
+ }
+ };
+
+ // How to call GC::retire method
+ int * p = new int;
+
+ // ... use p in lock-free manner
+
+ cds::gc::HP::retire<disposer>( p ) ; // place p to retired pointer array of HP GC
+ \endcode
+
+ Functor based on \p std::allocator :
+ \code
+ template <typename ALLOC = std::allocator<int> >
+ struct disposer {
+ template <typename T>
+ void operator()( T * p ) {
+ typedef typename ALLOC::templare rebind<T>::other alloc_t;
+ alloc_t a;
+ a.destroy( p );
+ a.deallocate( p, 1 );
+ }
+ };
+ \endcode
+ */
+ template <class Disposer, typename T>
+ static void retire( T * p ) ; // inline in hp_impl.h
+
+ /// Get current scan strategy
+ hp::scan_type getScanType() const
+ {
+ return hp::GarbageCollector::instance().getScanType();
+ }
+
+ /// Set current scan strategy
+ void setScanType(
+ hp::scan_type nScanType ///< new scan strategy
+ )
+ {
+ hp::GarbageCollector::instance().setScanType( nScanType );
+ }
+
+ /// Checks if Hazard Pointer GC is constructed and may be used
+ static bool isUsed()
+ {
+ return hp::GarbageCollector::isUsed();
+ }
+
+
+ /// Forced GC cycle call for current thread
+ /**
+ Usually, this function should not be called directly.
+ */
+ static void scan() ; // inline in hp_impl.h
+
+ /// Synonym for \ref scan()
+ static void force_dispose()
+ {
+ scan();
+ }
+ };
+}} // namespace cds::gc
+
+#endif // #ifndef __CDS_GC_HP_HP_DECL_H
--- /dev/null
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HP_HP_IMPL_H
+#define __CDS_GC_HP_HP_IMPL_H
+
+#include <cds/threading/model.h>
+#include <cds/details/static_functor.h>
+
+//@cond
+namespace cds { namespace gc {
+
+ inline HP::thread_gc::thread_gc(
+ bool bPersistent
+ )
+ : m_bPersistent( bPersistent )
+ {
+ if ( !threading::Manager::isThreadAttached() )
+ threading::Manager::attachThread();
+ }
+
+ inline HP::thread_gc::~thread_gc()
+ {
+ if ( !m_bPersistent )
+ cds::threading::Manager::detachThread();
+ }
+
+ inline HP::Guard::Guard() CDS_CONSTEXPR
+ : Guard::base_class( cds::threading::getGC<HP>() )
+ {}
+
+ template <size_t COUNT>
+ inline HP::GuardArray<COUNT>::GuardArray() CDS_CONSTEXPR
+ : GuardArray::base_class( cds::threading::getGC<HP>() )
+ {}
+
+ template <typename T>
+ inline void HP::retire( T * p, void (* pFunc)(T *) )
+ {
+ cds::threading::getGC<HP>().retirePtr( p, pFunc );
+ }
+
+ template <class Disposer, typename T>
+ inline void HP::retire( T * p )
+ {
+ cds::threading::getGC<HP>().retirePtr( p, cds::details::static_functor<Disposer, T>::call );
+ }
+
+ inline void HP::scan()
+ {
+ cds::threading::getGC<HP>().scan();
+ }
+
+
+}} // namespace cds::gc
+//@endcond
+
+#endif // #ifndef __CDS_GC_HP_HP_IMPL_H
#ifndef __CDS_THREADING__COMMON_H
#define __CDS_THREADING__COMMON_H
-#include <cds/gc/hp/hp_decl.h>
-#include <cds/gc/dhp/dhp_decl.h>
+#include <cds/gc/impl/hp_decl.h>
+#include <cds/gc/impl/dhp_decl.h>
#include <cds/urcu/details/gp_decl.h>
#include <cds/urcu/details/sh_decl.h>
<ClInclude Include="..\..\..\cds\gc\details\hp_inline.h" />\r
<ClInclude Include="..\..\..\cds\gc\details\hp_type.h" />\r
<ClInclude Include="..\..\..\cds\gc\dhp.h" />\r
- <ClInclude Include="..\..\..\cds\gc\dhp\dhp_decl.h" />\r
- <ClInclude Include="..\..\..\cds\gc\dhp\dhp_impl.h" />\r
<ClInclude Include="..\..\..\cds\gc\guarded_ptr.h" />\r
- <ClInclude Include="..\..\..\cds\gc\hp\hp.h" />\r
- <ClInclude Include="..\..\..\cds\gc\hp\hp_decl.h" />\r
- <ClInclude Include="..\..\..\cds\gc\hp\hp_impl.h" />\r
+ <ClInclude Include="..\..\..\cds\gc\impl\dhp_decl.h" />\r
+ <ClInclude Include="..\..\..\cds\gc\impl\dhp_impl.h" />\r
+ <ClInclude Include="..\..\..\cds\gc\impl\hp_decl.h" />\r
+ <ClInclude Include="..\..\..\cds\gc\impl\hp_impl.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\basket_queue.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\cuckoo_set.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\details\base.h" />\r
<Filter Include="Header Files\cds\container\impl">\r
<UniqueIdentifier>{0a2328b4-ff6f-4afb-8de0-9884ae172fa9}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="Header Files\cds\gc\hp">\r
- <UniqueIdentifier>{043c4eba-3bd4-4226-b214-e26f18b422a1}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="Header Files\cds\gc\dhp">\r
- <UniqueIdentifier>{9c0f5739-8d9d-46c2-bb91-90ca5beecc6d}</UniqueIdentifier>\r
+ <Filter Include="Header Files\cds\gc\impl">\r
+ <UniqueIdentifier>{3195cce2-1710-4b79-a1cf-6c7cea085fa3}</UniqueIdentifier>\r
</Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\..\cds\gc\dhp.h">\r
<Filter>Header Files\cds\gc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\cds\gc\hp\hp.h">\r
- <Filter>Header Files\cds\gc\hp</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\..\cds\gc\dhp\dhp_decl.h">\r
- <Filter>Header Files\cds\gc\dhp</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\..\cds\gc\dhp\dhp_impl.h">\r
- <Filter>Header Files\cds\gc\dhp</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\..\cds\gc\hp\hp_decl.h">\r
- <Filter>Header Files\cds\gc\hp</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\..\cds\gc\hp\hp_impl.h">\r
- <Filter>Header Files\cds\gc\hp</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\src\hp_const.h">\r
<Filter>Source Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\..\..\cds\gc\details\dhp.h">\r
<Filter>Header Files\cds\gc\details</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\..\cds\gc\impl\dhp_decl.h">\r
+ <Filter>Header Files\cds\gc\impl</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\gc\impl\dhp_impl.h">\r
+ <Filter>Header Files\cds\gc\impl</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\gc\impl\hp_decl.h">\r
+ <Filter>Header Files\cds\gc\impl</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\gc\impl\hp_impl.h">\r
+ <Filter>Header Files\cds\gc\impl</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file