rearrange cds/gc contents
authorkhizmax <khizmax@gmail.com>
Fri, 14 Nov 2014 11:38:56 +0000 (14:38 +0300)
committerkhizmax <khizmax@gmail.com>
Fri, 14 Nov 2014 11:38:56 +0000 (14:38 +0300)
26 files changed:
cds/container/ellen_bintree_map_dhp.h
cds/container/ellen_bintree_set_dhp.h
cds/gc/dhp.h
cds/gc/dhp_decl.h [new file with mode: 0644]
cds/gc/dhp_impl.h [new file with mode: 0644]
cds/gc/hp/details/hp_alloc.h [new file with mode: 0644]
cds/gc/hp/details/hp_fwd.h [new file with mode: 0644]
cds/gc/hp/details/hp_inline.h [new file with mode: 0644]
cds/gc/hp/details/hp_retired.h [new file with mode: 0644]
cds/gc/hp/details/hp_type.h [new file with mode: 0644]
cds/gc/hp/hzp.h [new file with mode: 0644]
cds/gc/hp_decl.h
cds/gc/hzp/details/hp_alloc.h [deleted file]
cds/gc/hzp/details/hp_fwd.h [deleted file]
cds/gc/hzp/details/hp_inline.h [deleted file]
cds/gc/hzp/details/hp_retired.h [deleted file]
cds/gc/hzp/details/hp_type.h [deleted file]
cds/gc/hzp/hzp.h [deleted file]
cds/gc/ptb.h [deleted file]
cds/gc/ptb_decl.h [deleted file]
cds/gc/ptb_impl.h [deleted file]
cds/threading/details/_common.h
projects/Win/vc12/cds.vcxproj
projects/Win/vc12/cds.vcxproj.filters
src/hzp_gc.cpp
tests/cppunit/test_main.cpp

index 91378d43f4347f15020d846f30730ce695c3e49b..59ed1e27e6f82b7220823e10ba2fa0c794a91b97 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef __CDS_CONTAINER_ELLEN_BINTREE_MAP_DHP_H
 #define __CDS_CONTAINER_ELLEN_BINTREE_MAP_DHP_H
 
-#include <cds/gc/ptb.h>
+#include <cds/gc/dhp.h>
 #include <cds/container/impl/ellen_bintree_map.h>
 
 #endif // #ifndef __CDS_CONTAINER_ELLEN_BINTREE_MAP_DHP_H
index beaca96ba5f99763d530faaf5bec61fcaf10794e..3bb3adf1375701882f94dac5f50ccc7b8f7c3771 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef __CDS_CONTAINER_ELLEN_BINTREE_SET_DHP_H
 #define __CDS_CONTAINER_ELLEN_BINTREE_SET_DHP_H
 
-#include <cds/gc/ptb.h>
+#include <cds/gc/dhp.h>
 #include <cds/container/impl/ellen_bintree_set.h>
 
 #endif // #ifndef __CDS_CONTAINER_ELLEN_BINTREE_SET_DHP_H
index 89abde529cff190d3205e7906d3732d762f6264b..819f49dcb7c9d860533055a1851faff676a12f89 100644 (file)
@@ -1,14 +1,10 @@
 //$$CDS-header$$
 
-#ifndef __CDS_GC_DHP_H
-#define __CDS_GC_DHP_H
+#ifndef __CDS_GC_PTB_H
+#define __CDS_GC_PTB_H
 
-#include <cds/gc/ptb.h>
+#include <cds/gc/dhp_decl.h>
+#include <cds/gc/dhp_impl.h>
+#include <cds/details/lib.h>
 
