Hazard Pointer GC refactoring
authorkhizmax <libcds.dev@gmail.com>
Sat, 15 Nov 2014 13:32:40 +0000 (16:32 +0300)
committerkhizmax <libcds.dev@gmail.com>
Sat, 15 Nov 2014 13:32:40 +0000 (16:32 +0300)
12 files changed:
cds/gc/details/hp.h [new file with mode: 0644]
cds/gc/details/hp_alloc.h [new file with mode: 0644]
cds/gc/details/hp_inline.h [new file with mode: 0644]
cds/gc/details/hp_type.h [new file with mode: 0644]
cds/gc/hp/details/hp_alloc.h [deleted file]
cds/gc/hp/details/hp_inline.h [deleted file]
cds/gc/hp/details/hp_type.h [deleted file]
cds/gc/hp/hp.h [deleted file]
cds/gc/hp/hp_decl.h
projects/Win/vc12/cds.vcxproj
projects/Win/vc12/cds.vcxproj.filters
src/hp_gc.cpp

diff --git a/cds/gc/details/hp.h b/cds/gc/details/hp.h
new file mode 100644 (file)
index 0000000..0e9f0c0
--- /dev/null
@@ -0,0 +1,766 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_DETAILS_HP_H
+#define __CDS_GC_DETAILS_HP_H
+
+#include <cds/cxx11_atomic.h>
+#include <cds/os/thread.h>
+#include <cds/details/bounded_array.h>
+
+#include <cds/gc/details/hp_type.h>
+#include <cds/gc/details/hp_alloc.h>
+
+#if CDS_COMPILER == CDS_COMPILER_MSVC
+#   pragma warning(push)
+    // warning C4251: 'cds::gc::hp::GarbageCollector::m_pListHead' : class 'cds::cxx11_atomic::atomic<T>'
+    // needs to have dll-interface to be used by clients of class 'cds::gc::hp::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::DHP</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 \p cds::gc::hp namespace and its members are internal representation of Hazard Pointer GC and should not be used directly.
+        Use \p 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 \p cds::gc::HP object in beginning of your \p main().
+        See \p cds::gc::HP class for explanation.
+    */
+    namespace hp {
+
+        // forwards
+        class GarbageCollector;
+        class ThreadGC;
+
+        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::hp::GarbageCollector& HzpMgr ) CDS_NOEXCEPT; // inline
+                ~retired_vector()
+                {}
+
+                /// Vector capacity.
+                /**
+                    The capacity is constant for any thread. It is defined by cds::gc::hp::GarbageCollector.
+                */
+                size_t capacity() const CDS_NOEXCEPT
+                { 
+                    return m_arr.capacity(); 
+                }
+
+                /// Current vector size (count of retired pointers in the vector)
+                size_t size() const CDS_NOEXCEPT
+                { 
+                    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 CDS_NOEXCEPT
+                {
+                    return m_nSize >= capacity();
+                }
+
+                /// Begin iterator
+                iterator    begin() CDS_NOEXCEPT
+                { 
+                    return m_arr.begin(); 
+                }
+
+                /// End iterator
+                iterator    end() CDS_NOEXCEPT
+                { 
+                    return m_arr.begin() +  m_nSize ; 
+                }
+
+                /// Clears the vector. After clearing, size() == 0
+                void clear() CDS_NOEXCEPT
+                {
+                    m_nSize = 0;
+                }
+            };
+
+            /// 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 hp_record {
+                hp_allocator<>    m_hzp; ///< array of hazard pointers. Implicit \ref CDS_DEFAULT_ALLOCATOR dependency
+                retired_vector    m_arrRetired ; ///< Retired pointer array
+
+                /// Ctor
+                hp_record( const cds::gc::hp::GarbageCollector& HzpMgr );    // inline
+                ~hp_record()
+                {}
+
+                /// 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 \p hp_record allocations
+                event_counter::value_type   evcRetireHPRec  ;   ///< Count of \p hp_record retire events
+                event_counter::value_type   evcAllocNewHPRec;   ///< Count of new \p hp_record allocations from heap
+                event_counter::value_type   evcDeleteHPRec  ;   ///< Count of \p hp_record 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 \p hp_record allocations
+                event_counter  m_RetireHPRec            ;    ///< Count of \p hp_record retire events
+                event_counter  m_AllocNewHPRec            ;    ///< Count of new \p hp_record allocations from heap
+                event_counter  m_DeleteHPRec            ;    ///< Count of \p hp_record 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::hp::details::hp_record
+            struct hplist_node : public details::hp_record
+            {
+                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 )
+                    : hp_record( 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() CDS_NOEXCEPT
+            {
+                return m_pHZPManager != nullptr;
+            }
+
+            /// Returns max Hazard Pointer count defined in construction time
+            size_t            getHazardPointerCount() const CDS_NOEXCEPT
+            { 
+                return m_nHazardPointerCount; 
+            }
+
+            /// Returns max thread count defined in construction time
+            size_t            getMaxThreadCount() const CDS_NOEXCEPT
+            { 
+                return m_nMaxThreadCount; 
+            }
+
+            /// Returns max size of retired objects array. It is defined in construction time
+            size_t            getMaxRetiredPtrCount() const CDS_NOEXCEPT
+            { 
+                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::hp_record * alloc_hp_record();
+
+            /// Free HP record. For internal use only
+            void free_hp_record( details::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * 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.alloc_hp_record();
+            }
+
+            /// Finalization. Repeat call is available
+            void fini()
+            {
+                if ( m_pHzpRec ) {
+                    details::hp_record * pRec = m_pHzpRec;
+                    m_pHzpRec = nullptr;
+                    m_HzpManager.free_hp_record( pRec );
+                }
+            }
+
+            /// Initializes HP guard \p guard
+            details::hp_guard& allocGuard()
+            {
+                assert( m_pHzpRec );
+                return m_pHzpRec->m_hzp.alloc();
+            }
+
+            /// Frees HP guard \p guard
+            void freeGuard( details::hp_guard& guard )
+            {
+                assert( m_pHzpRec );
+                m_pHzpRec->m_hzp.free( guard );
+            }
+
+            /// Initializes HP guard array \p arr
+            template <size_t Count>
+            void allocGuard( details::hp_array<Count>& arr )
+            {
+                assert( m_pHzpRec );
+                m_pHzpRec->m_hzp.alloc( arr );
+            }
+
+            /// Frees HP guard array \p arr
+            template <size_t Count>
+            void freeGuard( details::hp_array<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 *) )
+            {
+                /*
+                union {
+                    T * p;
+                    hazard_pointer hp;
+                } cast_ptr;
+                cast_ptr.p = p;
+
+                uinion{
+                    void( *pFunc )(T *);
+                    free_retired_ptr_func hpFunc;
+                } cast_func;
+                cast_func.pFunc = pFunc;
+
+                retirePtr( details::retired_ptr( cast_ptr.hp, cast_func.hpFunc ) );
+                */
+                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( details::retired_ptr const& 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 hp_guard.
+        /**
+            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 hazard pointer allocated 
+            in destructor.
+        */
+        class guard
+        {
+            //@cond
+            details::hp_guard&   m_hp    ; ///< Hazard pointer guarded
+            ThreadGC&           m_gc    ; ///< Thread GC
+            //@endcond
+
+        public:
+            typedef details::hp_guard::hazard_ptr hazard_ptr ;  ///< Hazard pointer type
+        public:
+            /// Allocates HP guard from \p gc
+            guard( 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>
+            guard( 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.
+            ~guard()
+            {
+                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::hp::details::hp_array class.
+            \p Count is the size of HP array
+        */
+        template <size_t Count>
+        class array : public details::hp_array<Count>
+        {
+            ThreadGC&    m_mgr    ;    ///< Thread GC
+
+        public:
+            /// Rebind array for other size \p COUNT2
+            template <size_t Count2>
+            struct rebind {
+                typedef array<Count2>  other;   ///< rebinding result
+            };
+
+        public:
+            /// Allocates array of HP guard from \p mgr
+            array( ThreadGC& mgr )
+                : m_mgr( mgr )
+            {
+                mgr.allocGuard( *this );
+            }
+
+            /// Frees array of HP guard
+            ~array()
+            {
+                m_mgr.freeGuard( *this );
+            }
+
+            /// Returns thread GC
+            ThreadGC&    getGC() const { return m_mgr; }
+        };
+
+    }   // namespace hp
+}}  // namespace cds::gc
+
+// Inlines
+#include <cds/gc/details/hp_inline.h>
+
+#if CDS_COMPILER == CDS_COMPILER_MSVC
+#   pragma warning(pop)
+#endif
+
+#endif  // #ifndef __CDS_GC_DETAILS_HP_H
diff --git a/cds/gc/details/hp_alloc.h b/cds/gc/details/hp_alloc.h
new file mode 100644 (file)
index 0000000..e057e1b
--- /dev/null
@@ -0,0 +1,320 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_DETAILS_HP_ALLOC_H
+#define __CDS_GC_DETAILS_HP_ALLOC_H
+
+#include <cds/cxx11_atomic.h>
+#include <cds/details/allocator.h>
+#include <cds/gc/details/hp_type.h>
+
+//@cond
+namespace cds {
+    namespace gc { namespace hp {
+        // forwards
+        class GarbageCollector;
+        class ThreadGC;
+
+    /// Hazard Pointer schema implementation details
+    namespace details {
+
+        /// Hazard pointer guard
+        /**
+            It is unsafe to use this class directly.
+            Instead, the \p hp::guard class should be used.
+        */
+        class hp_guard : protected atomics::atomic < hazard_pointer >
+        {
+        public:
+            typedef hazard_pointer   hazard_ptr;    ///< Hazard pointer type
+        private:
+            //@cond
+            typedef atomics::atomic<hazard_ptr>  base_class;
+            //@endcond
+
+        protected:
+            //@cond
+            template <class Allocator> friend class hp_allocator;
+            //@endcond
+
+        public:
+            hp_guard() CDS_NOEXCEPT
+                : base_class( nullptr )
+            {}
+            ~hp_guard() 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
+                set( p );
+                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( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT
+            {
+                return base_class::load( order );
+            }
+
+                template <typename T>
+            void set( T * p, atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT
+            {
+                base_class::store( reinterpret_cast<hazard_ptr>(p), order );
+            }
+
+            /// Clears HP
+            /**
+                Clearing has relaxed semantics.
+            */
+            void clear( atomics::memory_order order = atomics::memory_order_relaxed ) CDS_NOEXCEPT
+            {
+                // memory order is not necessary here
+                base_class::store( nullptr, order );
+            }
+        };
+
+        /// 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 \p hp::array should be used.
+
+            While creating the object of \p hp_array 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 \p hp_array object and implements interface for HP setting and freeing.
+
+            Template parameter:
+                \li Count - capacity of array
+
+        */
+        template <size_t Count>
+        class hp_array
+        {
+        public:
+            typedef hazard_pointer  hazard_ptr_type;   ///< Hazard pointer type
+            typedef hp_guard        atomic_hazard_ptr; ///< Element type of the array
+            static CDS_CONSTEXPR 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 <class Allocator> friend class hp_allocator;
+            //@endcond
+
+        public:
+            /// Constructs uninitialized array.
+            hp_array() CDS_NOEXCEPT
+            {}
+
+            /// Destructs object
+            ~hp_array() 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();
+            }
+        };
+
+        /// 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 Allocator - memory allocator class, default is \ref CDS_DEFAULT_ALLOCATOR
+
+            This helper class should not be used directly.
+        */
+        template <class Allocator = CDS_DEFAULT_ALLOCATOR >
+        class hp_allocator
+        {
+        public:
+            typedef hazard_pointer  hazard_ptr_type;    ///< type of hazard pointer
+            typedef hp_guard        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 hp_allocator(
+                size_t  nCapacity            ///< max count of hazard pointer per thread
+                )
+                : m_arrHazardPtr( alloc_array( nCapacity ) )
+                , m_nCapacity( nCapacity )
+            {
+                make_free();
+            }
+
+            /// Dtor
+            ~hp_allocator()
+            {
+                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( hp_array<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( hp_array<Count> const& 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::hp::details
+}   // namespace cds
+//@endcond
+
+#endif // #ifndef __CDS_GC_DETAILS_HP_ALLOC_H
diff --git a/cds/gc/details/hp_inline.h b/cds/gc/details/hp_inline.h
new file mode 100644 (file)
index 0000000..86bc997
--- /dev/null
@@ -0,0 +1,26 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_DETAILS_HP_INLINE_H
+#define __CDS_GC_DETAILS_HP_INLINE_H
+
+namespace cds {
+    namespace gc{ namespace hp { namespace details {
+
+        /************************************************************************/
+        /* INLINES                                                              */
+        /************************************************************************/
+        inline retired_vector::retired_vector( const cds::gc::hp::GarbageCollector& HzpMgr ) CDS_NOEXCEPT
+            : m_arr( HzpMgr.getMaxRetiredPtrCount() ),
+            m_nSize(0)
+        {}
+
+        inline hp_record::hp_record( const cds::gc::hp::GarbageCollector& HzpMgr )
+            : m_hzp( HzpMgr.getHazardPointerCount() ),
+            m_arrRetired( HzpMgr )
+        {}
+
+    } } }    // namespace gc::hp::details
+}    // namespace cds
+
+
+#endif // #ifndef __CDS_GC_DETAILS_HP_INLINE_H
diff --git a/cds/gc/details/hp_type.h b/cds/gc/details/hp_type.h
new file mode 100644 (file)
index 0000000..2167121
--- /dev/null
@@ -0,0 +1,23 @@
+//$$CDS-header$$
+
+#ifndef __CDS_GC_DETAILS_HP_TYPE_H
+#define __CDS_GC_DETAILS_HP_TYPE_H
+
+#include <cds/gc/details/retired_ptr.h> // free_retired_ptr_func
+
+namespace cds {
+    namespace gc {
+        namespace hp {
+
+            /// 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_DETAILS_HP_TYPE_H
+
+
diff --git a/cds/gc/hp/details/hp_alloc.h b/cds/gc/hp/details/hp_alloc.h
deleted file mode 100644 (file)
index 05cc626..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HP_DETAILS_HP_ALLOC_H
-#define __CDS_GC_HP_DETAILS_HP_ALLOC_H
-
-#include <cds/cxx11_atomic.h>
-#include <cds/details/allocator.h>
-#include <cds/gc/hp/details/hp_type.h>
-
-//@cond
-namespace cds {
-    namespace gc { namespace hp {
-        // forwards
-        class GarbageCollector;
-        class ThreadGC;
-
-    /// 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.
-        */
-        class hp_guard : protected atomics::atomic < hazard_pointer >
-        {
-        public:
-            typedef hazard_pointer   hazard_ptr;    ///< Hazard pointer type
-        private:
-            //@cond
-            typedef atomics::atomic<hazard_ptr>  base_class;
-            //@endcond
-
-        protected:
-            //@cond
-            template <class Allocator> friend class hp_allocator;
-            //@endcond
-
-        public:
-            hp_guard() CDS_NOEXCEPT
-                : base_class( nullptr )
-            {}
-            ~hp_guard() 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
-                set( p );
-                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( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT
-            {
-                return base_class::load( order );
-            }
-
-                template <typename T>
-            void set( T * p, atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT
-            {
-                base_class::store( reinterpret_cast<hazard_ptr>(p), order );
-            }
-
-            /// Clears HP
-            /**
-                Clearing has relaxed semantics.
-            */
-            void clear( atomics::memory_order order = atomics::memory_order_relaxed ) CDS_NOEXCEPT
-            {
-                // memory order is not necessary here
-                base_class::store( nullptr, order );
-            }
-        };
-
-        /// 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 \p hp_array 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 \p hp_array object and implements interface for HP setting and freeing.
-
-            Template parameter:
-                \li Count - capacity of array
-
-        */
-        template <size_t Count>
-        class hp_array
-        {
-        public:
-            typedef hazard_pointer  hazard_ptr_type;   ///< Hazard pointer type
-            typedef hp_guard        atomic_hazard_ptr; ///< Element type of the array
-            static CDS_CONSTEXPR 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 <class Allocator> friend class hp_allocator;
-            //@endcond
-
-        public:
-            /// Constructs uninitialized array.
-            hp_array() CDS_NOEXCEPT
-            {}
-
-            /// Destructs object
-            ~hp_array() 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();
-            }
-        };
-
-        /// 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 Allocator - memory allocator class, default is \ref CDS_DEFAULT_ALLOCATOR
-
-            This helper class should not be used directly.
-        */
-        template <class Allocator = CDS_DEFAULT_ALLOCATOR >
-        class hp_allocator
-        {
-        public:
-            typedef hazard_pointer  hazard_ptr_type;    ///< type of hazard pointer
-            typedef hp_guard        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 hp_allocator(
-                size_t  nCapacity            ///< max count of hazard pointer per thread
-                )
-                : m_arrHazardPtr( alloc_array( nCapacity ) )
-                , m_nCapacity( nCapacity )
-            {
-                make_free();
-            }
-
-            /// Dtor
-            ~hp_allocator()
-            {
-                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( hp_array<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( hp_array<Count> const& 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::hp::details
-}   // namespace cds
-//@endcond
-
-#endif // #ifndef __CDS_GC_HP_DETAILS_HP_ALLOC_H
diff --git a/cds/gc/hp/details/hp_inline.h b/cds/gc/hp/details/hp_inline.h
deleted file mode 100644 (file)
index 7142b78..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HP_DETAILS_HP_INLINE_H
-#define __CDS_GC_HP_DETAILS_HP_INLINE_H
-
-namespace cds {
-    namespace gc{ namespace hp { namespace details {
-
-        /************************************************************************/
-        /* INLINES                                                              */
-        /************************************************************************/
-        inline retired_vector::retired_vector( const cds::gc::hp::GarbageCollector& HzpMgr ) CDS_NOEXCEPT
-            : m_arr( HzpMgr.getMaxRetiredPtrCount() ),
-            m_nSize(0)
-        {}
-
-        inline hp_record::hp_record( const cds::gc::hp::GarbageCollector& HzpMgr )
-            : m_hzp( HzpMgr.getHazardPointerCount() ),
-            m_arrRetired( HzpMgr )
-        {}
-
-    } } }    // namespace gc::hp::details
-}    // namespace cds
-
-
-#endif // #ifndef __CDS_GC_HP_DETAILS_HP_INLINE_H
diff --git a/cds/gc/hp/details/hp_type.h b/cds/gc/hp/details/hp_type.h
deleted file mode 100644 (file)
index 2f22ebd..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HP_DETAILS_HP_TYPE_H
-#define __CDS_GC_HP_DETAILS_HP_TYPE_H
-
-#include <cds/gc/details/retired_ptr.h> // free_retired_ptr_func
-
-namespace cds {
-    namespace gc {
-        namespace hp {
-
-            /// 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_HP_DETAILS_HP_TYPE_H
-
-
diff --git a/cds/gc/hp/hp.h b/cds/gc/hp/hp.h
deleted file mode 100644 (file)
index 9124850..0000000
+++ /dev/null
@@ -1,750 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_HP_HP_H
-#define __CDS_GC_HP_HP_H
-
-#include <cds/cxx11_atomic.h>
-#include <cds/os/thread.h>
-#include <cds/details/bounded_array.h>
-
-#include <cds/gc/hp/details/hp_type.h>
-#include <cds/gc/hp/details/hp_alloc.h>
-
-#if CDS_COMPILER == CDS_COMPILER_MSVC
-#   pragma warning(push)
-    // warning C4251: 'cds::gc::hp::GarbageCollector::m_pListHead' : class 'cds::cxx11_atomic::atomic<T>'
-    // needs to have dll-interface to be used by clients of class 'cds::gc::hp::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::DHP</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 \p cds::gc::hp namespace and its members are internal representation of Hazard Pointer GC and should not be used directly.
-        Use \p 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 \p cds::gc::HP object in beginning of your \p main().
-        See \p cds::gc::HP class for explanation.
-    */
-    namespace hp {
-
-        // forwards
-        class GarbageCollector;
-        class ThreadGC;
-
-        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::hp::GarbageCollector& HzpMgr ) CDS_NOEXCEPT; // inline
-                ~retired_vector()
-                {}
-
-                /// Vector capacity.
-                /**
-                    The capacity is constant for any thread. It is defined by cds::gc::hp::GarbageCollector.
-                */
-                size_t capacity() const CDS_NOEXCEPT
-                { 
-                    return m_arr.capacity(); 
-                }
-
-                /// Current vector size (count of retired pointers in the vector)
-                size_t size() const CDS_NOEXCEPT
-                { 
-                    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 CDS_NOEXCEPT
-                {
-                    return m_nSize >= capacity();
-                }
-
-                /// Begin iterator
-                iterator    begin() CDS_NOEXCEPT
-                { 
-                    return m_arr.begin(); 
-                }
-
-                /// End iterator
-                iterator    end() CDS_NOEXCEPT
-                { 
-                    return m_arr.begin() +  m_nSize ; 
-                }
-
-                /// Clears the vector. After clearing, size() == 0
-                void clear() CDS_NOEXCEPT
-                {
-                    m_nSize = 0;
-                }
-            };
-
-            /// 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 hp_record {
-                hp_allocator<>    m_hzp; ///< array of hazard pointers. Implicit \ref CDS_DEFAULT_ALLOCATOR dependency
-                retired_vector    m_arrRetired ; ///< Retired pointer array
-
-                /// Ctor
-                hp_record( const cds::gc::hp::GarbageCollector& HzpMgr );    // inline
-                ~hp_record()
-                {}
-
-                /// 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 \p hp_record allocations
-                event_counter::value_type   evcRetireHPRec  ;   ///< Count of \p hp_record retire events
-                event_counter::value_type   evcAllocNewHPRec;   ///< Count of new \p hp_record allocations from heap
-                event_counter::value_type   evcDeleteHPRec  ;   ///< Count of \p hp_record 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 \p hp_record allocations
-                event_counter  m_RetireHPRec            ;    ///< Count of \p hp_record retire events
-                event_counter  m_AllocNewHPRec            ;    ///< Count of new \p hp_record allocations from heap
-                event_counter  m_DeleteHPRec            ;    ///< Count of \p hp_record 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::hp::details::hp_record
-            struct hplist_node : public details::hp_record
-            {
-                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 )
-                    : hp_record( 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() CDS_NOEXCEPT
-            {
-                return m_pHZPManager != nullptr;
-            }
-
-            /// Returns max Hazard Pointer count defined in construction time
-            size_t            getHazardPointerCount() const CDS_NOEXCEPT
-            { 
-                return m_nHazardPointerCount; 
-            }
-
-            /// Returns max thread count defined in construction time
-            size_t            getMaxThreadCount() const CDS_NOEXCEPT
-            { 
-                return m_nMaxThreadCount; 
-            }
-
-            /// Returns max size of retired objects array. It is defined in construction time
-            size_t            getMaxRetiredPtrCount() const CDS_NOEXCEPT
-            { 
-                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::hp_record * AllocateHPRec();
-
-            /// Free HP record. For internal use only
-            void RetireHPRec( details::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * 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::hp_record * pRec = m_pHzpRec;
-                    m_pHzpRec = nullptr;
-                    m_HzpManager.RetireHPRec( pRec );
-                }
-            }
-
-            /// Initializes HP guard \p guard
-            details::hp_guard& allocGuard()
-            {
-                assert( m_pHzpRec );
-                return m_pHzpRec->m_hzp.alloc();
-            }
-
-            /// Frees HP guard \p guard
-            void freeGuard( details::hp_guard& guard )
-            {
-                assert( m_pHzpRec );
-                m_pHzpRec->m_hzp.free( guard );
-            }
-
-            /// Initializes HP guard array \p arr
-            template <size_t Count>
-            void allocGuard( details::hp_array<Count>& arr )
-            {
-                assert( m_pHzpRec );
-                m_pHzpRec->m_hzp.alloc( arr );
-            }
-
-            /// Frees HP guard array \p arr
-            template <size_t Count>
-            void freeGuard( details::hp_array<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 hp_guard.
-        /**
-            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::hp_guard&   m_hp    ; ///< Hazard pointer guarded
-            ThreadGC&           m_gc    ; ///< Thread GC
-            //@endcond
-
-        public:
-            typedef details::hp_guard::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::hp::details::hp_array class.
-            \p Count is the size of HP array
-        */
-        template <size_t Count>
-        class AutoHPArray : public details::hp_array<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 hp
-}}  // 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_HP_HP_H
index 44ef1d3909a9ec1b2c199fe55c1c1803a1f222c6..9de3da4ef6460da6cdac7bf2d00c3f4215aad329 100644 (file)
@@ -4,7 +4,7 @@
 #define __CDS_GC_HP_HP_DECL_H
 
 #include <stdexcept>    // overflow_error
-#include <cds/gc/hp/hp.h>
+#include <cds/gc/details/hp.h>
 #include <cds/details/marked_ptr.h>
 
 namespace cds { namespace gc {
@@ -86,12 +86,12 @@ namespace cds { namespace gc {
         /// Hazard Pointer guard
         /**
             @headerfile cds/gc/hp.h
-            This class is a wrapper for hp::AutoHPGuard.
+            This class is a wrapper for \p hp::guard.
         */
-        class Guard : public hp::AutoHPGuard
+        class Guard : public hp::guard
         {
             //@cond
-            typedef hp::AutoHPGuard base_class;
+            typedef hp::guard base_class;
             //@endcond
 
         public:
@@ -206,14 +206,14 @@ namespace cds { namespace gc {
         /// Array of Hazard Pointer guards
         /**
             @headerfile cds/gc/hp.h
-            This class is a wrapper for hp::AutoHPArray template.
+            This class is a wrapper for \p hp::array template.
             Template parameter \p Count defines the size of HP array.
         */
         template <size_t Count>
-        class GuardArray : public hp::AutoHPArray<Count>
+        class GuardArray : public hp::array<Count>
         {
             //@cond
-            typedef hp::AutoHPArray<Count> base_class;
+            typedef hp::array<Count> base_class;
             //@endcond
         public:
             /// Rebind array for other size \p Count2
index 99b4958b6a2dd4a023985c64dbe589cb0b3e1c11..3b31649a52d3957eff969900666d30907a8b61be 100644 (file)
     <ClInclude Include="..\..\..\cds\details\bounded_container.h" />\r
     <ClInclude Include="..\..\..\cds\details\lib.h" />\r
     <ClInclude Include="..\..\..\cds\details\static_functor.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp_alloc.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp_inline.h" />\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp_type.h" />\r
     <ClInclude Include="..\..\..\cds\gc\dhp.h" />\r
     <ClInclude Include="..\..\..\cds\gc\dhp\dhp.h" />\r
     <ClInclude Include="..\..\..\cds\gc\dhp\dhp_decl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\dhp\dhp_impl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\guarded_ptr.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_alloc.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_inline.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\hp\details\hp_type.h" />\r
     <ClInclude Include="..\..\..\cds\gc\hp\hp.h" />\r
     <ClInclude Include="..\..\..\cds\gc\hp\hp_decl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\hp\hp_impl.h" />\r
index 788c8b9720bbb839e357ce7deeae19e858352227..d8599743075165c083904e9e444e210ef91b0b89 100644 (file)
     <ClInclude Include="..\..\..\cds\gc\dhp.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_inline.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\hp.h">\r
       <Filter>Header Files\cds\gc\hp</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\src\hp_const.h">\r
       <Filter>Source Files</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp_alloc.h">\r
+      <Filter>Header Files\cds\gc\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp_inline.h">\r
+      <Filter>Header Files\cds\gc\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp_type.h">\r
+      <Filter>Header Files\cds\gc\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\gc\details\hp.h">\r
+      <Filter>Header Files\cds\gc\details</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index a4681b99e555ce12b3bb4b8444bfe791ebf6222f..4899dd4d748af930f680f02d470bf54af43e0e75 100644 (file)
@@ -9,7 +9,7 @@
         2008.02.10    Maxim.Khiszinsky    Created
 */
 
-#include <cds/gc/hp/hp.h>
+#include <cds/gc/details/hp.h>
 
 #include <algorithm>    // std::sort
 #include "hp_const.h"
@@ -103,7 +103,7 @@ namespace cds { namespace gc {
             p.free();
         }
 
-        details::hp_record * GarbageCollector::AllocateHPRec()
+        details::hp_record * GarbageCollector::alloc_hp_record()
         {
             CDS_HAZARDPTR_STATISTIC( ++m_Stat.m_AllocHPRec );
 
@@ -136,7 +136,7 @@ namespace cds { namespace gc {
             return hprec;
         }
 
-        void GarbageCollector::RetireHPRec( details::hp_record * pRec )
+        void GarbageCollector::free_hp_record( details::hp_record * pRec )
         {
             assert( pRec != nullptr );
             CDS_HAZARDPTR_STATISTIC( ++m_Stat.m_RetireHPRec );
@@ -154,7 +154,7 @@ namespace cds { namespace gc {
             for ( hplist_node * hprec = m_pListHead.load(atomics::memory_order_acquire); hprec; hprec = pNext ) {
                 pNext = hprec->m_pNextNode;
                 if ( hprec->m_idOwner.load(atomics::memory_order_relaxed) != nullThreadId ) {
-                    RetireHPRec( hprec );
+                    free_hp_record( hprec );
                 }
             }
         }