Uses different pass count for different parallel queue test cases
[libcds.git] / cds / gc / hp.h
index a9b289139d2687d5fd8201fe41fa5b375fe522d5..75e8953a20c396a5d51872c041a4f5cc3c4ddadd 100644 (file)
@@ -33,6 +33,8 @@
 
 #include <exception>
 #include <cds/gc/details/hp_common.h>
+#include <cds/details/lib.h>
+#include <cds/threading/model.h>
 #include <cds/details/throw_exception.h>
 #include <cds/details/static_functor.h>
 #include <cds/details/marked_ptr.h>
@@ -151,7 +153,7 @@ namespace cds { namespace gc {
 #       ifdef CDS_DISABLE_SMR_EXCEPTION
                 assert( !full());
 #       else
-                if ( full() )
+                if ( full())
                     CDS_THROW_EXCEPTION( not_enought_hazard_ptr());
 #       endif
                 guard* g = free_head_;
@@ -162,7 +164,7 @@ namespace cds { namespace gc {
 
             void free( guard* g ) CDS_NOEXCEPT
             {
-                assert( g >= array_ && g < array_ + capacity() );
+                assert( g >= array_ && g < array_ + capacity());
 
                 if ( g ) {
                     g->clear();
@@ -218,7 +220,7 @@ namespace cds { namespace gc {
 
             guard& operator[]( size_t idx )
             {
-                assert( idx < capacity() );
+                assert( idx < capacity());
 
                 return array_[idx];
             }
@@ -265,14 +267,16 @@ namespace cds { namespace gc {
 
             size_t size() const CDS_NOEXCEPT
             {
-                return current_ - retired_;
+                return current_.load(atomics::memory_order_relaxed) - retired_;
             }
 
             bool push( retired_ptr&& p ) CDS_NOEXCEPT
             {
-                *current_ = p;
+                retired_ptr* cur = current_.load( atomics::memory_order_relaxed );
+                *cur = p;
                 CDS_HPSTAT( ++retire_call_count_ );
-                return ++current_ < last_;
+                current_.store( cur + 1, atomics::memory_order_relaxed );
+                return cur + 1 < last_;
             }
 
             retired_ptr* first() const CDS_NOEXCEPT
@@ -282,17 +286,22 @@ namespace cds { namespace gc {
 
             retired_ptr* last() const CDS_NOEXCEPT
             {
-                return current_;
+                return current_.load( atomics::memory_order_relaxed );
             }
 
             void reset( size_t nSize ) CDS_NOEXCEPT
             {
-                current_ = first() + nSize;
+                current_.store( first() + nSize, atomics::memory_order_relaxed );
+            }
+
+            void interthread_clear()
+            {
+                current_.exchange( first(), atomics::memory_order_acq_rel );
             }
 
             bool full() const CDS_NOEXCEPT
             {
-                return current_ == last_;
+                return current_.load( atomics::memory_order_relaxed ) == last_;
             }
 
             static size_t calc_array_size( size_t capacity )
@@ -301,9 +310,9 @@ namespace cds { namespace gc {
             }
 
         private:
-            retired_ptr*            current_;
-            retired_ptr* const      last_;
-            retired_ptr* const      retired_;
+            atomics::atomic<retired_ptr*> current_;
+            retired_ptr* const            last_;
+            retired_ptr* const            retired_;
 #       ifdef CDS_ENABLE_HPSTAT
         public:
             size_t  retire_call_count_;
@@ -347,18 +356,28 @@ namespace cds { namespace gc {
             thread_hp_storage   hazards_;   ///< Hazard pointers private to the thread
             retired_array       retired_;   ///< Retired data private to the thread
 
-            stat                stat_;      ///< Internal statistics for the thread
-
             char pad1_[cds::c_nCacheLineSize];
             atomics::atomic<unsigned int> sync_; ///< dummy var to introduce synchronizes-with relationship between threads
             char pad2_[cds::c_nCacheLineSize];
 
+#       ifdef CDS_ENABLE_HPSTAT
+            // Internal statistics:
+            size_t              free_count_;
+            size_t              scan_count_;
+            size_t              help_scan_count_;
+#       endif
+
             // CppCheck warn: pad1_ and pad2_ is uninitialized in ctor
             // cppcheck-suppress uninitMemberVar
             thread_data( guard* guards, size_t guard_count, retired_ptr* retired_arr, size_t retired_capacity )
                 : hazards_( guards, guard_count )
                 , retired_( retired_arr, retired_capacity )
                 , sync_(0)
+#       ifdef CDS_ENABLE_HPSTAT
+                , free_count_(0)
+                , scan_count_(0)
+                , help_scan_count_(0)
+#       endif
             {}
 
             thread_data() = delete;
@@ -374,8 +393,8 @@ namespace cds { namespace gc {
 
         /// \p smr::scan() strategy
         enum scan_type {
-            classic,    ///< classic scan as described in Michael's works (see smr::classic_scan() )
-            inplace     ///< inplace scan without allocation (see smr::inplace_scan() )
+            classic,    ///< classic scan as described in Michael's works (see smr::classic_scan())
+            inplace     ///< inplace scan without allocation (see smr::inplace_scan())
         };
 
         //@cond
@@ -502,7 +521,7 @@ namespace cds { namespace gc {
 #       ifdef CDS_DISABLE_SMR_EXCEPTION
                     assert( false );    // not enough hazard ptr
 #       else
-                    CDS_THROW_EXCEPTION( not_enought_hazard_ptr() );
+                    CDS_THROW_EXCEPTION( not_enought_hazard_ptr());
 #       endif
                 }
             }
@@ -514,7 +533,7 @@ namespace cds { namespace gc {
             static CDS_EXPORT_API void detach_thread();
 
             /// Get internal statistics
-            void statistics( stat& st );
+            CDS_EXPORT_API void statistics( stat& st );
 
         public: // for internal use only
             /// The main garbage collecting function
@@ -679,7 +698,7 @@ namespace cds { namespace gc {
                 @warning Can throw \p too_many_hazard_ptr_exception if internal hazard pointer objects are exhausted.
             */
             Guard()
-                : guard_( hp::smr::tls()->hazards_.alloc() )
+                : guard_( hp::smr::tls()->hazards_.alloc())
             {}
 
             /// Initilalizes an unlinked guard i.e. the guard contains no hazard pointer. Used for move semantics support
@@ -987,7 +1006,7 @@ namespace cds { namespace gc {
             template <typename T>
             T * assign( size_t nIndex, T * p )
             {
-                assert( nIndex < capacity() );
+                assert( nIndex < capacity());
 
                 guards_.set( nIndex, p );
                 hp::smr::tls()->sync();
@@ -1027,7 +1046,7 @@ namespace cds { namespace gc {
             template <typename T>
             T * get( size_t nIndex ) const
             {
-                assert( nIndex < capacity() );
+                assert( nIndex < capacity());
                 return guards_[nIndex]->template get_as<T>();
             }
 
@@ -1362,7 +1381,7 @@ namespace cds { namespace gc {
             \p func is a disposer: when \p p can be safely removed, \p func is called.
         */
         template <typename T>
-        static void retire( T * p, void( *func )( T * ))
+        static void retire( T * p, void( *func )( void * ))
         {
             hp::thread_data* rec = hp::smr::tls();
             if ( !rec->retired_.push( hp::retired_ptr( p, func )))
@@ -1457,7 +1476,7 @@ namespace cds { namespace gc {
             The function clears \p st before gathering statistics.
 
             @note Internal statistics is available only if you compile
-            \p libcds and your program with \p -DCDS_ENABLE_HPSTAT key.
+            \p libcds and your program with \p -DCDS_ENABLE_HPSTAT.
         */
         static void statistics( stat& st )
         {
@@ -1470,7 +1489,7 @@ namespace cds { namespace gc {
             and can be accessible after destructing the global \p %HP object.
 
             @note Internal statistics is available only if you compile
-            \p libcds and your program with \p -DCDS_ENABLE_HPSTAT key.
+            \p libcds and your program with \p -DCDS_ENABLE_HPSTAT.
 
             Usage:
             \code
@@ -1490,13 +1509,13 @@ namespace cds { namespace gc {
                 cds::gc::HP::stat const& st = cds::gc::HP::postmortem_statistics();
 
                 printf( "HP statistics:\n"
-                    "\tthread count           = %llu\n"
-                    "\tguard allocated        = %llu\n"
-                    "\tguard freed            = %llu\n"
-                    "\tretired data count     = %llu\n"
-                    "\tfree data count        = %llu\n"
-                    "\tscan() call count      = %llu\n"
-                    "\thelp_scan() call count = %llu\n",
+                    "  thread count           = %llu\n"
+                    "  guard allocated        = %llu\n"
+                    "  guard freed            = %llu\n"
+                    "  retired data count     = %llu\n"
+                    "  free data count        = %llu\n"
+                    "  scan() call count      = %llu\n"
+                    "  help_scan() call count = %llu\n",
                     st.thread_rec_count,
                     st.guard_allocated, st.guard_freed,
                     st.retired_count, st.free_count,
@@ -1507,7 +1526,7 @@ namespace cds { namespace gc {
             }
             \endcode
         */
-        static stat const& postmortem_statistics();
+        CDS_EXPORT_API static stat const& postmortem_statistics();
     };
 
 }} // namespace cds::gc