-//@cond
-namespace cds { namespace gc {
-    typedef PTB DHP;
-}} // namespace cds::gc
-//@endcond
-
-#endif // #ifndef __CDS_GC_DHP_H
+#endif // #ifndef __CDS_GC_PTB_H
diff --git a/cds/gc/dhp_decl.h b/cds/gc/dhp_decl.h
new file mode 100644 (file)
index 0000000..3249913
--- /dev/null
@@ -0,0 +1,421 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_PTB_DECL_H
+#define __CDS_GC_PTB_DECL_H
+
+#include <cds/gc/ptb/ptb.h>
+#include <cds/details/marked_ptr.h>
+#include <cds/details/static_functor.h>
+
+namespace cds { namespace gc {
+
+    /// Pass-the-Buck garbage collector
+    /**  @ingroup cds_garbage_collector
+        @headerfile cds/gc/dhp.h
+        This class is a wrapper for Pass-the-Buck garbage collector internal implementation.
+
+        Sources:
+        - [2002] M. Herlihy, V. Luchangco, and M. Moir. The repeat offender problem: A mechanism for supporting
+            dynamic-sized lockfree data structures. Technical Report TR-2002-112, Sun Microsystems Laboratories, 2002
+        - [2002] M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Dynamic-sized Lockfree Data Structures.
+            Technical Report TR-2002-110, Sun Microsystems Laboratories, 2002
+        - [2005] M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Nonblocking Memory Management Support
+            for Dynamic_Sized Data Structures. ACM Transactions on Computer Systems, Vol.23, No.2, May 2005
+
+        See \ref cds_how_to_use "How to use" section for details of garbage collector applying.
+    */
+    class PTB
+    {
+    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 ptb::ThreadGC   thread_gc_impl;
+
+        /// Wrapper for ptb::ThreadGC class
+        /**
+            @headerfile cds/gc/dhp.h
+            This class performs automatically attaching/detaching Pass-the-Buck 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 Pass-the-Buck 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 Pass-the-Buck GC.
+                - \p false (default) - the class destructor will detach the thread from Pass-the-Buck GC.
+            */
+            thread_gc(
+                bool    bPersistent = false
+            )   ;   // inline in ptb_impl.h
+
+            /// Destructor
+            /**
+                If the object has been created in persistent mode, the destructor does nothing.
+                Otherwise it detaches the current thread from Pass-the-Buck GC.
+            */
+            ~thread_gc()    ;   // inline in ptb_impl.h
+        };
+
+
+        /// Pass-the-Buck guard
+        /**
+            @headerfile cds/gc/dhp.h
+            This class is a wrapper for ptb::Guard.
+        */
+        class Guard: public ptb::Guard
+        {
+            //@cond
+            typedef ptb::Guard base_class;
+            //@endcond
+
+        public:
+            //@cond
+            Guard() ;   // inline in ptb_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 Pass-the-Buck guards
+        /**
+            @headerfile cds/gc/dhp.h
+            This class is a wrapper for ptb::GuardArray template.
+            Template parameter \p Count defines the size of PTB array.
+        */
+        template <size_t Count>
+        class GuardArray: public ptb::GuardArray<Count>
+        {
+            //@cond
+            typedef ptb::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 ptb_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 ptb::GarbageCollector singleton
+        /**
+            The constructor calls GarbageCollector::Construct with passed parameters.
+            See ptb::GarbageCollector::Construct for explanation of parameters meaning.
+        */
+        PTB(
+            size_t nLiberateThreshold = 1024
+            , size_t nInitialThreadGuardCount = 8
+        )
+        {
+            ptb::GarbageCollector::Construct(
+                nLiberateThreshold,
+                nInitialThreadGuardCount
+            );
+        }
+
+        /// Terminates ptb::GarbageCollector singleton
+        /**
+            The destructor calls \code ptb::GarbageCollector::Destruct() \endcode
+        */
+        ~PTB()
+        {
+            ptb::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
+            PTB 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 *) )
+        {
+            ptb::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 Pass-the-Buck GC is constructed and may be used
+        static bool isUsed()
+        {
+            return ptb::GarbageCollector::isUsed();
+        }
+
+        /// Forced GC cycle call for current thread
+        /**
+            Usually, this function should not be called directly.
+        */
+        static void scan()  ;   // inline in ptb_impl.h
+
+        /// Synonym for \ref scan()
+        static void force_dispose()
+        {
+            scan();
+        }
+    };
+
+}} // namespace cds::gc
+
+#endif // #ifndef __CDS_GC_PTB_DECL_H
diff --git a/cds/gc/dhp_impl.h b/cds/gc/dhp_impl.h
new file mode 100644 (file)
index 0000000..201564c
--- /dev/null
@@ -0,0 +1,43 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_PTB_IMPL_H
+#define __CDS_GC_PTB_IMPL_H
+
+#include <cds/threading/model.h>
+
+//@cond
+namespace cds { namespace gc {
+
+    inline PTB::thread_gc::thread_gc(
+        bool    bPersistent
+        )
+        : m_bPersistent( bPersistent )
+    {
+        if ( !cds::threading::Manager::isThreadAttached() )
+            cds::threading::Manager::attachThread();
+    }
+
+    inline PTB::thread_gc::~thread_gc()
+    {
+        if ( !m_bPersistent )
+            cds::threading::Manager::detachThread();
+    }
+
+    inline PTB::Guard::Guard()
+        : Guard::base_class( cds::threading::getGC<PTB>() )
+    {}
+
+    template <size_t COUNT>
+    inline PTB::GuardArray<COUNT>::GuardArray()
+        : GuardArray::base_class( cds::threading::getGC<PTB>() )
+    {}
+
+    inline void PTB::scan()
+    {
+        cds::threading::getGC<PTB>().scan();
+    }
+
+}} // namespace cds::gc
+//@endcond
+
+#endif // #ifndef __CDS_GC_PTB_IMPL_H
diff --git a/cds/gc/hp/details/hp_alloc.h b/cds/gc/hp/details/hp_alloc.h
new file mode 100644 (file)
index 0000000..2dcadd2
--- /dev/null
@@ -0,0 +1,324 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HZP_DETAILS_HP_ALLOC_H
+#define __CDS_GC_HZP_DETAILS_HP_ALLOC_H
+
+#include <cds/cxx11_atomic.h>
+#include <cds/details/allocator.h>
+#include <cds/gc/hp/details/hp_fwd.h>
+#include <cds/gc/hp/details/hp_type.h>
+
+//@cond
+namespace cds {
+    namespace gc { namespace hzp {
+    /// Hazard Pointer schema implementation details
+    namespace details {
+
+        /// Hazard pointer guard
+        /**
+            It is unsafe to use this class directly.
+            Instead, the AutoHPGuard class should be used.
+
+            Template parameter:
+                \li HazardPointer - type of hazard pointer. It is \ref hazard_pointer for Michael's Hazard Pointer reclamation schema
+        */
+        template <typename HazardPointer>
+        class HPGuardT: protected atomics::atomic<HazardPointer>
+        {
+        public:
+            typedef HazardPointer   hazard_ptr ;    ///< Hazard pointer type
+        private:
+            //@cond
+            typedef atomics::atomic<hazard_ptr>  base_class;
+            //@endcond
+
+        protected:
+            //@cond
+            template <typename OtherHazardPointer, class Allocator> friend class HPAllocator;
+            //@endcond
+
+        public:
+            HPGuardT() CDS_NOEXCEPT
+                : base_class( nullptr )
+            {}
+            ~HPGuardT() CDS_NOEXCEPT
+            {}
+
+            /// Sets HP value. Guards pointer \p p from reclamation.
+            /**
+                Storing has release semantics.
+            */
+            template <typename T>
+            T * operator =( T * p ) CDS_NOEXCEPT
+            {
+                // We use atomic store with explicit memory order because other threads may read this hazard pointer concurrently
+                base_class::store( reinterpret_cast<hazard_ptr>(p), atomics::memory_order_release );
+                return p;
+            }
+
+            //@cond
+            std::nullptr_t operator=( std::nullptr_t ) CDS_NOEXCEPT
+            {
+                clear();
+                return nullptr;
+            }
+            //@endcond
+
+            /// Returns current value of hazard pointer
+            /**
+                Loading has acquire semantics
+            */
+            operator hazard_ptr() const CDS_NOEXCEPT
+            {
+                return get();
+            }
+
+            /// Returns current value of hazard pointer
+            /**
+                Loading has acquire semantics
+            */
+            hazard_ptr get() const CDS_NOEXCEPT
+            {
+                return base_class::load( atomics::memory_order_acquire );
+            }
+
+            /// Clears HP
+            /**
+                Clearing has relaxed semantics.
+            */
+            void clear() CDS_NOEXCEPT
+            {
+                // memory order is not necessary here
+                base_class::store( nullptr, atomics::memory_order_relaxed );
+                //CDS_COMPILER_RW_BARRIER;
+            }
+        };
+
+        /// Specialization of HPGuardT for hazard_pointer type
+        typedef HPGuardT<hazard_pointer> HPGuard;
+
+        /// Array of hazard pointers.
+        /**
+            Array of hazard-pointer. Placing a pointer into this array guards the pointer against reclamation.
+            Template parameter \p Count defines the size of hazard pointer array. \p Count parameter should not exceed
+            GarbageCollector::getHazardPointerCount().
+
+            It is unsafe to use this class directly. Instead, the AutoHPArray should be used.
+
+            While creating the object of HPArray class an array of size \p Count of hazard pointers is reserved by
+            the HP Manager of current thread. The object's destructor cleans all of reserved hazard pointer and
+            returns reserved HP to the HP pool of ThreadGC.
+
+            Usually, it is not necessary to create an object of this class. The object of class ThreadGC contains
+            the HPArray object and implements interface for HP setting and freeing.
+
+            Template parameter:
+                \li HazardPointer - type of hazard pointer. It is hazard_pointer usually
+                \li Count - capacity of array
+
+        */
+        template <typename HazardPointer, size_t Count>
+        class HPArrayT
+        {
+        public:
+            typedef HazardPointer   hazard_ptr_type ;   ///< Hazard pointer type
+            typedef HPGuardT<hazard_ptr_type>   atomic_hazard_ptr    ; ///< Element type of the array
+            static const size_t c_nCapacity = Count ;   ///< Capacity of the array
+
+        private:
+            //@cond
+            atomic_hazard_ptr *     m_arr               ;   ///< Hazard pointer array of size = \p Count
+            template <typename OtherHazardPointer, class Allocator> friend class HPAllocator;
+            //@endcond
+
+        public:
+            /// Constructs uninitialized array.
+            HPArrayT() CDS_NOEXCEPT
+            {}
+
+            /// Destructs object
+            ~HPArrayT() CDS_NOEXCEPT
+            {}
+
+            /// Returns max count of hazard pointer for this array
+            CDS_CONSTEXPR size_t capacity() const
+            {
+                return c_nCapacity;
+            }
+
+            /// Set hazard pointer \p nIndex. 0 <= \p nIndex < \p Count
+            void set( size_t nIndex, hazard_ptr_type hzPtr ) CDS_NOEXCEPT
+            {
+                assert( nIndex < capacity() );
+                m_arr[nIndex] = hzPtr;
+            }
+
+            /// Returns reference to hazard pointer of index \p nIndex (0 <= \p nIndex < \p Count)
+            atomic_hazard_ptr& operator []( size_t nIndex ) CDS_NOEXCEPT
+            {
+                assert( nIndex < capacity() );
+                return m_arr[nIndex];
+            }
+
+            /// Returns reference to hazard pointer of index \p nIndex (0 <= \p nIndex < \p Count) [const version]
+            atomic_hazard_ptr& operator []( size_t nIndex ) const CDS_NOEXCEPT
+            {
+                assert( nIndex < capacity() );
+                return m_arr[nIndex];
+            }
+
+            /// Clears (sets to \p nullptr) hazard pointer \p nIndex
+            void clear( size_t nIndex ) CDS_NOEXCEPT
+            {
+                assert( nIndex < capacity() );
+                m_arr[ nIndex ].clear();
+            }
+        };
+
+        /// Specialization of HPArrayT class for hazard_pointer type
+        template <size_t Count> using HPArray = HPArrayT<hazard_pointer, Count >;
+
+        /// Allocator of hazard pointers for the thread
+        /**
+            The hazard pointer array is the free-list of unused hazard pointer for the thread.
+            The array is managed as a stack.
+            The max size (capacity) of array is defined at ctor time and cannot be changed during object's lifetime
+
+            Each allocator object is thread-private.
+
+            Template parameters:
+                \li HazardPointer - type of hazard pointer (hazard_pointer usually)
+                \li Allocator - memory allocator class, default is \ref CDS_DEFAULT_ALLOCATOR
+
+            This helper class should not be used directly.
+        */
+        template < typename HazardPointer, class Allocator = CDS_DEFAULT_ALLOCATOR >
+        class HPAllocator
+        {
+        public:
+            typedef HazardPointer               hazard_ptr_type     ;   ///< type of hazard pointer
+            typedef HPGuardT<hazard_ptr_type>   atomic_hazard_ptr   ;   ///< Atomic hazard pointer type
+            typedef Allocator                   allocator_type      ;   ///< allocator type
+
+        private:
+            //@cond
+            typedef cds::details::Allocator< atomic_hazard_ptr, allocator_type > allocator_impl;
+
+            atomic_hazard_ptr * m_arrHazardPtr  ;   ///< Array of hazard pointers
+            size_t              m_nTop          ;   ///< The top of stack
+            const size_t        m_nCapacity     ;   ///< Array capacity
+
+            //@endcond
+
+        public:
+            /// Default ctor
+            explicit HPAllocator(
+                size_t  nCapacity            ///< max count of hazard pointer per thread
+                )
+                : m_arrHazardPtr( alloc_array( nCapacity ) )
+                , m_nCapacity( nCapacity )
+            {
+                make_free();
+            }
+
+            /// Dtor
+            ~HPAllocator()
+            {
+                allocator_impl().Delete( m_arrHazardPtr, capacity() );
+            }
+
+            /// Get capacity of array
+            size_t capacity() const CDS_NOEXCEPT
+            {
+                return m_nCapacity;
+            }
+
+            /// Get size of array. The size is equal to the capacity of array
+            size_t size() const CDS_NOEXCEPT
+            {
+                return capacity();
+            }
+
+            /// Checks if all items are allocated
+            bool isFull() const CDS_NOEXCEPT
+            {
+                return m_nTop == 0;
+            }
+
+            /// Allocates hazard pointer
+            atomic_hazard_ptr& alloc() CDS_NOEXCEPT
+            {
+                assert( m_nTop > 0 );
+                --m_nTop;
+                return m_arrHazardPtr[m_nTop];
+            }
+
+            /// Frees previously allocated hazard pointer
+            void free( atomic_hazard_ptr& hp ) CDS_NOEXCEPT
+            {
+                assert( m_nTop < capacity() );
+                hp.clear();
+                ++m_nTop;
+                CDS_COMPILER_RW_BARRIER ;   // ???
+            }
+
+            /// Allocates hazard pointers array
+            /**
+                Allocates \p Count hazard pointers from array \p m_arrHazardPtr
+                Returns initialized object \p arr
+            */
+            template <size_t Count>
+            void alloc( HPArrayT<hazard_ptr_type, Count>& arr ) CDS_NOEXCEPT
+            {
+                assert( m_nTop >= Count );
+                m_nTop -= Count;
+                arr.m_arr = m_arrHazardPtr + m_nTop;
+            }
+
+            /// Frees hazard pointer array
+            /**
+                Frees the array of hazard pointers allocated by previous call \p this->alloc.
+            */
+            template <size_t Count>
+            void free( const HPArrayT<hazard_ptr_type, Count>& arr ) CDS_NOEXCEPT
+            {
+                assert( m_nTop + Count <= capacity());
+                for ( size_t i = m_nTop; i < m_nTop + Count; ++i )
+                    m_arrHazardPtr[ i ].clear();
+                m_nTop += Count;
+            }
+
+            /// Makes all HP free
+            void clear() CDS_NOEXCEPT
+            {
+                make_free();
+            }
+
+            /// Returns to i-th hazard pointer
+            atomic_hazard_ptr& operator []( size_t i ) CDS_NOEXCEPT
+            {
+                assert( i < capacity() );
+                return m_arrHazardPtr[i];
+            }
+
+        private:
+            //@cond
+            void make_free() CDS_NOEXCEPT
+            {
+                for ( size_t i = 0; i < capacity(); ++i )
+                    m_arrHazardPtr[ i ].clear();
+                m_nTop = capacity();
+            }
+
+            atomic_hazard_ptr * alloc_array( size_t nCapacity )
+            {
+                return allocator_impl().NewArray( nCapacity );
+            }
+            //@endcond
+        };
+
+    }}} // namespace gc::hzp::details
+}   // namespace cds
+//@endcond
+
+#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_ALLOC_H
diff --git a/cds/gc/hp/details/hp_fwd.h b/cds/gc/hp/details/hp_fwd.h
new file mode 100644 (file)
index 0000000..3183f47
--- /dev/null
@@ -0,0 +1,15 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HZP_DETAILS_HP_FWD_H
+#define __CDS_GC_HZP_DETAILS_HP_FWD_H
+
+namespace cds {
+    namespace gc { namespace hzp {
+
+        // forward declarations
+        class GarbageCollector;
+        class ThreadGC;
+    } }
+}
+
+#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_FWD_H
diff --git a/cds/gc/hp/details/hp_inline.h b/cds/gc/hp/details/hp_inline.h
new file mode 100644 (file)
index 0000000..dbb561c
--- /dev/null
@@ -0,0 +1,26 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HZP_DETAILS_HP_INLINE_H
+#define __CDS_GC_HZP_DETAILS_HP_INLINE_H
+
+namespace cds {
+    namespace gc{ namespace hzp { namespace details {
+
+        /************************************************************************/
+        /* INLINES                                                              */
+        /************************************************************************/
+        inline retired_vector::retired_vector( const cds::gc::hzp::GarbageCollector& HzpMgr )
+            : m_arr( HzpMgr.getMaxRetiredPtrCount() ),
+            m_nSize(0)
+        {}
+
+        inline HPRec::HPRec( const cds::gc::hzp::GarbageCollector& HzpMgr )
+            : m_hzp( HzpMgr.getHazardPointerCount() ),
+            m_arrRetired( HzpMgr )
+        {}
+
+    } } }    // namespace gc::hzp::details
+}    // namespace cds
+
+
+#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_INLINE_H
diff --git a/cds/gc/hp/details/hp_retired.h b/cds/gc/hp/details/hp_retired.h
new file mode 100644 (file)
index 0000000..6b6dd4a
--- /dev/null
@@ -0,0 +1,86 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HZP_DETAILS_HP_RETIRED_H
+#define __CDS_GC_HZP_DETAILS_HP_RETIRED_H
+
+#include <cds/gc/hp/details/hp_fwd.h>
+#include <cds/gc/hp/details/hp_type.h>
+
+#include <cds/details/bounded_array.h>
+
+namespace cds {
+    namespace gc{ namespace hzp { namespace details {
+
+        /// Retired pointer
+        typedef cds::gc::details::retired_ptr   retired_ptr;
+
+        /// Array of retired pointers
+        /**
+            The vector of retired pointer ready to delete.
+
+            The Hazard Pointer schema is build on thread-static arrays. For each HP-enabled thread the HP manager allocates
+            array of retired pointers. The array belongs to the thread: owner thread writes to the array, other threads
+            just read it.
+        */
+        class retired_vector {
+            /// Underlying vector implementation
+            typedef cds::details::bounded_array<retired_ptr>    retired_vector_impl;
+
+            retired_vector_impl m_arr   ;   ///< the array of retired pointers
+            size_t              m_nSize ;   ///< Current size of \p m_arr
+
+        public:
+            /// Iterator
+            typedef    retired_vector_impl::iterator    iterator;
+
+            /// Constructor
+            retired_vector( const cds::gc::hzp::GarbageCollector& HzpMgr )    ;    // inline
+            ~retired_vector()
+            {}
+
+            /// Vector capacity.
+            /**
+                The capacity is constant for any thread. It is defined by cds::gc::hzp::GarbageCollector.
+            */
+            size_t capacity() const     { return m_arr.capacity(); }
+
+            /// Current vector size (count of retired pointers in the vector)
+            size_t size() const         { return m_nSize; }
+
+            /// Set vector size. Uses internally
+            void size( size_t nSize )
+            {
+                assert( nSize <= capacity() );
+                m_nSize = nSize;
+            }
+
+            /// Pushes retired pointer to the vector
+            void push( const retired_ptr& p )
+            {
+                assert( m_nSize < capacity() );
+                m_arr[ m_nSize ] = p;
+                ++m_nSize;
+            }
+
+            /// Checks if the vector is full (size() == capacity() )
+            bool isFull() const
+            {
+                return m_nSize >= capacity();
+            }
+
+            /// Begin iterator
+            iterator    begin()    { return m_arr.begin(); }
+            /// End iterator
+            iterator    end()    { return m_arr.begin() +  m_nSize ; }
+
+            /// Clears the vector. After clearing, size() == 0
+            void clear()
+            {
+                m_nSize = 0;
+            }
+        };
+
+    } } }    // namespace gc::hzp::details
+}    // namespace cds
+
+#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_RETIRED_H
diff --git a/cds/gc/hp/details/hp_type.h b/cds/gc/hp/details/hp_type.h
new file mode 100644 (file)
index 0000000..7ff9ab3
--- /dev/null
@@ -0,0 +1,23 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HZP_DETAILS_HP_TYPE_H
+#define __CDS_GC_HZP_DETAILS_HP_TYPE_H
+
+#include <cds/gc/details/retired_ptr.h>
+
+namespace cds {
+    namespace gc {
+        namespace hzp {
+
+            /// Hazard pointer
+            typedef void *    hazard_pointer;
+
+            /// 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;
+        }
+    }
+}
+
+#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_TYPE_H
+
+
diff --git a/cds/gc/hp/hzp.h b/cds/gc/hp/hzp.h
new file mode 100644 (file)
index 0000000..7e29165
--- /dev/null
@@ -0,0 +1,655 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_HZP_HZP_H
+#define __CDS_GC_HZP_HZP_H
+
+#include <vector>
+#include <cds/cxx11_atomic.h>
+#include <cds/os/thread.h>
+#include <cds/gc/hp/details/hp_fwd.h>
+#include <cds/gc/hp/details/hp_alloc.h>
+#include <cds/gc/hp/details/hp_retired.h>
+
+#if CDS_COMPILER == CDS_COMPILER_MSVC
+#   pragma warning(push)
+    // warning C4251: 'cds::gc::hzp::GarbageCollector::m_pListHead' : class 'cds::cxx11_atomic::atomic<T>'
+    // needs to have dll-interface to be used by clients of class 'cds::gc::hzp::GarbageCollector'
+#   pragma warning(disable: 4251)
+#endif
+
+/*
+    Editions:
+        2007.12.24  khizmax Add statistics and CDS_GATHER_HAZARDPTR_STAT macro
+        2008.03.06  khizmax Refactoring: implementation of HazardPtrMgr is moved to hazardptr.cpp
+        2008.03.08  khizmax Remove HazardPtrMgr singleton. Now you must initialize/destroy HazardPtrMgr calling
+                            HazardPtrMgr::Construct / HazardPtrMgr::Destruct before use (usually in main() function).
+        2008.12.06  khizmax Refactoring. Changes class name, namespace hierarchy, all helper defs have been moved to details namespace
+        2010.01.27  khizmax Introducing memory order constraint
+*/
+
+namespace cds {
+    /**
+        @page cds_garbage_collectors_comparison GC comparison
+        @ingroup cds_garbage_collector
+
+        <table>
+            <tr>
+                <th>Feature</th>
+                <th>%cds::gc::HP</th>
+                <th>%cds::gc::PTB</th>
+            </tr>
+            <tr>
+                <td>Implementation quality</td>
+                <td>stable</td>
+                <td>stable</td>
+            </tr>
+            <tr>
+                <td>Performance rank (1 - slowest, 5 - fastest)</td>
+                <td>5</td>
+                <td>4</td>
+            </tr>
+            <tr>
+                <td>Max number of guarded (hazard) pointers per thread</td>
+                <td>limited (specifies in GC object ctor)</td>
+                <td>unlimited (dynamically allocated when needed)</td>
+            </tr>
+            <tr>
+                <td>Max number of retired pointers<sup>1</sup></td>
+                <td>bounded</td>
+                <td>bounded</td>
+           </tr>
+            <tr>
+                <td>Array of retired pointers</td>
+                <td>preallocated for each thread, limited in size</td>
+                <td>global for the entire process, unlimited (dynamically allocated when needed)</td>
+            </tr>
+            <tr>
+                <td>Support direct pointer to item of lock-free container (useful for iterators)</td>
+                <td>not supported</td>
+                <td>not supported</td>
+            </tr>
+        </table>
+
+        <sup>1</sup>Unbounded count of retired pointer means a possibility of memory exhaustion.
+    */
+
+    /// Different safe memory reclamation schemas (garbage collectors)
+    /** @ingroup cds_garbage_collector
+
+        This namespace specifies different safe memory reclamation (SMR) algorithms.
+        See \ref cds_garbage_collector "Garbage collectors"
+    */
+    namespace gc {
+
+    /// Michael's Hazard Pointers reclamation schema
+    /**
+    \par 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"
+
+
+        The cds::gc::hzp namespace and its members are internal representation of Hazard Pointer GC and should not be used directly.
+        Use cds::gc::HP class in your code.
+
+        Hazard Pointer garbage collector is a singleton. The main user-level part of Hazard Pointer schema is
+        GC class and its nested classes. Before use any HP-related class you must initialize HP garbage collector
+        by contructing cds::gc::HP object in beginning of your main().
+        See cds::gc::HP class for explanation.
+    */
+    namespace hzp {
+
+        namespace details {
+            /// Hazard pointer record of the thread
+            /**
+                The structure of type "single writer - multiple reader": only the owner thread may write to this structure
+                other threads have read-only access.
+            */
+            struct HPRec {
+                HPAllocator<hazard_pointer>    m_hzp        ; ///< array of hazard pointers. Implicit \ref CDS_DEFAULT_ALLOCATOR dependency
+                retired_vector            m_arrRetired ; ///< Retired pointer array
+
+                /// Ctor
+                HPRec( const cds::gc::hzp::GarbageCollector& HzpMgr ) ;    // inline
+                ~HPRec()
+                {}
+
+                /// Clears all hazard pointers
+                void clear()
+                {
+                    m_hzp.clear();
+                }
+            };
+        }    // namespace details
+
+        /// GarbageCollector::Scan phase strategy
+        /**
+            See GarbageCollector::Scan for explanation
+        */
+        enum scan_type {
+            classic,    ///< classic scan as described in Michael's works (see GarbageCollector::classic_scan)
+            inplace     ///< inplace scan without allocation (see GarbageCollector::inplace_scan)
+        };
+
+        /// Hazard Pointer singleton
+        /**
+            Safe memory reclamation schema by Michael "Hazard Pointers"
+
+        \par Sources:
+            \li [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
+            \li [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
+            \li [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
+
+        */
+        class CDS_EXPORT_API GarbageCollector
+        {
+        public:
+            typedef cds::atomicity::event_counter  event_counter   ;   ///< event counter type
+
+            /// Internal GC statistics
+            struct InternalState {
+                size_t              nHPCount                ;   ///< HP count per thread (const)
+                size_t              nMaxThreadCount         ;   ///< Max thread count (const)
+                size_t              nMaxRetiredPtrCount     ;   ///< Max retired pointer count per thread (const)
+                size_t              nHPRecSize              ;   ///< Size of HP record, bytes (const)
+
+                size_t              nHPRecAllocated         ;   ///< Count of HP record allocations
+                size_t              nHPRecUsed              ;   ///< Count of HP record used
+                size_t              nTotalRetiredPtrCount   ;   ///< Current total count of retired pointers
+                size_t              nRetiredPtrInFreeHPRecs ;   ///< Count of retired pointer in free (unused) HP records
+
+                event_counter::value_type   evcAllocHPRec   ;   ///< Count of HPRec allocations
+                event_counter::value_type   evcRetireHPRec  ;   ///< Count of HPRec retire events
+                event_counter::value_type   evcAllocNewHPRec;   ///< Count of new HPRec allocations from heap
+                event_counter::value_type   evcDeleteHPRec  ;   ///< Count of HPRec deletions
+
+                event_counter::value_type   evcScanCall     ;   ///< Count of Scan calling
+                event_counter::value_type   evcHelpScanCall ;   ///< Count of HelpScan calling
+                event_counter::value_type   evcScanFromHelpScan;///< Count of Scan calls from HelpScan
+
+                event_counter::value_type   evcDeletedNode  ;   ///< Count of deleting of retired objects
+                event_counter::value_type   evcDeferredNode ;   ///< Count of objects that cannot be deleted in Scan phase because of a hazard_pointer guards it
+            };
+
+            /// No GarbageCollector object is created
+            CDS_DECLARE_EXCEPTION( HZPManagerEmpty, "Global Hazard Pointer GarbageCollector is NULL" );
+
+            /// Not enough required Hazard Pointer count
+            CDS_DECLARE_EXCEPTION( HZPTooMany, "Not enough required Hazard Pointer count" );
+
+        private:
+            /// Internal GC statistics
+            struct Statistics {
+                event_counter  m_AllocHPRec            ;    ///< Count of HPRec allocations
+                event_counter  m_RetireHPRec            ;    ///< Count of HPRec retire events
+                event_counter  m_AllocNewHPRec            ;    ///< Count of new HPRec allocations from heap
+                event_counter  m_DeleteHPRec            ;    ///< Count of HPRec deletions
+
+                event_counter  m_ScanCallCount            ;    ///< Count of Scan calling
+                event_counter  m_HelpScanCallCount        ;    ///< Count of HelpScan calling
+                event_counter  m_CallScanFromHelpScan    ;    ///< Count of Scan calls from HelpScan
+
+                event_counter  m_DeletedNode            ;    ///< Count of retired objects deleting
+                event_counter  m_DeferredNode            ;    ///< Count of objects that cannot be deleted in Scan phase because of a hazard_pointer guards it
+            };
+
+            /// Internal list of cds::gc::hzp::details::HPRec
+            struct hplist_node: public details::HPRec
+            {
+                hplist_node *                       m_pNextNode ; ///< next hazard ptr record in list
+                atomics::atomic<OS::ThreadId>    m_idOwner   ; ///< Owner thread id; 0 - the record is free (not owned)
+                atomics::atomic<bool>            m_bFree     ; ///< true if record if free (not owned)
+
+                //@cond
+                hplist_node( const GarbageCollector& HzpMgr )
+                    : HPRec( HzpMgr ),
+                    m_pNextNode( nullptr ),
+                    m_idOwner( OS::c_NullThreadId ),
+                    m_bFree( true )
+                {}
+
+                ~hplist_node()
+                {
+                    assert( m_idOwner.load( atomics::memory_order_relaxed ) == OS::c_NullThreadId );
+                    assert( m_bFree.load(atomics::memory_order_relaxed) );
+                }
+                //@endcond
+            };
+
+            atomics::atomic<hplist_node *>   m_pListHead  ;  ///< Head of GC list
+
+            static GarbageCollector *    m_pHZPManager  ;   ///< GC instance pointer
+
+            Statistics              m_Stat              ;   ///< Internal statistics
+            bool                    m_bStatEnabled      ;   ///< true - statistics enabled
+
+            const size_t            m_nHazardPointerCount   ;   ///< max count of thread's hazard pointer
+            const size_t            m_nMaxThreadCount       ;   ///< max count of thread
+            const size_t            m_nMaxRetiredPtrCount   ;   ///< max count of retired ptr per thread
+            scan_type               m_nScanType             ;   ///< scan type (see \ref scan_type enum)
+
+
+        private:
+            /// Ctor
+            GarbageCollector(
+                size_t nHazardPtrCount = 0,         ///< Hazard pointer count per thread
+                size_t nMaxThreadCount = 0,         ///< Max count of thread
+                size_t nMaxRetiredPtrCount = 0,     ///< Capacity of the array of retired objects
+                scan_type nScanType = inplace       ///< Scan type (see \ref scan_type enum)
+            );
+
+            /// Dtor
+            ~GarbageCollector();
+
+            /// Allocate new HP record
+            hplist_node * NewHPRec();
+
+            /// Permanently deletes HPrecord \p pNode
+            /**
+                Caveat: for performance reason this function is defined as inline and cannot be called directly
+            */
+            void                DeleteHPRec( hplist_node * pNode );
+
+            /// Permanently deletes retired pointer \p p
+            /**
+                Caveat: for performance reason this function is defined as inline and cannot be called directly
+            */
+            void                DeletePtr( details::retired_ptr& p );
+
+            //@cond
+            void detachAllThread();
+            //@endcond
+
+        public:
+            /// Creates GarbageCollector singleton
+            /**
+                GC is the singleton. 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 - HP pointer count per thread. Usually it is small number (2-4) depending from
+                                     the data structure algorithms. By default, if \p nHazardPtrCount = 0,
+                                     the function uses maximum of HP count for CDS library.
+
+                \p nMaxThreadCount - max count of thread with using HP GC in your application. Default is 100.
+
+                \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
+                                    \p nHazardPtrCount * \p nMaxThreadCount.
+                                    Default is 2 * \p nHazardPtrCount * \p nMaxThreadCount.
+            */
+            static void    CDS_STDCALL Construct(
+                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
+                scan_type nScanType = inplace   ///< Scan type (see \ref scan_type enum)
+            );
+
+            /// Destroys global instance of GarbageCollector
+            /**
+                The parameter \p bDetachAll should be used carefully: if its value is \p true,
+                then the destroying GC automatically detaches all attached threads. This feature
+                can be useful when you have no control over the thread termination, for example,
+                when \p libcds is injected into existing external thread.
+            */
+            static void CDS_STDCALL Destruct(
+                bool bDetachAll = false     ///< Detach all threads
+            );
+
+            /// Returns pointer to GarbageCollector instance
+            static GarbageCollector&   instance()
+            {
+                if ( !m_pHZPManager )
+                    throw HZPManagerEmpty();
+                return *m_pHZPManager;
+            }
+
+            /// Checks if global GC object is constructed and may be used
+            static bool isUsed()
+            {
+                return m_pHZPManager != nullptr;
+            }
+
+            /// Returns max Hazard Pointer count defined in construction time
+            size_t            getHazardPointerCount() const        { return m_nHazardPointerCount; }
+
+            /// Returns max thread count defined in construction time
+            size_t            getMaxThreadCount() const             { return m_nMaxThreadCount; }
+
+            /// Returns max size of retired objects array. It is defined in construction time
+            size_t            getMaxRetiredPtrCount() const        { return m_nMaxRetiredPtrCount; }
+
+            // Internal statistics
+
+            /// Get internal statistics
+            InternalState& getInternalState(InternalState& stat) const;
+
+            /// Checks if internal statistics enabled
+            bool              isStatisticsEnabled() const { return m_bStatEnabled; }
+
+            /// Enables/disables internal statistics
+            bool              enableStatistics( bool bEnable )
+            {
+                bool bEnabled = m_bStatEnabled;
+                m_bStatEnabled = bEnable;
+                return bEnabled;
+            }
+
+            /// Checks that required hazard pointer count \p nRequiredCount is less or equal then max hazard pointer count
+            /**
+                If \p nRequiredCount > getHazardPointerCount() then the exception HZPTooMany is thrown
+            */
+            static void checkHPCount( unsigned int nRequiredCount )
+            {
+                if ( instance().getHazardPointerCount() < nRequiredCount )
+                    throw HZPTooMany();
+            }
+
+            /// Get current scan strategy
+            scan_type getScanType() const
+            {
+                return m_nScanType;
+            }
+
+            /// Set current scan strategy
+            /** @anchor hzp_gc_setScanType
+                Scan strategy changing is allowed on the fly.
+            */
+            void setScanType(
+                scan_type nScanType     ///< new scan strategy
+            )
+            {
+                m_nScanType = nScanType;
+            }
+
+        public:    // Internals for threads
+
+            /// Allocates Hazard Pointer GC record. For internal use only
+            details::HPRec * AllocateHPRec();
+
+            /// Free HP record. For internal use only
+            void RetireHPRec( details::HPRec * pRec );
+
+            /// The main garbage collecting function
+            /**
+                This function is called internally by ThreadGC object when upper bound of thread's list of reclaimed pointers
+                is reached.
+
+                There are the following scan algorithm:
+                - \ref hzp_gc_classic_scan "classic_scan" allocates memory for internal use
+                - \ref hzp_gc_inplace_scan "inplace_scan" does not allocate any memory
+
+                Use \ref hzp_gc_setScanType "setScanType" member function to setup appropriate scan algorithm.
+            */
+            void Scan( details::HPRec * pRec )
+            {
+                switch ( m_nScanType ) {
+                    case inplace:
+                        inplace_scan( pRec );
+                        break;
+                    default:
+                        assert(false)   ;   // Forgotten something?..
+                    case classic:
+                        classic_scan( pRec );
+                        break;
+                }
+            }
+
+            /// Helper scan routine
+            /**
+                The function guarantees that every node that is eligible for reuse is eventually freed, barring
+                thread failures. To do so, after executing Scan, a thread executes a HelpScan,
+                where it checks every HP record. If an HP record is inactive, the thread moves all "lost" reclaimed pointers
+                to thread's list of reclaimed pointers.
+
+                The function is called internally by Scan.
+            */
+            void HelpScan( details::HPRec * pThis );
+
+        protected:
+            /// Classic scan algorithm
+            /** @anchor hzp_gc_classic_scan
+                Classical scan algorithm as described in Michael's paper.
+
+                A scan includes four stages. The first stage involves scanning the array HP for non-null values.
+                Whenever a non-null value is encountered, it is inserted in a local list of currently protected pointer.
+                Only stage 1 accesses shared variables. The following stages operate only on private variables.
+
+                The second stage of a scan involves sorting local list of protected pointers to allow
+                binary search in the third stage.
+
+                The third stage of a scan involves checking each reclaimed node
+                against the pointers in local list of protected pointers. If the binary search yields
+                no match, the node is freed. Otherwise, it cannot be deleted now and must kept in thread's list
+                of reclaimed pointers.
+
+                The forth stage prepares new thread's private list of reclaimed pointers
+                that could not be freed during the current scan, where they remain until the next scan.
+
+                This algorithm allocates memory for internal HP array.
+
+                This function is called internally by ThreadGC object when upper bound of thread's list of reclaimed pointers
+                is reached.
+            */
+            void classic_scan( details::HPRec * pRec );
+
+            /// In-place scan algorithm
+            /** @anchor hzp_gc_inplace_scan
+                Unlike the \ref hzp_gc_classic_scan "classic_scan" algorithm, \p inplace_scan does not allocate any memory.
+                All operations are performed in-place.
+            */
+            void inplace_scan( details::HPRec * pRec );
+        };
+
+        /// Thread's hazard pointer manager
+        /**
+            To use Hazard Pointer reclamation schema each thread object must be linked with the object of ThreadGC class
+            that interacts with GarbageCollector global object. The linkage is performed by calling \ref cds_threading "cds::threading::Manager::attachThread()"
+            on the start of each thread that uses HP GC. Before terminating the thread linked to HP GC it is necessary to call
+            \ref cds_threading "cds::threading::Manager::detachThread()".
+        */
+        class ThreadGC
+        {
+            GarbageCollector&   m_HzpManager    ; ///< Hazard Pointer GC singleton
+            details::HPRec *    m_pHzpRec       ; ///< Pointer to thread's HZP record
+
+        public:
+            /// Default constructor
+            ThreadGC()
+                : m_HzpManager( GarbageCollector::instance() ),
+                m_pHzpRec( nullptr )
+            {}
+
+            /// The object is not copy-constructible
+            ThreadGC( ThreadGC const& ) = delete;
+
+            ~ThreadGC()
+            {
+                fini();
+            }
+
+            /// Checks if thread GC is initialized
+            bool    isInitialized() const   { return m_pHzpRec != nullptr; }
+
+            /// Initialization. Repeat call is available
+            void init()
+            {
+                if ( !m_pHzpRec )
+                    m_pHzpRec = m_HzpManager.AllocateHPRec();
+            }
+
+            /// Finalization. Repeat call is available
+            void fini()
+            {
+                if ( m_pHzpRec ) {
+                    details::HPRec * pRec = m_pHzpRec;
+                    m_pHzpRec = nullptr;
+                    m_HzpManager.RetireHPRec( pRec );
+                }
+            }
+
+            /// Initializes HP guard \p guard
+            details::HPGuard& allocGuard()
+            {
+                assert( m_pHzpRec );
+                return m_pHzpRec->m_hzp.alloc();
+            }
+
+            /// Frees HP guard \p guard
+            void freeGuard( details::HPGuard& guard )
+            {
+                assert( m_pHzpRec );
+                m_pHzpRec->m_hzp.free( guard );
+            }
+
+            /// Initializes HP guard array \p arr
+            template <size_t Count>
+            void allocGuard( details::HPArray<Count>& arr )
+            {
+                assert( m_pHzpRec );
+                m_pHzpRec->m_hzp.alloc( arr );
+            }
+
+            /// Frees HP guard array \p arr
+            template <size_t Count>
+            void freeGuard( details::HPArray<Count>& arr )
+            {
+                assert( m_pHzpRec );
+                m_pHzpRec->m_hzp.free( arr );
+            }
+
+            /// Places retired pointer \p and its deleter \p pFunc into thread's array of retired pointer for deferred reclamation
+            template <typename T>
+            void retirePtr( T * p, void (* pFunc)(T *) )
+            {
+                retirePtr( details::retired_ptr( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ) ) );
+            }
+
+            /// Places retired pointer \p into thread's array of retired pointer for deferred reclamation
+            void retirePtr( const details::retired_ptr& p )
+            {
+                m_pHzpRec->m_arrRetired.push( p );
+
+                if ( m_pHzpRec->m_arrRetired.isFull() ) {
+                    // Max of retired pointer count is reached. Do scan
+                    scan();
+                }
+            }
+
+            //@cond
+            void scan()
+            {
+                m_HzpManager.Scan( m_pHzpRec );
+                m_HzpManager.HelpScan( m_pHzpRec );
+            }
+            //@endcond
+        };
+
+        /// Auto HPGuard.
+        /**
+            This class encapsulates Hazard Pointer guard to protect a pointer against deletion .
+            It allocates one HP from thread's HP array in constructor and free the HP allocated in destruction time.
+        */
+        class AutoHPGuard
+        {
+            //@cond
+            details::HPGuard&   m_hp    ; ///< Hazard pointer guarded
+            ThreadGC&           m_gc    ; ///< Thread GC
+            //@endcond
+
+        public:
+            typedef details::HPGuard::hazard_ptr hazard_ptr ;  ///< Hazard pointer type
+        public:
+            /// Allocates HP guard from \p gc
+            AutoHPGuard( ThreadGC& gc )
+                : m_hp( gc.allocGuard() )
+                , m_gc( gc )
+            {}
+
+            /// Allocates HP guard from \p gc and protects the pointer \p p of type \p T
+            template <typename T>
+            AutoHPGuard( ThreadGC& gc, T * p  )
+                : m_hp( gc.allocGuard() )
+                , m_gc( gc )
+            {
+                m_hp = p;
+            }
+
+            /// Frees HP guard. The pointer guarded may be deleted after this.
+            ~AutoHPGuard()
+            {
+                m_gc.freeGuard( m_hp );
+            }
+
+            /// Returns thread GC
+            ThreadGC&    getGC() const
+            {
+                return m_gc;
+            }
+
+            /// Protects the pointer \p p against reclamation (guards the pointer).
+            template <typename T>
+            T * operator =( T * p )
+            {
+                return m_hp = p;
+            }
+
+            //@cond
+            std::nullptr_t operator =(std::nullptr_t)
+            {
+                return m_hp = nullptr;
+            }
+
+            hazard_ptr get() const
+            {
+                return m_hp;
+            }
+            //@endcond
+        };
+
+        /// Auto-managed array of hazard pointers
+        /**
+            This class is wrapper around cds::gc::hzp::details::HPArray class.
+            \p Count is the size of HP array
+        */
+        template <size_t Count>
+        class AutoHPArray: public details::HPArray<Count>
+        {
+            ThreadGC&    m_mgr    ;    ///< Thread GC
+
+        public:
+            /// Rebind array for other size \p COUNT2
+            template <size_t Count2>
+            struct rebind {
+                typedef AutoHPArray<Count2>  other   ;   ///< rebinding result
+            };
+
+        public:
+            /// Allocates array of HP guard from \p mgr
+            AutoHPArray( ThreadGC& mgr )
+                : m_mgr( mgr )
+            {
+                mgr.allocGuard( *this );
+            }
+
+            /// Frees array of HP guard
+            ~AutoHPArray()
+            {
+                m_mgr.freeGuard( *this );
+            }
+
+            /// Returns thread GC
+            ThreadGC&    getGC() const { return m_mgr; }
+        };
+
+    }   // namespace hzp
+}}  // namespace cds::gc
+
+// Inlines
+#include <cds/gc/hp/details/hp_inline.h>
+
+#if CDS_COMPILER == CDS_COMPILER_MSVC
+#   pragma warning(pop)
+#endif
+
+#endif  // #ifndef __CDS_GC_HZP_HZP_H
index 2b92a5408129252d479367d128cbab1d19c344b7..76f0aba2d2fa1efe0bcfe00a271336d3ba140a6b 100644 (file)
@@ -4,7 +4,7 @@
 #define __CDS_GC_HP_DECL_H
 
 #include <stdexcept>    // overflow_error
