Removed redundant spaces
[libcds.git] / cds / gc / details / dhp.h
index 4491bd4d6b5477115eea163d1d12ed2646e8df00..5f03cc8f675b3c7188b20df068da1032522a773b 100644 (file)
@@ -1,10 +1,39 @@
-//$$CDS-header$$
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
 
 #ifndef CDSLIB_GC_DETAILS_DHP_H
 #define CDSLIB_GC_DETAILS_DHP_H
 
 #include <mutex>        // unique_lock
 #include <cds/algo/atomic.h>
+#include <cds/algo/int_algo.h>
 #include <cds/gc/details/retired_ptr.h>
 #include <cds/details/aligned_allocator.h>
 #include <cds/details/allocator.h>
@@ -57,8 +86,8 @@ namespace cds { namespace gc {
             /// Retired pointer buffer node
             struct retired_ptr_node {
                 retired_ptr         m_ptr   ;   ///< retired pointer
-                retired_ptr_node *  m_pNext     ;   ///< next retired pointer in buffer
-                retired_ptr_node *  m_pNextFree ;   ///< next item in free list of retired_ptr_node
+                atomics::atomic<retired_ptr_node *>  m_pNext     ;   ///< next retired pointer in buffer
+                atomics::atomic<retired_ptr_node *>  m_pNextFree ;   ///< next item in free list of \p retired_ptr_node
             };
 
             /// Internal guard representation
@@ -88,13 +117,23 @@ namespace cds { namespace gc {
                 {
                     return pPost.load( atomics::memory_order_acquire ) == nullptr;
                 }
+
+                guarded_ptr get( atomics::memory_order order = atomics::memory_order_acquire )
+                {
+                    return pPost.load( order );
+                }
+
+                void set( guarded_ptr p, atomics::memory_order order = atomics::memory_order_release )
+                {
+                    pPost.store( p, order );
+                }
             };
 
             /// Guard allocator
             template <class Alloc = CDS_DEFAULT_ALLOCATOR>
             class guard_allocator
             {
-                cds::details::Allocator<details::guard_data>  m_GuardAllocator    ;   ///< guard allocator
+                cds::details::Allocator<details::guard_data>  m_GuardAllocator;   ///< guard allocator
 
                 atomics::atomic<guard_data *>  m_GuardList;     ///< Head of allocated guard list (linked by guard_data::pGlobalNext field)
                 atomics::atomic<guard_data *>  m_FreeGuardList; ///< Head of free guard list (linked by guard_data::pNextFree field)
@@ -145,7 +184,7 @@ namespace cds { namespace gc {
                 }
 
                 /// Allocates a guard from free list or from heap if free list is empty
-                guard_data * alloc()
+                guard_data* alloc()
                 {
                     // Try to pop a guard from free-list
                     details::guard_data * pGuard;
@@ -167,7 +206,7 @@ namespace cds { namespace gc {
                 /**
                     The function places the guard \p pGuard into free-list
                 */
-                void free( guard_data * pGuard ) CDS_NOEXCEPT
+                void free( guard_data* pGuard ) CDS_NOEXCEPT
                 {
                     pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
 
@@ -262,7 +301,7 @@ namespace cds { namespace gc {
                 {
                     retired_ptr_node * pHead = m_pHead.load(atomics::memory_order_acquire);
                     do {
-                        node.m_pNext = pHead;
+                        node.m_pNext.store( pHead, atomics::memory_order_relaxed );
                         // pHead is changed by compare_exchange_weak
                     } while ( !m_pHead.compare_exchange_weak( pHead, &node, atomics::memory_order_release, atomics::memory_order_relaxed ));
 
@@ -277,30 +316,30 @@ namespace cds { namespace gc {
 
                     retired_ptr_node * pHead = m_pHead.load( atomics::memory_order_acquire );
                     do {
-                        pLast->m_pNext = pHead;
+                        pLast->m_pNext.store( pHead, atomics::memory_order_relaxed );
                         // pHead is changed by compare_exchange_weak
-                    } while ( !m_pHead.compare_exchange_weak( pHead, pFirst, atomics::memory_order_release, atomics::memory_order_relaxed ) );
+                    } while ( !m_pHead.compare_exchange_weak( pHead, pFirst, atomics::memory_order_release, atomics::memory_order_relaxed ));
 
                     return m_nItemCount.fetch_add( nSize, atomics::memory_order_relaxed ) + 1;
                 }
 
-                /// Result of \ref dhp_gc_privatve "privatize" function.
+                /// Result of \ref dhp_gc_privatize "privatize" function.
                 /**
                     The \p privatize function returns retired node list as \p first and the size of that list as \p second.
                 */
                 typedef std::pair<retired_ptr_node *, size_t> privatize_result;
 
                 /// Gets current list of retired pointer and clears the list
-                /**@anchor dhp_gc_privatve
+                /**@anchor dhp_gc_privatize
                 */
                 privatize_result privatize() CDS_NOEXCEPT
                 {
                     privatize_result res;
-                    res.first = m_pHead.exchange( nullptr, atomics::memory_order_acq_rel );
 
                     // Item counter is needed only as a threshold for \p scan() function
                     // So, we may clear the item counter without synchronization with m_pHead
                     res.second = m_nItemCount.exchange( 0, atomics::memory_order_relaxed );
+                    res.first = m_pHead.exchange( nullptr, atomics::memory_order_acq_rel );
                     return res;
                 }
 
@@ -326,47 +365,48 @@ namespace cds { namespace gc {
 
                 /// Pool block
                 struct block {
-                    block *     pNext;  ///< next block
-                    item        items[m_nItemPerBlock];   ///< item array
+                    atomics::atomic<block *> pNext;     ///< next block
+                    item        items[m_nItemPerBlock]; ///< item array
                 };
 
                 atomics::atomic<block *> m_pBlockListHead;   ///< head of of allocated block list
 
                 // To solve ABA problem we use epoch-based approach
-                static const unsigned int c_nEpochCount = 4;    ///< Max epoch count
+                unsigned int const m_nEpochBitmask;             ///< Epoch bitmask (log2( m_nEpochCount))
                 atomics::atomic<unsigned int> m_nCurEpoch;      ///< Current epoch
-                atomics::atomic<item *>  m_pEpochFree[c_nEpochCount];   ///< List of free item per epoch
+                atomics::atomic<item *>* m_pEpochFree;          ///< List of free item per epoch
                 atomics::atomic<item *>  m_pGlobalFreeHead;     ///< Head of unallocated item list
 
-                cds::details::Allocator< block, Alloc > m_BlockAllocator    ;   ///< block allocator
+                typedef cds::details::Allocator< block, Alloc > block_allocator;
+                typedef cds::details::Allocator< atomics::atomic<item *>, Alloc > epoch_array_alloc;
 
             private:
                 void allocNewBlock()
                 {
                     // allocate new block
-                    block * pNew = m_BlockAllocator.New();
+                    block * pNew = block_allocator().New();
 
                     // link items within the block
                     item * pLastItem = pNew->items + m_nItemPerBlock - 1;
                     for ( item * pItem = pNew->items; pItem != pLastItem; ++pItem ) {
-                        pItem->m_pNextFree = pItem + 1;
-                        CDS_STRICT_DO( pItem->m_pNext = nullptr );
+                        pItem->m_pNextFree.store( pItem + 1, atomics::memory_order_release );
+                        CDS_STRICT_DO( pItem->m_pNext.store( nullptr, atomics::memory_order_relaxed ));
                     }
 
                     // links new block to the block list
                     {
-                        block * pHead = m_pBlockListHead.load(atomics::memory_order_acquire);
+                        block * pHead = m_pBlockListHead.load(atomics::memory_order_relaxed);
                         do {
-                            pNew->pNext = pHead;
+                            pNew->pNext.store( pHead, atomics::memory_order_relaxed );
                             // pHead is changed by compare_exchange_weak
-                        } while ( !m_pBlockListHead.compare_exchange_weak( pHead, pNew, atomics::memory_order_release, atomics::memory_order_relaxed ));
+                        } while ( !m_pBlockListHead.compare_exchange_weak( pHead, pNew, atomics::memory_order_relaxed, atomics::memory_order_relaxed ));
                     }
 
                     // links block's items to the free list
                     {
-                        item * pHead = m_pGlobalFreeHead.load(atomics::memory_order_acquire);
+                        item * pHead = m_pGlobalFreeHead.load(atomics::memory_order_relaxed);
                         do {
-                            pLastItem->m_pNextFree = pHead;
+                            pLastItem->m_pNextFree.store( pHead, atomics::memory_order_release );
                             // pHead is changed by compare_exchange_weak
                         } while ( !m_pGlobalFreeHead.compare_exchange_weak( pHead, pNew->items, atomics::memory_order_release, atomics::memory_order_relaxed ));
                     }
@@ -374,21 +414,25 @@ namespace cds { namespace gc {
 
                 unsigned int current_epoch() const CDS_NOEXCEPT
                 {
-                    return m_nCurEpoch.load(atomics::memory_order_acquire) & (c_nEpochCount - 1);
+                    return m_nCurEpoch.load(atomics::memory_order_acquire) & m_nEpochBitmask;
                 }
 
                 unsigned int next_epoch() const CDS_NOEXCEPT
                 {
-                    return (m_nCurEpoch.load(atomics::memory_order_acquire) - 1) & (c_nEpochCount - 1);
+                    return (m_nCurEpoch.load(atomics::memory_order_acquire) - 1) & m_nEpochBitmask;
                 }
 
             public:
-                retired_ptr_pool()
+                retired_ptr_pool( unsigned int nEpochCount = 8 )
                     : m_pBlockListHead( nullptr )
+                    , m_nEpochBitmask( static_cast<unsigned int>(beans::ceil2(nEpochCount)) - 1 )
                     , m_nCurEpoch(0)
+                    , m_pEpochFree( epoch_array_alloc().NewArray( m_nEpochBitmask + 1))
                     , m_pGlobalFreeHead( nullptr )
                 {
-                    for (unsigned int i = 0; i < sizeof(m_pEpochFree)/sizeof(m_pEpochFree[0]); ++i )
+
+
+                    for (unsigned int i = 0; i <= m_nEpochBitmask; ++i )
                         m_pEpochFree[i].store( nullptr, atomics::memory_order_relaxed );
 
                     allocNewBlock();
@@ -396,11 +440,14 @@ namespace cds { namespace gc {
 
                 ~retired_ptr_pool()
                 {
+                    block_allocator a;
                     block * p;
                     for ( block * pBlock = m_pBlockListHead.load(atomics::memory_order_relaxed); pBlock; pBlock = p ) {
-                        p = pBlock->pNext;
-                        m_BlockAllocator.Delete( pBlock );
+                        p = pBlock->pNext.load( atomics::memory_order_relaxed );
+                        a.Delete( pBlock );
                     }
+
+                    epoch_array_alloc().Delete( m_pEpochFree, m_nEpochBitmask + 1 );
                 }
 
                 /// Increments current epoch
@@ -418,24 +465,30 @@ namespace cds { namespace gc {
                         pItem = m_pEpochFree[ nEpoch = current_epoch() ].load(atomics::memory_order_acquire);
                         if ( !pItem )
                             goto retry;
-                        if ( m_pEpochFree[nEpoch].compare_exchange_weak( pItem, pItem->m_pNextFree, atomics::memory_order_release, atomics::memory_order_relaxed ))
+                        if ( m_pEpochFree[nEpoch].compare_exchange_weak( pItem,
+                                                                         pItem->m_pNextFree.load(atomics::memory_order_acquire),
+                                                                         atomics::memory_order_acquire, atomics::memory_order_relaxed ))
+                        {
                             goto success;
+                        }
                     }
 
                     // Epoch free list is empty
                     // Alloc from global free list
                 retry:
-                    pItem = m_pGlobalFreeHead.load( atomics::memory_order_acquire );
+                    pItem = m_pGlobalFreeHead.load( atomics::memory_order_relaxed );
                     do {
                         if ( !pItem ) {
                             allocNewBlock();
                             goto retry;
                         }
                         // pItem is changed by compare_exchange_weak
-                    } while ( !m_pGlobalFreeHead.compare_exchange_weak( pItem, pItem->m_pNextFree, atomics::memory_order_release, atomics::memory_order_relaxed ));
+                    } while ( !m_pGlobalFreeHead.compare_exchange_weak( pItem,
+                                                                        pItem->m_pNextFree.load(atomics::memory_order_acquire),
+                                                                        atomics::memory_order_acquire, atomics::memory_order_relaxed ));
 
                 success:
-                    CDS_STRICT_DO( pItem->m_pNextFree = nullptr );
+                    CDS_STRICT_DO( pItem->m_pNextFree.store( nullptr, atomics::memory_order_relaxed ));
                     return *pItem;
                 }
 
@@ -460,212 +513,12 @@ namespace cds { namespace gc {
                     item * pCurHead;
                     do {
                         pCurHead = m_pEpochFree[nEpoch = next_epoch()].load(atomics::memory_order_acquire);
-                        pTail->m_pNextFree = pCurHead;
+                        pTail->m_pNextFree.store( pCurHead, atomics::memory_order_release );
                     } while ( !m_pEpochFree[nEpoch].compare_exchange_weak( pCurHead, pHead, atomics::memory_order_release, atomics::memory_order_relaxed ));
                 }
             };
-
-            /// Uninitialized guard
-            class guard
-            {
-                friend class dhp::ThreadGC;
-            protected:
-                details::guard_data * m_pGuard ;    ///< Pointer to guard data
-
-            public:
-                /// Initialize empty guard.
-                CDS_CONSTEXPR guard() CDS_NOEXCEPT
-                    : m_pGuard( nullptr )
-                {}
-
-                /// Copy-ctor is disabled
-                guard( guard const& ) = delete;
-
-                /// Move-ctor is disabled
-                guard( guard&& ) = delete;
-
-                /// Object destructor, does nothing
-                ~guard() CDS_NOEXCEPT
-                {}
-
-                /// Get current guarded pointer
-                void * get( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT
-                {
-                    assert( m_pGuard != nullptr );
-                    return m_pGuard->pPost.load( order );
-                }
-
-                /// Guards pointer \p p
-                void set( void * p, atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT
-                {
-                    assert( m_pGuard != nullptr );
-                    m_pGuard->pPost.store( p, order );
-                }
-
-                /// Clears the guard
-                void clear( atomics::memory_order order = atomics::memory_order_relaxed ) CDS_NOEXCEPT
-                {
-                    assert( m_pGuard != nullptr );
-                    m_pGuard->pPost.store( nullptr, order );
-                }
-
-                /// Guards pointer \p p
-                template <typename T>
-                T * operator =(T * p) CDS_NOEXCEPT
-                {
-                    set( reinterpret_cast<void *>( const_cast<T *>(p) ));
-                    return p;
-                }
-
-                std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
-                {
-                    clear();
-                    return nullptr;
-                }
-
-            public: // for ThreadGC.
-                /*
-                    GCC cannot compile code for template versions of ThreadGC::allocGuard/freeGuard,
-                    the compiler produces error: \91cds::gc::dhp::details::guard_data* cds::gc::dhp::details::guard::m_pGuard\92 is protected
-                    despite the fact that ThreadGC is declared as friend for guard class.
-                    Therefore, we have to add set_guard/get_guard public functions
-                */
-                /// Set guard data
-                void set_guard( details::guard_data * pGuard ) CDS_NOEXCEPT
-                {
-                    assert( m_pGuard == nullptr );
-                    m_pGuard = pGuard;
-                }
-
-                /// Get current guard data
-                details::guard_data * get_guard() CDS_NOEXCEPT
-                {
-                    return m_pGuard;
-                }
-                /// Get current guard data
-                details::guard_data * get_guard() const CDS_NOEXCEPT
-                {
-                    return m_pGuard;
-                }
-
-                details::guard_data * release_guard() CDS_NOEXCEPT
-                {
-                    details::guard_data * p = m_pGuard;
-                    m_pGuard = nullptr;
-                    return p;
-                }
-
-                bool is_initialized() const
-                {
-                    return m_pGuard != nullptr;
-                }
-            };
-
         } // namespace details
 
-        /// Guard
-        /**
-            This class represents auto guard: ctor allocates a guard from guard pool,
-            dtor returns the guard back to the pool of free guard.
-        */
-        class Guard: public details::guard
-        {
-            typedef details::guard    base_class;
-            friend class ThreadGC;
-        public:
-            /// Allocates a guard from \p gc GC. \p gc must be ThreadGC object of current thread
-            Guard(); // inline in dhp_impl.h
-
-            /// Returns guard allocated back to pool of free guards
-            ~Guard();    // inline in dhp_impl.h
-
-            /// Guards pointer \p p
-            template <typename T>
-            T * operator =(T * p) CDS_NOEXCEPT
-            {
-                return base_class::operator =<T>( p );
-            }
-
-            std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
-            {
-                return base_class::operator =(nullptr);
-            }
-        };
-
-        /// Array of guards
-        /**
-            This class represents array of auto guards: ctor allocates \p Count guards from guard pool,
-            dtor returns the guards allocated back to the pool.
-        */
-        template <size_t Count>
-        class GuardArray
-        {
-            details::guard      m_arr[Count]    ;    ///< array of guard
-            const static size_t c_nCapacity = Count ;   ///< Array capacity (equal to \p Count template parameter)
-
-        public:
-            /// Rebind array for other size \p OtherCount
-            template <size_t OtherCount>
-            struct rebind {
-                typedef GuardArray<OtherCount>  other   ;   ///< rebinding result
-            };
-
-        public:
-            /// Allocates array of guards from \p gc which must be the ThreadGC object of current thread
-            GuardArray();    // inline in dhp_impl.h
-
-            /// The object is not copy-constructible
-            GuardArray( GuardArray const& ) = delete;
-
-            /// The object is not move-constructible
-            GuardArray( GuardArray&& ) = delete;
-
-            /// Returns guards allocated back to pool
-            ~GuardArray();    // inline in dh_impl.h
-
-            /// Returns the capacity of array
-            CDS_CONSTEXPR size_t capacity() const CDS_NOEXCEPT
-            {
-                return c_nCapacity;
-            }
-
-            /// Returns reference to the guard of index \p nIndex (0 <= \p nIndex < \p Count)
-            details::guard& operator []( size_t nIndex ) CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                return m_arr[nIndex];
-            }
-
-            /// Returns reference to the guard of index \p nIndex (0 <= \p nIndex < \p Count) [const version]
-            const details::guard& operator []( size_t nIndex ) const CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                return m_arr[nIndex];
-            }
-
-            /// Set the guard \p nIndex. 0 <= \p nIndex < \p Count
-            template <typename T>
-            void set( size_t nIndex, T * p ) CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                m_arr[nIndex].set( p );
-            }
-
-            /// Clears (sets to \p nullptr) the guard \p nIndex
-            void clear( size_t nIndex ) CDS_NOEXCEPT
-            {
-                assert( nIndex < capacity() );
-                m_arr[nIndex].clear();
-            }
-
-            /// Clears all guards in the array
-            void clearAll() CDS_NOEXCEPT
-            {
-                for ( size_t i = 0; i < capacity(); ++i )
-                    clear(i);
-            }
-        };
-
         /// Memory manager (Garbage collector)
         class CDS_EXPORT_API GarbageCollector
         {
@@ -721,13 +574,13 @@ namespace cds { namespace gc {
         private:
             static GarbageCollector * m_pManager    ;   ///< GC global instance
 
+            atomics::atomic<size_t>  m_nLiberateThreshold;   ///< Max size of retired pointer buffer to call \p scan()
+            const size_t             m_nInitialThreadGuardCount; ///< Initial count of guards allocated for ThreadGC
+
             details::guard_allocator<>      m_GuardPool         ;   ///< Guard pool
             details::retired_ptr_pool<>     m_RetiredAllocator  ;   ///< Pool of free retired pointers
             details::retired_ptr_buffer     m_RetiredBuffer     ;   ///< Retired pointer buffer for liberating
 
-            atomics::atomic<size_t>      m_nLiberateThreshold;   ///< Max size of retired pointer buffer to call \p scan()
-            const size_t    m_nInitialThreadGuardCount; ///< Initial count of guards allocated for ThreadGC
-
             internal_stat   m_stat  ;   ///< Internal statistics
             bool            m_bStatEnabled  ;   ///< Internal Statistics enabled
 
@@ -740,18 +593,22 @@ namespace cds { namespace gc {
                 After calling of this function you may use CDS data structures based on cds::gc::DHP.
 
                 \par Parameters
-                \li \p nLiberateThreshold - \p scan() threshold. When count of retired pointers reaches this value,
+                - \p nLiberateThreshold - \p scan() threshold. When count of retired pointers reaches this value,
                     the \ref dhp_gc_liberate "scan()" member function would be called for freeing retired pointers.
                     If \p nLiberateThreshold <= 1, \p scan() would called after each \ref dhp_gc_retirePtr "retirePtr" call.
-                \li \p nInitialThreadGuardCount - initial count of guard allocated for ThreadGC. When a thread
+                - \p nInitialThreadGuardCount - initial count of guard allocated for ThreadGC. When a thread
                     is initialized the GC allocates local guard pool for the thread from common guard pool.
                     By perforce the local thread's guard pool is grown automatically from common pool.
                     When the thread terminated its guard pool is backed to common GC's pool.
-
+                - \p nEpochCount: internally, DHP memory manager uses epoch-based schema to solve
+                    ABA problem for internal data. \p nEpochCount specifies the epoch count,
+                    i.e. the count of simultaneously working threads that remove the elements
+                    of DHP-based concurrent data structure. Default value is 16.
             */
             static void CDS_STDCALL Construct(
                 size_t nLiberateThreshold = 1024
                 , size_t nInitialThreadGuardCount = 8
+                , size_t nEpochCount = 16
             );
 
             /// Destroys DHP memory manager
@@ -796,7 +653,7 @@ namespace cds { namespace gc {
             }
 
             /// Allocates guard list for a thread.
-            details::guard_data * allocGuardList( size_t nCount )
+            details::guard_data* allocGuardList( size_t nCount )
             {
                 return m_GuardPool.allocList( nCount );
             }
@@ -811,15 +668,15 @@ namespace cds { namespace gc {
             /**@anchor dhp_gc_retirePtr
             */
             template <typename T>
-            void retirePtr( T * p, void (* pFunc)(T *) )
+            void retirePtr( T * p, void (* pFunc)(T *))
             {
-                retirePtr( retired_ptr( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ) ) );
+                retirePtr( 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( retired_ptr const& p )
             {
-                if ( m_RetiredBuffer.push( m_RetiredAllocator.alloc(p)) >= m_nLiberateThreshold.load(atomics::memory_order_relaxed) )
+                if ( m_RetiredBuffer.push( m_RetiredAllocator.alloc(p)) >= m_nLiberateThreshold.load(atomics::memory_order_relaxed))
                     scan();
             }
 
@@ -854,7 +711,7 @@ namespace cds { namespace gc {
             }
 
         private:
-            GarbageCollector( size_t nLiberateThreshold, size_t nInitialThreadGuardCount );
+            GarbageCollector( size_t nLiberateThreshold, size_t nInitialThreadGuardCount, size_t nEpochCount );
             ~GarbageCollector();
         };
 
@@ -872,14 +729,14 @@ namespace cds { namespace gc {
         */
         class ThreadGC
         {
-            GarbageCollector&   m_gc    ;   ///< reference to GC singleton
-            details::guard_data *    m_pList ;   ///< Local list of guards owned by the thread
-            details::guard_data *    m_pFree ;   ///< The list of free guard from m_pList
+            GarbageCollector&        m_gc;      ///< reference to GC singleton
+            details::guard_data *    m_pList;   ///< Local list of guards owned by the thread
+            details::guard_data *    m_pFree;   ///< The list of free guard from m_pList
 
         public:
             /// Default constructor
             ThreadGC()
-                : m_gc( GarbageCollector::instance() )
+                : m_gc( GarbageCollector::instance())
                 , m_pList( nullptr )
                 , m_pFree( nullptr )
             {}
@@ -913,77 +770,89 @@ namespace cds { namespace gc {
             }
 
         public:
-            /// Initializes guard \p g
-            void allocGuard( dhp::details::guard& g )
+            /// Allocates new guard
+            dhp::details::guard_data* allocGuard()
             {
                 assert( m_pList != nullptr );
-                if ( !g.m_pGuard ) {
-                    if ( m_pFree ) {
-                        g.m_pGuard = m_pFree;
-                        m_pFree = m_pFree->pNextFree.load( atomics::memory_order_relaxed );
-                    }
-                    else {
-                        g.m_pGuard = m_gc.allocGuard();
-                        g.m_pGuard->pThreadNext = m_pList;
-                        m_pList = g.m_pGuard;
-                    }
+
+                dhp::details::guard_data* ret;
+                if ( cds_likely( m_pFree )) {
+                    ret = m_pFree;
+                    m_pFree = m_pFree->pNextFree.load( atomics::memory_order_relaxed );
                 }
+                else {
+                    ret = m_gc.allocGuard();
+                    ret->pThreadNext = m_pList;
+                    m_pList = ret;
+                }
+                return ret;
             }
 
             /// Frees guard \p g
-            void freeGuard( dhp::details::guard& g )
+            void freeGuard( dhp::details::guard_data* g )
             {
                 assert( m_pList != nullptr );
-                if ( g.m_pGuard ) {
-                    g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
-                    g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
-                    m_pFree = g.m_pGuard;
-                    g.m_pGuard = nullptr;
+                if ( cds_likely( g )) {
+                    g->pPost.store( nullptr, atomics::memory_order_relaxed );
+                    g->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
+                    m_pFree = g;
                 }
             }
 
+            /// Guard array
+            template <size_t Count>
+            using guard_array = dhp::details::guard_data* [Count];
+
             /// Initializes guard array \p arr
             template <size_t Count>
-            void allocGuard( GuardArray<Count>& arr )
+            void allocGuard( guard_array<Count>& arr )
             {
                 assert( m_pList != nullptr );
                 size_t nCount = 0;
 
                 while ( m_pFree && nCount < Count ) {
-                    arr[nCount].set_guard( m_pFree );
+                    arr[nCount] = m_pFree;
                     m_pFree = m_pFree->pNextFree.load(atomics::memory_order_relaxed);
                     ++nCount;
                 }
 
                 while ( nCount < Count ) {
-                    details::guard& g = arr[nCount++];
-                    g.set_guard( m_gc.allocGuard() );
-                    g.get_guard()->pThreadNext = m_pList;
-                    m_pList = g.get_guard();
+                    dhp::details::guard_data*& g = arr[nCount];
+                    g = m_gc.allocGuard();
+                    g->pThreadNext = m_pList;
+                    m_pList = g;
+                    ++nCount;
                 }
             }
 
             /// Frees guard array \p arr
             template <size_t Count>
-            void freeGuard( GuardArray<Count>& arr )
+            void freeGuard( guard_array<Count>& arr )
             {
                 assert( m_pList != nullptr );
 
-                details::guard_data * pGuard;
-                for ( size_t i = 0; i < Count - 1; ++i ) {
-                    pGuard = arr[i].get_guard();
-                    pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
-                    pGuard->pNextFree.store( arr[i+1].get_guard(), atomics::memory_order_relaxed );
+                details::guard_data* first = nullptr;
+                details::guard_data* last;
+                for ( size_t i = 0; i < Count; ++i ) {
+                    details::guard_data* guard = arr[i];
+                    if ( cds_likely( guard )) {
+                        guard->pPost.store( nullptr, atomics::memory_order_relaxed );
+                        if ( first )
+                            last->pNextFree.store( guard, atomics::memory_order_relaxed );
+                        else
+                            first = guard;
+                        last = guard;
+                    }
+                }
+                if ( first ) {
+                    last->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
+                    m_pFree = first;
                 }
-                pGuard = arr[Count-1].get_guard();
-                pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
-                pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
-                m_pFree = arr[0].get_guard();
             }
 
             /// Places retired pointer \p and its deleter \p pFunc into list of retired pointer for deferred reclamation
             template <typename T>
-            void retirePtr( T * p, void (* pFunc)(T *) )
+            void retirePtr( T * p, void (* pFunc)(T *))
             {
                 m_gc.retirePtr( p, pFunc );
             }