-#include <cds/gc/hzp/hzp.h>
+#include <cds/gc/hp/hp.h>
 #include <cds/details/marked_ptr.h>
 
 namespace cds { namespace gc {
diff --git a/cds/gc/hzp/details/hp_alloc.h b/cds/gc/hzp/details/hp_alloc.h
deleted file mode 100644 (file)
index 83a8772..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HZP_DETAILS_HP_ALLOC_H
-#define __CDS_GC_HZP_DETAILS_HP_ALLOC_H
-
-#include <cds/cxx11_atomic.h>
-#include <cds/details/allocator.h>
-#include <cds/gc/hzp/details/hp_fwd.h>
-#include <cds/gc/hzp/details/hp_type.h>
-
-//@cond
-namespace cds {
-    namespace gc { namespace hzp {
-    /// Hazard Pointer schema implementation details
-    namespace details {
-
-        /// Hazard pointer guard
-        /**
-            It is unsafe to use this class directly.
-            Instead, the AutoHPGuard class should be used.
-
-            Template parameter:
-                \li HazardPointer - type of hazard pointer. It is \ref hazard_pointer for Michael's Hazard Pointer reclamation schema
-        */
-        template <typename HazardPointer>
-        class HPGuardT: protected atomics::atomic<HazardPointer>
-        {
-        public:
-            typedef HazardPointer   hazard_ptr ;    ///< Hazard pointer type
-        private:
-            //@cond
-            typedef atomics::atomic<hazard_ptr>  base_class;
-            //@endcond
-
-        protected:
-            //@cond
-            template <typename OtherHazardPointer, class Allocator> friend class HPAllocator;
-            //@endcond
-
-        public:
-            HPGuardT() CDS_NOEXCEPT
-                : base_class( nullptr )
-            {}
-            ~HPGuardT() CDS_NOEXCEPT
-            {}
-
-            /// Sets HP value. Guards pointer \p p from reclamation.
-            /**
-                Storing has release semantics.
-            */
-            template <typename T>
-            T * operator =( T * p ) CDS_NOEXCEPT
-            {
-                // We use atomic store with explicit memory order because other threads may read this hazard pointer concurrently
-                base_class::store( reinterpret_cast<hazard_ptr>(p), atomics::memory_order_release );
-                return p;
-            }
-
-            //@cond
-            std::nullptr_t operator=( std::nullptr_t ) CDS_NOEXCEPT
-            {
-                clear();
-                return nullptr;
-            }
-            //@endcond
-
-            /// Returns current value of hazard pointer
-            /**
-                Loading has acquire semantics
-            */
-            operator hazard_ptr() const CDS_NOEXCEPT
-            {
-                return get();
-            }
-
-            /// Returns current value of hazard pointer
-            /**
-                Loading has acquire semantics
-            */
-            hazard_ptr get() const CDS_NOEXCEPT
-            {
-                return base_class::load( atomics::memory_order_acquire );
-            }
-
-            /// Clears HP
-            /**
-                Clearing has relaxed semantics.
-            */
-            void clear() CDS_NOEXCEPT
-            {
-                // memory order is not necessary here
-                base_class::store( nullptr, atomics::memory_order_relaxed );
-                //CDS_COMPILER_RW_BARRIER;
-            }
-        };
-
-        /// Specialization of HPGuardT for hazard_pointer type
-        typedef HPGuardT<hazard_pointer> HPGuard;
-
-        /// Array of hazard pointers.
-        /**
-            Array of hazard-pointer. Placing a pointer into this array guards the pointer against reclamation.
-            Template parameter \p Count defines the size of hazard pointer array. \p Count parameter should not exceed
-            GarbageCollector::getHazardPointerCount().
-
-            It is unsafe to use this class directly. Instead, the AutoHPArray should be used.
-
-            While creating the object of HPArray class an array of size \p Count of hazard pointers is reserved by
-            the HP Manager of current thread. The object's destructor cleans all of reserved hazard pointer and
-            returns reserved HP to the HP pool of ThreadGC.
-
-            Usually, it is not necessary to create an object of this class. The object of class ThreadGC contains
-            the HPArray object and implements interface for HP setting and freeing.
-
-            Template parameter:
-                \li HazardPointer - type of hazard pointer. It is hazard_pointer usually
-                \li Count - capacity of array
-
-        */
-        template <typename HazardPointer, size_t Count>
-        class HPArrayT
-        {
-        public:
-            typedef HazardPointer   hazard_ptr_type ;   ///< Hazard pointer type
-            typedef HPGuardT<hazard_ptr_type>   atomic_hazard_ptr    ; ///< Element type of the array
-            static const size_t c_nCapacity = Count ;   ///< Capacity of the array
-
-        private:
-            //@cond
-            atomic_hazard_ptr *     m_arr               ;   ///< Hazard pointer array of size = \p Count
-            template <typename OtherHazardPointer, class Allocator> friend class HPAllocator;
-            //@endcond
-
-        public:
-            /// Constructs uninitialized array.
-            HPArrayT() CDS_NOEXCEPT
-            {}
-
-            /// Destructs object
-            ~HPArrayT() CDS_NOEXCEPT
-            {}
-
-            /// Returns max count of hazard pointer for this array
-            CDS_CONSTEXPR size_t capacity() const
-            {
-                return c_nCapacity;
-            }
-
-            /// Set hazard pointer \p nIndex. 0 <= \p nIndex < \p Count
-            void set( size_t nIndex, hazard_ptr_type hzPtr ) CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                m_arr[nIndex] = hzPtr;
-            }
-
-            /// Returns reference to hazard pointer of index \p nIndex (0 <= \p nIndex < \p Count)
-            atomic_hazard_ptr& operator []( size_t nIndex ) CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                return m_arr[nIndex];
-            }
-
-            /// Returns reference to hazard pointer of index \p nIndex (0 <= \p nIndex < \p Count) [const version]
-            atomic_hazard_ptr& operator []( size_t nIndex ) const CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                return m_arr[nIndex];
-            }
-
-            /// Clears (sets to \p nullptr) hazard pointer \p nIndex
-            void clear( size_t nIndex ) CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                m_arr[ nIndex ].clear();
-            }
-        };
-
-        /// Specialization of HPArrayT class for hazard_pointer type
-        template <size_t Count> using HPArray = HPArrayT<hazard_pointer, Count >;
-
-        /// Allocator of hazard pointers for the thread
-        /**
-            The hazard pointer array is the free-list of unused hazard pointer for the thread.
-            The array is managed as a stack.
-            The max size (capacity) of array is defined at ctor time and cannot be changed during object's lifetime
-
-            Each allocator object is thread-private.
-
-            Template parameters:
-                \li HazardPointer - type of hazard pointer (hazard_pointer usually)
-                \li Allocator - memory allocator class, default is \ref CDS_DEFAULT_ALLOCATOR
-
-            This helper class should not be used directly.
-        */
-        template < typename HazardPointer, class Allocator = CDS_DEFAULT_ALLOCATOR >
-        class HPAllocator
-        {
-        public:
-            typedef HazardPointer               hazard_ptr_type     ;   ///< type of hazard pointer
-            typedef HPGuardT<hazard_ptr_type>   atomic_hazard_ptr   ;   ///< Atomic hazard pointer type
-            typedef Allocator                   allocator_type      ;   ///< allocator type
-
-        private:
-            //@cond
-            typedef cds::details::Allocator< atomic_hazard_ptr, allocator_type > allocator_impl;
-
-            atomic_hazard_ptr * m_arrHazardPtr  ;   ///< Array of hazard pointers
-            size_t              m_nTop          ;   ///< The top of stack
-            const size_t        m_nCapacity     ;   ///< Array capacity
-
-            //@endcond
-
-        public:
-            /// Default ctor
-            explicit HPAllocator(
-                size_t  nCapacity            ///< max count of hazard pointer per thread
-                )
-                : m_arrHazardPtr( alloc_array( nCapacity ) )
-                , m_nCapacity( nCapacity )
-            {
-                make_free();
-            }
-
-            /// Dtor
-            ~HPAllocator()
-            {
-                allocator_impl().Delete( m_arrHazardPtr, capacity() );
-            }
-
-            /// Get capacity of array
-            size_t capacity() const CDS_NOEXCEPT
-            {
-                return m_nCapacity;
-            }
-
-            /// Get size of array. The size is equal to the capacity of array
-            size_t size() const CDS_NOEXCEPT
-            {
-                return capacity();
-            }
-
-            /// Checks if all items are allocated
-            bool isFull() const CDS_NOEXCEPT
-            {
-                return m_nTop == 0;
-            }
-
-            /// Allocates hazard pointer
-            atomic_hazard_ptr& alloc() CDS_NOEXCEPT
-            {
-                assert( m_nTop > 0 );
-                --m_nTop;
-                return m_arrHazardPtr[m_nTop];
-            }
-
-            /// Frees previously allocated hazard pointer
-            void free( atomic_hazard_ptr& hp ) CDS_NOEXCEPT
-            {
-                assert( m_nTop < capacity() );
-                hp.clear();
-                ++m_nTop;
-                CDS_COMPILER_RW_BARRIER ;   // ???
-            }
-
-            /// Allocates hazard pointers array
-            /**
-                Allocates \p Count hazard pointers from array \p m_arrHazardPtr
-                Returns initialized object \p arr
-            */
-            template <size_t Count>
-            void alloc( HPArrayT<hazard_ptr_type, Count>& arr ) CDS_NOEXCEPT
-            {
-                assert( m_nTop >= Count );
-                m_nTop -= Count;
-                arr.m_arr = m_arrHazardPtr + m_nTop;
-            }
-
-            /// Frees hazard pointer array
-            /**
-                Frees the array of hazard pointers allocated by previous call \p this->alloc.
-            */
-            template <size_t Count>
-            void free( const HPArrayT<hazard_ptr_type, Count>& arr ) CDS_NOEXCEPT
-            {
-                assert( m_nTop + Count <= capacity());
-                for ( size_t i = m_nTop; i < m_nTop + Count; ++i )
-                    m_arrHazardPtr[ i ].clear();
-                m_nTop += Count;
-            }
-
-            /// Makes all HP free
-            void clear() CDS_NOEXCEPT
-            {
-                make_free();
-            }
-
-            /// Returns to i-th hazard pointer
-            atomic_hazard_ptr& operator []( size_t i ) CDS_NOEXCEPT
-            {
-                assert( i < capacity() );
-                return m_arrHazardPtr[i];
-            }
-
-        private:
-            //@cond
-            void make_free() CDS_NOEXCEPT
-            {
-                for ( size_t i = 0; i < capacity(); ++i )
-                    m_arrHazardPtr[ i ].clear();
-                m_nTop = capacity();
-            }
-
-            atomic_hazard_ptr * alloc_array( size_t nCapacity )
-            {
-                return allocator_impl().NewArray( nCapacity );
-            }
-            //@endcond
-        };
-
-    }}} // namespace gc::hzp::details
-}   // namespace cds
-//@endcond
-
-#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_ALLOC_H
diff --git a/cds/gc/hzp/details/hp_fwd.h b/cds/gc/hzp/details/hp_fwd.h
deleted file mode 100644 (file)
index 3183f47..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HZP_DETAILS_HP_FWD_H
-#define __CDS_GC_HZP_DETAILS_HP_FWD_H
-
-namespace cds {
-    namespace gc { namespace hzp {
-
-        // forward declarations
-        class GarbageCollector;
-        class ThreadGC;
-    } }
-}
-
-#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_FWD_H
diff --git a/cds/gc/hzp/details/hp_inline.h b/cds/gc/hzp/details/hp_inline.h
deleted file mode 100644 (file)
index dbb561c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HZP_DETAILS_HP_INLINE_H
-#define __CDS_GC_HZP_DETAILS_HP_INLINE_H
-
-namespace cds {
-    namespace gc{ namespace hzp { namespace details {
-
-        /************************************************************************/
-        /* INLINES                                                              */
-        /************************************************************************/
-        inline retired_vector::retired_vector( const cds::gc::hzp::GarbageCollector& HzpMgr )
-            : m_arr( HzpMgr.getMaxRetiredPtrCount() ),
-            m_nSize(0)
-        {}
-
-        inline HPRec::HPRec( const cds::gc::hzp::GarbageCollector& HzpMgr )
-            : m_hzp( HzpMgr.getHazardPointerCount() ),
-            m_arrRetired( HzpMgr )
-        {}
-
-    } } }    // namespace gc::hzp::details
-}    // namespace cds
-
-
-#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_INLINE_H
diff --git a/cds/gc/hzp/details/hp_retired.h b/cds/gc/hzp/details/hp_retired.h
deleted file mode 100644 (file)
index fc32ec6..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HZP_DETAILS_HP_RETIRED_H
-#define __CDS_GC_HZP_DETAILS_HP_RETIRED_H
-
-#include <cds/gc/hzp/details/hp_fwd.h>
-#include <cds/gc/hzp/details/hp_type.h>
-
-#include <cds/details/bounded_array.h>
-
-namespace cds {
-    namespace gc{ namespace hzp { namespace details {
-
-        /// Retired pointer
-        typedef cds::gc::details::retired_ptr   retired_ptr;
-
-        /// Array of retired pointers
-        /**
-            The vector of retired pointer ready to delete.
-
-            The Hazard Pointer schema is build on thread-static arrays. For each HP-enabled thread the HP manager allocates
-            array of retired pointers. The array belongs to the thread: owner thread writes to the array, other threads
-            just read it.
-        */
-        class retired_vector {
-            /// Underlying vector implementation
-            typedef cds::details::bounded_array<retired_ptr>    retired_vector_impl;
-
-            retired_vector_impl m_arr   ;   ///< the array of retired pointers
-            size_t              m_nSize ;   ///< Current size of \p m_arr
-
-        public:
-            /// Iterator
-            typedef    retired_vector_impl::iterator    iterator;
-
-            /// Constructor
-            retired_vector( const cds::gc::hzp::GarbageCollector& HzpMgr )    ;    // inline
-            ~retired_vector()
-            {}
-
-            /// Vector capacity.
-            /**
-                The capacity is constant for any thread. It is defined by cds::gc::hzp::GarbageCollector.
-            */
-            size_t capacity() const     { return m_arr.capacity(); }
-
-            /// Current vector size (count of retired pointers in the vector)
-            size_t size() const         { return m_nSize; }
-
-            /// Set vector size. Uses internally
-            void size( size_t nSize )
-            {
-                assert( nSize <= capacity() );
-                m_nSize = nSize;
-            }
-
-            /// Pushes retired pointer to the vector
-            void push( const retired_ptr& p )
-            {
-                assert( m_nSize < capacity() );
-                m_arr[ m_nSize ] = p;
-                ++m_nSize;
-            }
-
-            /// Checks if the vector is full (size() == capacity() )
-            bool isFull() const
-            {
-                return m_nSize >= capacity();
-            }
-
-            /// Begin iterator
-            iterator    begin()    { return m_arr.begin(); }
-            /// End iterator
-            iterator    end()    { return m_arr.begin() +  m_nSize ; }
-
-            /// Clears the vector. After clearing, size() == 0
-            void clear()
-            {
-                m_nSize = 0;
-            }
-        };
-
-    } } }    // namespace gc::hzp::details
-}    // namespace cds
-
-#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_RETIRED_H
diff --git a/cds/gc/hzp/details/hp_type.h b/cds/gc/hzp/details/hp_type.h
deleted file mode 100644 (file)
index 7ff9ab3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HZP_DETAILS_HP_TYPE_H
-#define __CDS_GC_HZP_DETAILS_HP_TYPE_H
-
-#include <cds/gc/details/retired_ptr.h>
-
-namespace cds {
-    namespace gc {
-        namespace hzp {
-
-            /// Hazard pointer
-            typedef void *    hazard_pointer;
-
-            /// 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;
-        }
-    }
-}
-
-#endif // #ifndef __CDS_GC_HZP_DETAILS_HP_TYPE_H
-
-
diff --git a/cds/gc/hzp/hzp.h b/cds/gc/hzp/hzp.h
deleted file mode 100644 (file)
index b92a5a4..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HZP_HZP_H
-#define __CDS_GC_HZP_HZP_H
-
-#include <vector>
-#include <cds/cxx11_atomic.h>
-#include <cds/os/thread.h>
-#include <cds/gc/hzp/details/hp_fwd.h>
-#include <cds/gc/hzp/details/hp_alloc.h>
-#include <cds/gc/hzp/details/hp_retired.h>
-
-#if CDS_COMPILER == CDS_COMPILER_MSVC
-#   pragma warning(push)
-    // warning C4251: 'cds::gc::hzp::GarbageCollector::m_pListHead' : class 'cds::cxx11_atomic::atomic<T>'
-    // needs to have dll-interface to be used by clients of class 'cds::gc::hzp::GarbageCollector'
-#   pragma warning(disable: 4251)
-#endif
-
-/*
-    Editions:
-        2007.12.24  khizmax Add statistics and CDS_GATHER_HAZARDPTR_STAT macro
-        2008.03.06  khizmax Refactoring: implementation of HazardPtrMgr is moved to hazardptr.cpp
-        2008.03.08  khizmax Remove HazardPtrMgr singleton. Now you must initialize/destroy HazardPtrMgr calling
-                            HazardPtrMgr::Construct / HazardPtrMgr::Destruct before use (usually in main() function).
-        2008.12.06  khizmax Refactoring. Changes class name, namespace hierarchy, all helper defs have been moved to details namespace
-        2010.01.27  khizmax Introducing memory order constraint
-*/
-
-namespace cds {
-    /**
-        @page cds_garbage_collectors_comparison GC comparison
-        @ingroup cds_garbage_collector
-
-        <table>
-            <tr>
-                <th>Feature</th>
-                <th>%cds::gc::HP</th>
-                <th>%cds::gc::PTB</th>
-            </tr>
-            <tr>
-                <td>Implementation quality</td>
-                <td>stable</td>
-                <td>stable</td>
-            </tr>
-            <tr>
-                <td>Performance rank (1 - slowest, 5 - fastest)</td>
-                <td>5</td>
-                <td>4</td>
-            </tr>
-            <tr>
-                <td>Max number of guarded (hazard) pointers per thread</td>
-                <td>limited (specifies in GC object ctor)</td>
-                <td>unlimited (dynamically allocated when needed)</td>
-            </tr>
-            <tr>
-                <td>Max number of retired pointers<sup>1</sup></td>
-                <td>bounded</td>
-                <td>bounded</td>
-           </tr>
-            <tr>
-                <td>Array of retired pointers</td>
-                <td>preallocated for each thread, limited in size</td>
-                <td>global for the entire process, unlimited (dynamically allocated when needed)</td>
-            </tr>
-            <tr>
-                <td>Support direct pointer to item of lock-free container (useful for iterators)</td>
-                <td>not supported</td>
-                <td>not supported</td>
-            </tr>
-        </table>
-
-        <sup>1</sup>Unbounded count of retired pointer means a possibility of memory exhaustion.
-    */
-
-    /// Different safe memory reclamation schemas (garbage collectors)
-    /** @ingroup cds_garbage_collector
-
-        This namespace specifies different safe memory reclamation (SMR) algorithms.
-        See \ref cds_garbage_collector "Garbage collectors"
-    */
-    namespace gc {
-
-    /// Michael's Hazard Pointers reclamation schema
-    /**
-    \par 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"
-
-
-        The cds::gc::hzp namespace and its members are internal representation of Hazard Pointer GC and should not be used directly.
-        Use cds::gc::HP class in your code.
-
-        Hazard Pointer garbage collector is a singleton. The main user-level part of Hazard Pointer schema is
-        GC class and its nested classes. Before use any HP-related class you must initialize HP garbage collector
-        by contructing cds::gc::HP object in beginning of your main().
-        See cds::gc::HP class for explanation.
-    */
-    namespace hzp {
-
-        namespace details {
-            /// Hazard pointer record of the thread
-            /**
-                The structure of type "single writer - multiple reader": only the owner thread may write to this structure
-                other threads have read-only access.
-            */
-            struct HPRec {
-                HPAllocator<hazard_pointer>    m_hzp        ; ///< array of hazard pointers. Implicit \ref CDS_DEFAULT_ALLOCATOR dependency
-                retired_vector            m_arrRetired ; ///< Retired pointer array
-
-                /// Ctor
-                HPRec( const cds::gc::hzp::GarbageCollector& HzpMgr ) ;    // inline
-                ~HPRec()
-                {}
-
-                /// Clears all hazard pointers
-                void clear()
-                {
-                    m_hzp.clear();
-                }
-            };
-        }    // namespace details
-
-        /// GarbageCollector::Scan phase strategy
-        /**
-            See GarbageCollector::Scan for explanation
-        */
-        enum scan_type {
-            classic,    ///< classic scan as described in Michael's works (see GarbageCollector::classic_scan)
-            inplace     ///< inplace scan without allocation (see GarbageCollector::inplace_scan)
-        };
-
-        /// Hazard Pointer singleton
-        /**
-            Safe memory reclamation schema by Michael "Hazard Pointers"
-
-        \par Sources:
-            \li [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
-            \li [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
-            \li [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
-
-        */
-        class CDS_EXPORT_API GarbageCollector
-        {
-        public:
-            typedef cds::atomicity::event_counter  event_counter   ;   ///< event counter type
-
-            /// Internal GC statistics
-            struct InternalState {
-                size_t              nHPCount                ;   ///< HP count per thread (const)
-                size_t              nMaxThreadCount         ;   ///< Max thread count (const)
-                size_t              nMaxRetiredPtrCount     ;   ///< Max retired pointer count per thread (const)
-                size_t              nHPRecSize              ;   ///< Size of HP record, bytes (const)
-
-                size_t              nHPRecAllocated         ;   ///< Count of HP record allocations
-                size_t              nHPRecUsed              ;   ///< Count of HP record used
-                size_t              nTotalRetiredPtrCount   ;   ///< Current total count of retired pointers
-                size_t              nRetiredPtrInFreeHPRecs ;   ///< Count of retired pointer in free (unused) HP records
-
-                event_counter::value_type   evcAllocHPRec   ;   ///< Count of HPRec allocations
-                event_counter::value_type   evcRetireHPRec  ;   ///< Count of HPRec retire events
-                event_counter::value_type   evcAllocNewHPRec;   ///< Count of new HPRec allocations from heap
-                event_counter::value_type   evcDeleteHPRec  ;   ///< Count of HPRec deletions
-
-                event_counter::value_type   evcScanCall     ;   ///< Count of Scan calling
-                event_counter::value_type   evcHelpScanCall ;   ///< Count of HelpScan calling
-                event_counter::value_type   evcScanFromHelpScan;///< Count of Scan calls from HelpScan
-
-                event_counter::value_type   evcDeletedNode  ;   ///< Count of deleting of retired objects
-                event_counter::value_type   evcDeferredNode ;   ///< Count of objects that cannot be deleted in Scan phase because of a hazard_pointer guards it
-            };
-
-            /// No GarbageCollector object is created
-            CDS_DECLARE_EXCEPTION( HZPManagerEmpty, "Global Hazard Pointer GarbageCollector is NULL" );
-
-            /// Not enough required Hazard Pointer count
-            CDS_DECLARE_EXCEPTION( HZPTooMany, "Not enough required Hazard Pointer count" );
-
-        private:
-            /// Internal GC statistics
-            struct Statistics {
-                event_counter  m_AllocHPRec            ;    ///< Count of HPRec allocations
-                event_counter  m_RetireHPRec            ;    ///< Count of HPRec retire events
-                event_counter  m_AllocNewHPRec            ;    ///< Count of new HPRec allocations from heap
-                event_counter  m_DeleteHPRec            ;    ///< Count of HPRec deletions
-
-                event_counter  m_ScanCallCount            ;    ///< Count of Scan calling
-                event_counter  m_HelpScanCallCount        ;    ///< Count of HelpScan calling
-                event_counter  m_CallScanFromHelpScan    ;    ///< Count of Scan calls from HelpScan
-
-                event_counter  m_DeletedNode            ;    ///< Count of retired objects deleting
-                event_counter  m_DeferredNode            ;    ///< Count of objects that cannot be deleted in Scan phase because of a hazard_pointer guards it
-            };
-
-            /// Internal list of cds::gc::hzp::details::HPRec
-            struct hplist_node: public details::HPRec
-            {
-                hplist_node *                       m_pNextNode ; ///< next hazard ptr record in list
-                atomics::atomic<OS::ThreadId>    m_idOwner   ; ///< Owner thread id; 0 - the record is free (not owned)
-                atomics::atomic<bool>            m_bFree     ; ///< true if record if free (not owned)
-
-                //@cond
-                hplist_node( const GarbageCollector& HzpMgr )
-                    : HPRec( HzpMgr ),
-                    m_pNextNode( nullptr ),
-                    m_idOwner( OS::c_NullThreadId ),
-                    m_bFree( true )
-                {}
-
-                ~hplist_node()
-                {
-                    assert( m_idOwner.load( atomics::memory_order_relaxed ) == OS::c_NullThreadId );
-                    assert( m_bFree.load(atomics::memory_order_relaxed) );
-                }
-                //@endcond
-            };
-
-            atomics::atomic<hplist_node *>   m_pListHead  ;  ///< Head of GC list
-
-            static GarbageCollector *    m_pHZPManager  ;   ///< GC instance pointer
-
-            Statistics              m_Stat              ;   ///< Internal statistics
-            bool                    m_bStatEnabled      ;   ///< true - statistics enabled
-
-            const size_t            m_nHazardPointerCount   ;   ///< max count of thread's hazard pointer
-            const size_t            m_nMaxThreadCount       ;   ///< max count of thread
-            const size_t            m_nMaxRetiredPtrCount   ;   ///< max count of retired ptr per thread
-            scan_type               m_nScanType             ;   ///< scan type (see \ref scan_type enum)
-
-
-        private:
-            /// Ctor
-            GarbageCollector(
-                size_t nHazardPtrCount = 0,         ///< Hazard pointer count per thread
-                size_t nMaxThreadCount = 0,         ///< Max count of thread
-                size_t nMaxRetiredPtrCount = 0,     ///< Capacity of the array of retired objects
-                scan_type nScanType = inplace       ///< Scan type (see \ref scan_type enum)
-            );
-
-            /// Dtor
-            ~GarbageCollector();
-
-            /// Allocate new HP record
-            hplist_node * NewHPRec();
-
-            /// Permanently deletes HPrecord \p pNode
-            /**
-                Caveat: for performance reason this function is defined as inline and cannot be called directly
-            */
-            void                DeleteHPRec( hplist_node * pNode );
-
-            /// Permanently deletes retired pointer \p p
-            /**
-                Caveat: for performance reason this function is defined as inline and cannot be called directly
-            */
-            void                DeletePtr( details::retired_ptr& p );
-
-            //@cond
-            void detachAllThread();
-            //@endcond
-
-        public:
-            /// Creates GarbageCollector singleton
-            /**
-                GC is the singleton. 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 - HP pointer count per thread. Usually it is small number (2-4) depending from
-                                     the data structure algorithms. By default, if \p nHazardPtrCount = 0,
-                                     the function uses maximum of HP count for CDS library.
-
-                \p nMaxThreadCount - max count of thread with using HP GC in your application. Default is 100.
-
-                \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
-                                    \p nHazardPtrCount * \p nMaxThreadCount.
-                                    Default is 2 * \p nHazardPtrCount * \p nMaxThreadCount.
-            */
-            static void    CDS_STDCALL Construct(
-                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
-                scan_type nScanType = inplace   ///< Scan type (see \ref scan_type enum)
-            );
-
-            /// Destroys global instance of GarbageCollector
-            /**
-                The parameter \p bDetachAll should be used carefully: if its value is \p true,
-                then the destroying GC automatically detaches all attached threads. This feature
-                can be useful when you have no control over the thread termination, for example,
-                when \p libcds is injected into existing external thread.
-            */
-            static void CDS_STDCALL Destruct(
-                bool bDetachAll = false     ///< Detach all threads
-            );
-
-            /// Returns pointer to GarbageCollector instance
-            static GarbageCollector&   instance()
-            {
-                if ( !m_pHZPManager )
-                    throw HZPManagerEmpty();
-                return *m_pHZPManager;
-            }
-
-            /// Checks if global GC object is constructed and may be used
-            static bool isUsed()
-            {
-                return m_pHZPManager != nullptr;
-            }
-
-            /// Returns max Hazard Pointer count defined in construction time
-            size_t            getHazardPointerCount() const        { return m_nHazardPointerCount; }
-
-            /// Returns max thread count defined in construction time
-            size_t            getMaxThreadCount() const             { return m_nMaxThreadCount; }
-
-            /// Returns max size of retired objects array. It is defined in construction time
-            size_t            getMaxRetiredPtrCount() const        { return m_nMaxRetiredPtrCount; }
-
-            // Internal statistics
-
-            /// Get internal statistics
-            InternalState& getInternalState(InternalState& stat) const;
-
-            /// Checks if internal statistics enabled
-            bool              isStatisticsEnabled() const { return m_bStatEnabled; }
-
-            /// Enables/disables internal statistics
-            bool              enableStatistics( bool bEnable )
-            {
-                bool bEnabled = m_bStatEnabled;
-                m_bStatEnabled = bEnable;
-                return bEnabled;
-            }
-
-            /// Checks that required hazard pointer count \p nRequiredCount is less or equal then max hazard pointer count
-            /**
-                If \p nRequiredCount > getHazardPointerCount() then the exception HZPTooMany is thrown
-            */
-            static void checkHPCount( unsigned int nRequiredCount )
-            {
-                if ( instance().getHazardPointerCount() < nRequiredCount )
-                    throw HZPTooMany();
-            }
-
-            /// Get current scan strategy
-            scan_type getScanType() const
-            {
-                return m_nScanType;
-            }
-
-            /// Set current scan strategy
-            /** @anchor hzp_gc_setScanType
-                Scan strategy changing is allowed on the fly.
-            */
-            void setScanType(
-                scan_type nScanType     ///< new scan strategy
-            )
-            {
-                m_nScanType = nScanType;
-            }
-
-        public:    // Internals for threads
-
-            /// Allocates Hazard Pointer GC record. For internal use only
-            details::HPRec * AllocateHPRec();
-
-            /// Free HP record. For internal use only
-            void RetireHPRec( details::HPRec * pRec );
-
-            /// The main garbage collecting function
-            /**
-                This function is called internally by ThreadGC object when upper bound of thread's list of reclaimed pointers
-                is reached.
-
-                There are the following scan algorithm:
-                - \ref hzp_gc_classic_scan "classic_scan" allocates memory for internal use
-                - \ref hzp_gc_inplace_scan "inplace_scan" does not allocate any memory
-
-                Use \ref hzp_gc_setScanType "setScanType" member function to setup appropriate scan algorithm.
-            */
-            void Scan( details::HPRec * pRec )
-            {
-                switch ( m_nScanType ) {
-                    case inplace:
-                        inplace_scan( pRec );
-                        break;
-                    default:
-                        assert(false)   ;   // Forgotten something?..
-                    case classic:
-                        classic_scan( pRec );
-                        break;
-                }
-            }
-
-            /// Helper scan routine
-            /**
-                The function guarantees that every node that is eligible for reuse is eventually freed, barring
-                thread failures. To do so, after executing Scan, a thread executes a HelpScan,
-                where it checks every HP record. If an HP record is inactive, the thread moves all "lost" reclaimed pointers
-                to thread's list of reclaimed pointers.
-
-                The function is called internally by Scan.
-            */
-            void HelpScan( details::HPRec * pThis );
-
-        protected:
-            /// Classic scan algorithm
-            /** @anchor hzp_gc_classic_scan
-                Classical scan algorithm as described in Michael's paper.
-
-                A scan includes four stages. The first stage involves scanning the array HP for non-null values.
-                Whenever a non-null value is encountered, it is inserted in a local list of currently protected pointer.
-                Only stage 1 accesses shared variables. The following stages operate only on private variables.
-
-                The second stage of a scan involves sorting local list of protected pointers to allow
-                binary search in the third stage.
-
-                The third stage of a scan involves checking each reclaimed node
-                against the pointers in local list of protected pointers. If the binary search yields
-                no match, the node is freed. Otherwise, it cannot be deleted now and must kept in thread's list
-                of reclaimed pointers.
-
-                The forth stage prepares new thread's private list of reclaimed pointers
-                that could not be freed during the current scan, where they remain until the next scan.
-
-                This algorithm allocates memory for internal HP array.
-
-                This function is called internally by ThreadGC object when upper bound of thread's list of reclaimed pointers
-                is reached.
-            */
-            void classic_scan( details::HPRec * pRec );
-
-            /// In-place scan algorithm
-            /** @anchor hzp_gc_inplace_scan
-                Unlike the \ref hzp_gc_classic_scan "classic_scan" algorithm, \p inplace_scan does not allocate any memory.
-                All operations are performed in-place.
-            */
-            void inplace_scan( details::HPRec * pRec );
-        };
-
-        /// Thread's hazard pointer manager
-        /**
-            To use Hazard Pointer reclamation schema each thread object must be linked with the object of ThreadGC class
-            that interacts with GarbageCollector global object. The linkage is performed by calling \ref cds_threading "cds::threading::Manager::attachThread()"
-            on the start of each thread that uses HP GC. Before terminating the thread linked to HP GC it is necessary to call
-            \ref cds_threading "cds::threading::Manager::detachThread()".
-        */
-        class ThreadGC
-        {
-            GarbageCollector&   m_HzpManager    ; ///< Hazard Pointer GC singleton
-            details::HPRec *    m_pHzpRec       ; ///< Pointer to thread's HZP record
-
-        public:
-            /// Default constructor
-            ThreadGC()
-                : m_HzpManager( GarbageCollector::instance() ),
-                m_pHzpRec( nullptr )
-            {}
-
-            /// The object is not copy-constructible
-            ThreadGC( ThreadGC const& ) = delete;
-
-            ~ThreadGC()
-            {
-                fini();
-            }
-
-            /// Checks if thread GC is initialized
-            bool    isInitialized() const   { return m_pHzpRec != nullptr; }
-
-            /// Initialization. Repeat call is available
-            void init()
-            {
-                if ( !m_pHzpRec )
-                    m_pHzpRec = m_HzpManager.AllocateHPRec();
-            }
-
-            /// Finalization. Repeat call is available
-            void fini()
-            {
-                if ( m_pHzpRec ) {
-                    details::HPRec * pRec = m_pHzpRec;
-                    m_pHzpRec = nullptr;
-                    m_HzpManager.RetireHPRec( pRec );
-                }
-            }
-
-            /// Initializes HP guard \p guard
-            details::HPGuard& allocGuard()
-            {
-                assert( m_pHzpRec );
-                return m_pHzpRec->m_hzp.alloc();
-            }
-
-            /// Frees HP guard \p guard
-            void freeGuard( details::HPGuard& guard )
-            {
-                assert( m_pHzpRec );
-                m_pHzpRec->m_hzp.free( guard );
-            }
-
-            /// Initializes HP guard array \p arr
-            template <size_t Count>
-            void allocGuard( details::HPArray<Count>& arr )
-            {
-                assert( m_pHzpRec );
-                m_pHzpRec->m_hzp.alloc( arr );
-            }
-
-            /// Frees HP guard array \p arr
-            template <size_t Count>
-            void freeGuard( details::HPArray<Count>& arr )
-            {
-                assert( m_pHzpRec );
-                m_pHzpRec->m_hzp.free( arr );
-            }
-
-            /// Places retired pointer \p and its deleter \p pFunc into thread's array of retired pointer for deferred reclamation
-            template <typename T>
-            void retirePtr( T * p, void (* pFunc)(T *) )
-            {
-                retirePtr( details::retired_ptr( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ) ) );
-            }
-
-            /// Places retired pointer \p into thread's array of retired pointer for deferred reclamation
-            void retirePtr( const details::retired_ptr& p )
-            {
-                m_pHzpRec->m_arrRetired.push( p );
-
-                if ( m_pHzpRec->m_arrRetired.isFull() ) {
-                    // Max of retired pointer count is reached. Do scan
-                    scan();
-                }
-            }
-
-            //@cond
-            void scan()
-            {
-                m_HzpManager.Scan( m_pHzpRec );
-                m_HzpManager.HelpScan( m_pHzpRec );
-            }
-            //@endcond
-        };
-
-        /// Auto HPGuard.
-        /**
-            This class encapsulates Hazard Pointer guard to protect a pointer against deletion .
-            It allocates one HP from thread's HP array in constructor and free the HP allocated in destruction time.
-        */
-        class AutoHPGuard
-        {
-            //@cond
-            details::HPGuard&   m_hp    ; ///< Hazard pointer guarded
-            ThreadGC&           m_gc    ; ///< Thread GC
-            //@endcond
-
-        public:
-            typedef details::HPGuard::hazard_ptr hazard_ptr ;  ///< Hazard pointer type
-        public:
-            /// Allocates HP guard from \p gc
-            AutoHPGuard( ThreadGC& gc )
-                : m_hp( gc.allocGuard() )
-                , m_gc( gc )
-            {}
-
-            /// Allocates HP guard from \p gc and protects the pointer \p p of type \p T
-            template <typename T>
-            AutoHPGuard( ThreadGC& gc, T * p  )
-                : m_hp( gc.allocGuard() )
-                , m_gc( gc )
-            {
-                m_hp = p;
-            }
-
-            /// Frees HP guard. The pointer guarded may be deleted after this.
-            ~AutoHPGuard()
-            {
-                m_gc.freeGuard( m_hp );
-            }
-
-            /// Returns thread GC
-            ThreadGC&    getGC() const
-            {
-                return m_gc;
-            }
-
-            /// Protects the pointer \p p against reclamation (guards the pointer).
-            template <typename T>
-            T * operator =( T * p )
-            {
-                return m_hp = p;
-            }
-
-            //@cond
-            std::nullptr_t operator =(std::nullptr_t)
-            {
-                return m_hp = nullptr;
-            }
-
-            hazard_ptr get() const
-            {
-                return m_hp;
-            }
-            //@endcond
-        };
-
-        /// Auto-managed array of hazard pointers
-        /**
-            This class is wrapper around cds::gc::hzp::details::HPArray class.
-            \p Count is the size of HP array
-        */
-        template <size_t Count>
-        class AutoHPArray: public details::HPArray<Count>
-        {
-            ThreadGC&    m_mgr    ;    ///< Thread GC
-
-        public:
-            /// Rebind array for other size \p COUNT2
-            template <size_t Count2>
-            struct rebind {
-                typedef AutoHPArray<Count2>  other   ;   ///< rebinding result
-            };
-
-        public:
-            /// Allocates array of HP guard from \p mgr
-            AutoHPArray( ThreadGC& mgr )
-                : m_mgr( mgr )
-            {
-                mgr.allocGuard( *this );
-            }
-
-            /// Frees array of HP guard
-            ~AutoHPArray()
-            {
-                m_mgr.freeGuard( *this );
-            }
-
-            /// Returns thread GC
-            ThreadGC&    getGC() const { return m_mgr; }
-        };
-
-    }   // namespace hzp
-}}  // namespace cds::gc
-
-// Inlines
-#include <cds/gc/hzp/details/hp_inline.h>
-
-#if CDS_COMPILER == CDS_COMPILER_MSVC
-#   pragma warning(pop)
-#endif
-
-#endif  // #ifndef __CDS_GC_HZP_HZP_H
diff --git a/cds/gc/ptb.h b/cds/gc/ptb.h
deleted file mode 100644 (file)
index 8096695..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_PTB_H
-#define __CDS_GC_PTB_H
-
-#include <cds/gc/ptb_decl.h>
-#include <cds/gc/ptb_impl.h>
-#include <cds/details/lib.h>
-
-#endif // #ifndef __CDS_GC_PTB_H
diff --git a/cds/gc/ptb_decl.h b/cds/gc/ptb_decl.h
deleted file mode 100644 (file)
index 34feb39..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_PTB_DECL_H
-#define __CDS_GC_PTB_DECL_H
-
-#include <cds/gc/ptb/ptb.h>
-#include <cds/details/marked_ptr.h>
-#include <cds/details/static_functor.h>
-
-namespace cds { namespace gc {
-
-    /// Pass-the-Buck garbage collector
-    /**  @ingroup cds_garbage_collector
-        @headerfile cds/gc/ptb.h
-        This class is a wrapper for Pass-the-Buck garbage collector internal implementation.
-
-        Sources:
-        - [2002] M. Herlihy, V. Luchangco, and M. Moir. The repeat offender problem: A mechanism for supporting
-            dynamic-sized lockfree data structures. Technical Report TR-2002-112, Sun Microsystems Laboratories, 2002
-        - [2002] M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Dynamic-sized Lockfree Data Structures.
-            Technical Report TR-2002-110, Sun Microsystems Laboratories, 2002
-        - [2005] M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Nonblocking Memory Management Support
-            for Dynamic_Sized Data Structures. ACM Transactions on Computer Systems, Vol.23, No.2, May 2005
-
-        See \ref cds_how_to_use "How to use" section for details of garbage collector applying.
-    */
-    class PTB
-    {
-    public:
-        /// Native guarded pointer type
-        typedef void * guarded_pointer;
-
-        /// Atomic reference
-        /**
-            @headerfile cds/gc/ptb.h
-        */
-        template <typename T> using atomic_ref = atomics::atomic<T *>;
-
-        /// Atomic type
-        /**
-            @headerfile cds/gc/ptb.h
-        */
-        template <typename T> using atomic_type = atomics::atomic<T>;
-
-        /// Atomic marked pointer
-        /**
-            @headerfile cds/gc/ptb.h
-        */
-        template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
-
-        /// Thread GC implementation for internal usage
-        typedef ptb::ThreadGC   thread_gc_impl;
-
-        /// Wrapper for ptb::ThreadGC class
-        /**
-            @headerfile cds/gc/ptb.h
-            This class performs automatically attaching/detaching Pass-the-Buck 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 Pass-the-Buck 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 Pass-the-Buck GC.
-                - \p false (default) - the class destructor will detach the thread from Pass-the-Buck GC.
-            */
-            thread_gc(
-                bool    bPersistent = false
-            )   ;   // inline in ptb_impl.h
-
-            /// Destructor
-            /**
-                If the object has been created in persistent mode, the destructor does nothing.
-                Otherwise it detaches the current thread from Pass-the-Buck GC.
-            */
-            ~thread_gc()    ;   // inline in ptb_impl.h
-        };
-
-
-        /// Pass-the-Buck guard
-        /**
-            @headerfile cds/gc/ptb.h
-            This class is a wrapper for ptb::Guard.
-        */
-        class Guard: public ptb::Guard
-        {
-            //@cond
-            typedef ptb::Guard base_class;
-            //@endcond
-
-        public:
-            //@cond
-            Guard() ;   // inline in ptb_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 Pass-the-Buck guards
-        /**
-            @headerfile cds/gc/ptb.h
-            This class is a wrapper for ptb::GuardArray template.
-            Template parameter \p Count defines the size of PTB array.
-        */
-        template <size_t Count>
-        class GuardArray: public ptb::GuardArray<Count>
-        {
-            //@cond
-            typedef ptb::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 ptb_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 ptb::GarbageCollector singleton
-        /**
-            The constructor calls GarbageCollector::Construct with passed parameters.
-            See ptb::GarbageCollector::Construct for explanation of parameters meaning.
-        */
-        PTB(
-            size_t nLiberateThreshold = 1024
-            , size_t nInitialThreadGuardCount = 8
-        )
-        {
-            ptb::GarbageCollector::Construct(
-                nLiberateThreshold,
-                nInitialThreadGuardCount
-            );
-        }
-
-        /// Terminates ptb::GarbageCollector singleton
-        /**
-            The destructor calls \code ptb::GarbageCollector::Destruct() \endcode
-        */
-        ~PTB()
-        {
-            ptb::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
-            PTB 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 *) )
-        {
-            ptb::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 Pass-the-Buck GC is constructed and may be used
-        static bool isUsed()
-        {
-            return ptb::GarbageCollector::isUsed();
-        }
-
-        /// Forced GC cycle call for current thread
-        /**
-            Usually, this function should not be called directly.
-        */
-        static void scan()  ;   // inline in ptb_impl.h
-
-        /// Synonym for \ref scan()
-        static void force_dispose()
-        {
-            scan();
-        }
-    };
-
-}} // namespace cds::gc
-
-#endif // #ifndef __CDS_GC_PTB_DECL_H
diff --git a/cds/gc/ptb_impl.h b/cds/gc/ptb_impl.h
deleted file mode 100644 (file)
index 201564c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_PTB_IMPL_H
-#define __CDS_GC_PTB_IMPL_H
-
-#include <cds/threading/model.h>
-
-//@cond
-namespace cds { namespace gc {
-
-    inline PTB::thread_gc::thread_gc(
-        bool    bPersistent
-        )
-        : m_bPersistent( bPersistent )
-    {
-        if ( !cds::threading::Manager::isThreadAttached() )
-            cds::threading::Manager::attachThread();
-    }
-
-    inline PTB::thread_gc::~thread_gc()
-    {
-        if ( !m_bPersistent )
-            cds::threading::Manager::detachThread();
-    }
-
-    inline PTB::Guard::Guard()
-        : Guard::base_class( cds::threading::getGC<PTB>() )
-    {}
-
-    template <size_t COUNT>
-    inline PTB::GuardArray<COUNT>::GuardArray()
-        : GuardArray::base_class( cds::threading::getGC<PTB>() )
-    {}
-
-    inline void PTB::scan()
-    {
-        cds::threading::getGC<PTB>().scan();
-    }
-
-}} // namespace cds::gc
-//@endcond
-
-#endif // #ifndef __CDS_GC_PTB_IMPL_H
index 619a01f228030cd5be7b7e58c38165e1d4e48c99..b31823a4fc04c77298ab225844b480c61a5cf888 100644 (file)
@@ -4,7 +4,7 @@
 #define __CDS_THREADING__COMMON_H
 
 #include <cds/gc/hp_decl.h>
-#include <cds/gc/ptb_decl.h>
+#include <cds/gc/dhp_decl.h>
 
 #include <cds/urcu/details/gp_decl.h>
 #include <cds/urcu/details/sh_decl.h>
index 70e78e5c9587d172726821bd223760b0829caeda..d242c1e1b50a8e3bd55461cd9dfdeecbf5977b9c 100644 (file)
     <ClInclude Include="..\..\..\cds\details\lib.h" />\r
     <ClInclude Include="..\..\..\cds\details\static_functor.h" />\r
     <ClInclude Include="..\..\..\cds\gc\dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\dhp_decl.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\dhp_impl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\gc_fwd.h" />\r
     <ClInclude Include="..\..\..\cds\gc\guarded_ptr.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_alloc.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_fwd.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_inline.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_retired.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_type.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\hp\hzp.h" />\r
     <ClInclude Include="..\..\..\cds\gc\hp_decl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\hp_impl.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\ptb_decl.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\ptb_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
     <ClInclude Include="..\..\..\cds\gc\default_gc.h" />\r
     <ClInclude Include="..\..\..\cds\gc\hp.h" />\r
     <ClInclude Include="..\..\..\cds\gc\nogc.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\ptb.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_alloc.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_fwd.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_inline.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_retired.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_type.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\hzp.h" />\r
     <ClInclude Include="..\..\..\cds\gc\ptb\ptb.h" />\r
     <ClInclude Include="..\..\..\cds\gc\details\retired_ptr.h" />\r
     <ClInclude Include="..\..\..\cds\user_setup\allocator.h" />\r
index b9dcf1e0689747bab5c556b07966d2094cee2c2c..75906e30cc1bd3f0218867bbaf7f71997dc42164 100644 (file)
@@ -18,9 +18,6 @@
     <Filter Include="Header Files\cds\gc">\r
       <UniqueIdentifier>{a3c9928d-5261-4593-a8b9-728235f7056f}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="Header Files\cds\gc\hzp">\r
-      <UniqueIdentifier>{21a6c665-7381-45b8-9f03-b21f3da5503d}</UniqueIdentifier>\r
-    </Filter>\r
     <Filter Include="Header Files\cds\gc\ptb">\r
       <UniqueIdentifier>{53d28ee4-5fe9-4fa1-a617-53d8b0628eac}</UniqueIdentifier>\r
     </Filter>\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
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="..\..\..\src\dllmain.cpp">\r
     <ClInclude Include="..\..\..\cds\gc\nogc.h">\r
       <Filter>Header Files\cds\gc</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\ptb.h">\r
-      <Filter>Header Files\cds\gc</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_alloc.h">\r
-      <Filter>Header Files\cds\gc\hzp</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_fwd.h">\r
-      <Filter>Header Files\cds\gc\hzp</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_inline.h">\r
-      <Filter>Header Files\cds\gc\hzp</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_retired.h">\r
-      <Filter>Header Files\cds\gc\hzp</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\details\hp_type.h">\r
-      <Filter>Header Files\cds\gc\hzp</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\hzp\hzp.h">\r
-      <Filter>Header Files\cds\gc\hzp</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\..\cds\gc\ptb\ptb.h">\r
       <Filter>Header Files\cds\gc\ptb</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\cds\gc\hp_impl.h">\r
       <Filter>Header Files\cds\gc</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\ptb_decl.h">\r
-      <Filter>Header Files\cds\gc</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\ptb_impl.h">\r
-      <Filter>Header Files\cds\gc</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\..\cds\compiler\cxx11_atomic.h">\r
       <Filter>Header Files\cds\compiler</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\cds\container\details\split_list_base.h">\r
       <Filter>Header Files\cds\container\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\dhp.h">\r
-      <Filter>Header Files\cds\gc</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\..\cds\container\michael_list_dhp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\cds\container\ellen_bintree_set_dhp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\dhp.h">\r
+      <Filter>Header Files\cds\gc</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\dhp_decl.h">\r
+      <Filter>Header Files\cds\gc</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\dhp_impl.h">\r
+      <Filter>Header Files\cds\gc</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_alloc.h">\r
+      <Filter>Header Files\cds\gc\hp</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_fwd.h">\r
+      <Filter>Header Files\cds\gc\hp</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_inline.h">\r
+      <Filter>Header Files\cds\gc\hp</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_retired.h">\r
+      <Filter>Header Files\cds\gc\hp</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_type.h">\r
+      <Filter>Header Files\cds\gc\hp</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\hp\hzp.h">\r
+      <Filter>Header Files\cds\gc\hp</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index e171fbcc03bdae21bd4fc92bea0ee62103037124..a8bb004dc886b2a9c26b39e16e97e9a88405bf4b 100644 (file)
@@ -9,7 +9,7 @@
         2008.02.10    Maxim.Khiszinsky    Created
 */
 
-#include <cds/gc/hzp/hzp.h>
+#include <cds/gc/hp/hp.h>
 
 #include <algorithm>    // std::sort
 #include "hzp_const.h"
index 3ae3362cd045c1b89dde34b4ef703e3bd29b97c6..452c05036c647bbc7dc01c5affe3a7bc8e2d2753 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <cds/init.h>
 #include <cds/gc/hp.h>
-#include <cds/gc/ptb.h>
+#include <cds/gc/dhp.h>
 #include <cds/urcu/general_instant.h>
 #include <cds/urcu/general_buffered.h>
 #include <cds/urcu/general_threaded.h>